计算机游戏程序设计基础实验指导书_第1页
计算机游戏程序设计基础实验指导书_第2页
计算机游戏程序设计基础实验指导书_第3页
计算机游戏程序设计基础实验指导书_第4页
计算机游戏程序设计基础实验指导书_第5页
已阅读5页,还剩147页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第5章二维游戏场景绘制英雄快跑(一)基础知识TiledMap编辑器制作游戏地图、序列帧动画、碰撞检测TiledMap编辑器制作游戏地图加载游戏地图添加玩家(序列帧动画)单点触摸屏幕,控制英雄上跳游戏地图的移动玩家下落,落到地面(碰撞检测)游戏结束(二)TiledMap编辑器制作游戏地图1、创建游戏地图新建一个游戏地图,地图大小设置如下:2、编辑游戏地图通过TiledMap编辑器编辑一个大型游戏地图,如下图所示。3、记录游戏地图中砖块的GID值并记录下每个要作为地面的图块的GID值,GID值显示在地图编辑器的左下角,如下图中方括号中存放的值即为选中方块的GID值。4、导出游戏地图将制作好的地图导出为tmx文件。接着创建一个Cocos2d项目,将制作好的地图和图片资源文件一起放到新建好的项目的Resource文件夹中。(三)配置文件与游戏管理文件1、游戏配置文件游戏需要新建一个Config.h的头文件,此文件用来定义游戏中需要的参数,包括玩家、地图的标记、玩家资源的相关参数、资源路径等等。usingnamespacestd;staticconstintPLAYER_TAG=110;//playertagstaticconstintMAP_TAG=111;//maptagstaticintPLAYER_WIDTH=100; //playerimgwidthstaticintPLAYER_HEIGHT=100; //playerimgheightstaticintPLAYER_JUMP_SPEED=30;//playerjumpspeedstaticstringMAP_TMX_FILE_PATH="Chapter05/MoveAndControl.tmx";staticstringMAP_BG_LAYER_NAME="back";//mapbackgroundlayernamestaticintMAP_FLOUR_NUM=6;staticintMAP_FLOUR[]={7,8,151,170,171,172};staticstringGAME_OVER_TIPS="GameOver!";//gamefailedtipswordsstaticstringGAME_SUCCESS="Success!";//gamesuccesstipswords// fntfilepathstaticstringTIPS_FNT_PATH="fonts/futura-48.fnt";//playerimgpathstaticstringPLAYER_IMG_PATH[4]={ "Chapter05/player/player1.png", "Chapter05/player/player2.png", "Chapter05/player/player3.png", "Chapter05/player/player4.png"};enumDir{ STOP, UP, DOWN};2、游戏的管理文件GameManager.h类#include"cocos2d.h"USING_NS_CC;usingnamespacecocos2d;#defineGM()GameManager::getInstance()classGameManager:publicRef{public: GameManager(); virtual~GameManager(); virtualboolinit(); staticGameManager*getInstance();public: //获取精灵相对于地图的坐标 Vec2getMapPosition(TMXTiledMap*map,Node*node); //获取精灵指定位置的图块编号 intgetTileID(TMXTiledMap*map,Node*node);private: staticGameManager*m_gameManager;};GameManager.cpp#include"GameManager.h"#include"Config.h"GameManager::GameManager(){}GameManager::~GameManager(){ m_gameManager=NULL;}boolGameManager::init(){ returntrue;}GameManager*GameManager::m_gameManager=NULL;GameManager*GameManager::getInstance(){ if(m_gameManager==NULL) { m_gameManager=newGameManager(); m_gameManager->init(); } returnm_gameManager;}Vec2GameManager::getMapPosition(TMXTiledMap*map,Node*node){ //玩家相对于屏幕的坐标 floatpx=node->getPositionX(); floatpy=node->getPositionY()-node->getContentSize().height/2; //地图相对于屏幕的x坐标 floatmx=abs(map->getPositionX()); floatmy=0; //玩家相对于地图的坐标 returnVec2(px+mx,py+my);}intGameManager::getTileID(TMXTiledMap*map,Node*node){ Vec2current=getMapPosition(map,node); returnmap->getLayer(MAP_BG_LAYER_NAME)->getTileGIDAt(Vec2((int)(current.x/map->getTileSize().width),(int)(map->getMapSize().height-1-current.y/map->getTileSize().height)));}(四)加载游戏地图MapScene.cpp文件中。voidMapScene::loadMap(std::stringmapPath){ //加载地图 automap=TMXTiledMap::create(mapPath); if(map!=NULL) { this->addChild(map,2); map->setTag(MAP_TAG); map->setPosition(Vec2(0,0)); }else { CCLOG("loadmapfailed!"); return; }}(五)添加玩家(序列帧动画)voidMapScene::addPlayer(Vec2pos){ //玩家跑动动画 Vector<SpriteFrame*>frameVector; for(inti=0;i<4;i++) { autospriteFrame=SpriteFrame::create(PLAYER_IMG_PATH[i],Rect(0,0,PLAYER_WIDTH,PLAYER_HEIGHT)); frameVector.pushBack(spriteFrame); } autoanimation=Animation::createWithSpriteFrames(frameVector); animation->setDelayPerUnit(0.07f); autoanimate=Animate::create(animation); //添加玩家 autoplayer=Sprite::create(); player->setTag(PLAYER_TAG); player->runAction(RepeatForever::create(animate)); this->addChild(player,10); player->setPosition(pos);}(六)触屏监听voidMapScene::addTouchListener(){ //加入触摸的处理 autolistener=EventListenerTouchOneByOne::create(); listener->onTouchBegan=CC_CALLBACK_2(MapScene::onTouchBegan,this); Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this);}boolMapScene::onTouchBegan(Touch*touch,Event*unused_event){ if(!this->m_isJump){ m_isJump=true; m_jumpDir=Dir::UP; } returntrue;}(七)游戏结束voidMapScene::success(){ autotips=Label::createWithBMFont(TIPS_FNT_PATH,GAME_SUCCESS); SizevisibleSize=Director::getInstance()->getVisibleSize(); tips->setPosition(Vec2(visibleSize.width/2,visibleSize.height/2)); this->addChild(tips,10);}(八)游戏地图的移动与碰撞检测的实现voidMapScene::update(floatt){ autoplayer=this->getChildByTag(PLAYER_TAG); automap=(TMXTiledMap*)getChildByTag(MAP_TAG); //玩家相对于屏幕的坐标 floatplayer_screen_x=player->getPositionX(); floatplayer_screen_y=player->getPositionY()-player->getContentSize().height/2; //地图相对于屏幕的x坐标 floatmap_screen_x=abs(map->getPositionX()); floatmap_screen_y=0; //玩家相对于地图的坐标 floatplayer_map_x=player_screen_x+map_screen_x; floatplayer_map_y=player_screen_y+map_screen_y; //不跳动时遇到非地面图块自动下落 if((int)(player_map_y/map->getTileSize().width)>=0) { intplayerTiledID=map->getLayer(MAP_BG_LAYER_NAME)->getTileGIDAt(Vec2((int)(player_map_x/map->getTileSize().width),(int)(map->getMapSize().height-1-player_map_y/map->getTileSize().height))); if((m_isJump==false)&&(m_jumpDir==Dir::STOP)&&(playerTiledID!=8)&&(playerTiledID!=7) &&(playerTiledID!=151)&&(playerTiledID!=170)&&(playerTiledID!=171)&&(playerTiledID!=172)){ m_isJump=true; m_jumpDir=Dir::DOWN; m_jumpSpeed=2; } } //处理玩家的跳跃 if(m_isJump){ if(m_jumpDir==Dir::UP){ player->setPositionY(player->getPositionY()+m_jumpSpeed); m_jumpSpeed-=2; if(m_jumpSpeed<=0) { m_jumpDir=Dir::DOWN; } }elseif(m_jumpDir==Dir::DOWN) { //用于记录玩家是否落到地面上 boolcheck=false; for(inti=0;i<m_jumpSpeed;i+=2){ //计算当前玩家相对于地图的坐标 floatplayer_screen_x=player->getPositionX(); floatplayer_screen_y=player->getPositionY()-player->getContentSize().height/2+i; //地图相对于屏幕的x坐标 floatmap_screen_x=abs(map->getPositionX()); floatmap_screen_y=0; //玩家相对于地图的坐标 floatplayer_map_x=player_screen_x+map_screen_x; floatplayer_map_y=player_screen_y+map_screen_y; //获取玩家脚下的地图块的编号 if(player_map_y/map->getTileSize().width>=0){ inttiledID=map->getLayer(MAP_BG_LAYER_NAME)->getTileGIDAt(Vec2((int)(player_map_x/map->getTileSize().width),(int)(map->getMapSize().height-1-player_map_y/map->getTileSize().height))); if(tiledID==8||tiledID==7||tiledID==151||tiledID==170||tiledID==171||tiledID==172){ check=true; player->setPositionY((int)(player_screen_y+player->getContentSize().height/2-6)); m_jumpSpeed=PLAYER_JUMP_SPEED; m_jumpDir=Dir::STOP; m_isJump=false; break; } } if(player_screen_y<=-80){ gameOver();//角色死亡 } } if(!check) { player->setPositionY(player->getPositionY()-m_jumpSpeed); m_jumpSpeed+=2; if(m_jumpSpeed>PLAYER_JUMP_SPEED) { m_jumpSpeed=PLAYER_JUMP_SPEED; } } } } this->getChildByTag(MAP_TAG)->setPositionX(this->getChildByTag(MAP_TAG)->getPositionX()-3); //滚动背景地图 intmapWidth=map->getMapSize().width*map->getTileSize().width; intvisibleWidth=Director::getInstance()->getWinSize().width; if(map->getPositionX()<-(mapWidth-visibleWidth)) { map->setPositionX(-(mapWidth-visibleWidth)); //地图静止后移动角色 player->setPositionX(player->getPositionX()+3); if(player->getPositionX()>visibleWidth) { player->setPositionX(visibleWidth); this->unscheduleUpdate(); this->removeChildByTag(PLAYER_TAG); success(); return; } }}(九)初始化游戏boolMapScene::init(){ if(!Layer::init()) { returnfalse; } m_isJump=false; m_jumpDir=Dir::STOP; m_jumpSpeed=PLAYER_JUMP_SPEED; m_gameOver=false; SizevisibleSize=Director::getInstance()->getVisibleSize(); Vec2origin=Director::getInstance()->getVisibleOrigin(); //加载地图 loadMap(MAP_TMX_FILE_PATH); //添加玩家 addPlayer(Vec2(80,40)); //游戏逻辑 this->scheduleUpdate(); //添加触屏侦听 addTouchListener(); returntrue;}(十)游戏运行后的效果如图。

游戏交互界面设计贪食豆基础知识交互界面设计、Cocos2d-x中的用户交互、触摸事件、碰撞检测创建摇杆类Joystick该类中包含一个枚举类型的数据结构,用于表示摇杆的方向。使用静态方法create来创建Joystick类,并有一个用来获得方向的函数。Joystick.h#ifndef__JOYSTICK_H__#define__JOYSTICK_H__#include"cocos2d.h"USING_NS_CC;enumJoystick_dir{ _LEFT, _RIGHT, _STOP};classJoystick:publicLayer{public: Joystick(); ~Joystick();//创建摇杆,aPoint是摇杆中心aRadius是摇杆半径aJsSprite是摇杆控制点aJsBg是摇杆背景 staticJoystick*create(Vec2aPoint,floataRadius,char*aJsSprite,char*aJsBg);//获取摇杆方向 Joystick_dirgetDirection();private: floatgetVelocity();//摇杆力度 voidupdate(floatdt); //初始化,aPoint是摇杆中心aRadius是摇杆半径aJsSprite是摇杆控制点aJsBg是摇杆背景 virtualboolinit(Vec2aPoint,floataRadius,char*aJsSprite,char*aJsBg); virtualboolonTouchBegan(Touch*pTouch,Event*pEvent); virtualvoidonTouchMoved(Touch*pTouch,Event*pEvent); virtualvoidonTouchEnded(Touch*pTouch,Event*pEvent);private: Vec2m_centerPoint;//摇杆中心 Vec2m_currentPoint;//摇杆当前位置 floatm_radius;//摇杆半径 Sprite*m_jsSprite;};#endif在Joystick类的初始化方法init中为摇杆创建了形态,并添加了触摸事件监听器。在getDirection方法中获得方向(本例中只设置了两个方向),并使用getVelocity获得摇杆力度。Joystick.cpp#include"Joystick.h"Joystick*Joystick::create(Vec2aPoint,floataRadius,char*aJsSprite,char*aJsBg){ Joystick*pRet=new(std::nothrow)Joystick(); if(pRet&&pRet->init(aPoint,aRadius,aJsSprite,aJsBg)){ pRet->autorelease(); returnpRet; } else{ deletepRet; pRet=NULL; returnNULL; }}//初始化aPoint是摇杆中心aRadius是摇杆半径aJsSprite是摇杆控制点aJsBg是摇杆背景boolJoystick::init(Vec2aPoint,floataRadius,char*aJsSprite,char*aJsBg){ if(!Layer::init()) { returnfalse; } m_radius=aRadius;//摇杆半径 m_centerPoint=aPoint;//摇杆控制中心 m_currentPoint=m_centerPoint; m_jsSprite=Sprite::create(aJsSprite);//摇杆控制点 m_jsSprite->setPosition(m_centerPoint); auto_aJsBg=Sprite::create(aJsBg);//摇杆背景 _aJsBg->setPosition(m_centerPoint); _aJsBg->setTag(88); this->addChild(_aJsBg); this->addChild(m_jsSprite); this->scheduleUpdate(); autolistener=EventListenerTouchOneByOne::create(); listener->onTouchBegan=CC_CALLBACK_2(Joystick::onTouchBegan,this); listener->onTouchMoved=CC_CALLBACK_2(Joystick::onTouchMoved,this); listener->onTouchEnded=CC_CALLBACK_2(Joystick::onTouchEnded,this); Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this); returntrue;}//获取摇杆当前方向Joystick_dirJoystick::getDirection(){ if((m_currentPoint-m_centerPoint).x>0) { returnJoystick_dir::_RIGHT; }if((m_currentPoint-m_centerPoint).x<0) { returnJoystick_dir::_LEFT; } returnJoystick_dir::_STOP;}//获取摇杆力度floatJoystick::getVelocity(){ returnm_centerPoint.getDistance(m_currentPoint);}//更新摇杆按钮位置voidJoystick::update(floatdt){ m_jsSprite->setPosition(m_jsSprite->getPosition()+(m_currentPoint-m_jsSprite->getPosition())*0.5);}boolJoystick::onTouchBegan(Touch*pTouch,Event*pEvent){ autotouchPoint=pTouch->getLocation(); if(touchPoint.getDistance(m_centerPoint)>m_radius){ returnfalse; } m_currentPoint=touchPoint; returntrue;}voidJoystick::onTouchMoved(Touch*pTouch,Event*pEvent){ autotouchPoint=pTouch->getLocation(); if(touchPoint.getDistance(m_centerPoint)>m_radius) { m_currentPoint=m_centerPoint+(touchPoint-m_centerPoint).getNormalized()*m_radius; }else{ m_currentPoint=touchPoint; }}voidJoystick::onTouchEnded(Touch*pTouch,Event*pEvent){ m_currentPoint=m_centerPoint;}在HelloWorld场景中使用摇杆类在头文件中声明一个小豆子主角bean和一个遥感类m_joystick,以及一个放置小球的Vector数组以及添加和删除小球的方法。HelloWorld.h#include"cocos2d.h"#include"Joystick.h"classHelloWorld:publiccocos2d::Layer{public:staticcocos2d::Scene*createScene();virtualboolinit();//aselectorcallbackvoidmenuCloseCallback(cocos2d::Ref*pSender); voidaddBall1(floatdt); voidaddBall2(floatdt); voidaddBall3(floatdt); voidremoveBall(Sprite*ball); voidupdate(floatdt);CREATE_FUNC(HelloWorld);private: Sprite*bean; SizevisibleSize; Joystick*m_joystick; Vector<Sprite*>ballVector;};#endif//__HELLOWORLD_SCENE_H__.cpp文件中在init方法中创建了一个背景颜色层,并初始化了豆子bean和一个遥感类。并启动了三个调度器来分别以不同的时间间隔来调用小球的三个生成方法,以及一个用于实时更新的调度器,来启动该程序的update函数。在update函数里实现了小球与小豆子的碰撞检测和小豆子的位置更新,以便于能够实时检测,更新状态。HelloWorld.cpp#include"HelloWorldScene.h"USING_NS_CC;Scene*HelloWorld::createScene(){autoscene=Scene::create();autolayer=HelloWorld::create();scene->addChild(layer);returnscene;}boolHelloWorld::init(){if(!Layer::init()){returnfalse;}visibleSize=Director::getInstance()->getVisibleSize();Vec2origin=Director::getInstance()->getVisibleOrigin(); //添加颜色层 autocolorLayer=LayerColor::create(Color4B(128,125,200,255),480,visibleSize.height); colorLayer->setPosition(Vec2(200,0)); this->addChild(colorLayer);autocloseItem=MenuItemImage::create("CloseNormal.png","CloseSelected.png",CC_CALLBACK_1(HelloWorld::menuCloseCallback,this)); closeItem->setPosition(Vec2(origin.x+visibleSize.width-closeItem->getContentSize().width/2,origin.y+closeItem->getContentSize().height/2));automenu=Menu::create(closeItem,NULL);menu->setPosition(Vec2::ZERO);this->addChild(menu,1); //移动精灵 bean=Sprite::create("bean.png"); bean->setPosition(Point(visibleSize.width/2,100)); this->addChild(bean,6); //摇杆 m_joystick=Joystick::create(Vec2(100,100),50.0f,"j-btn.png","j-bg.png"); this->addChild(m_joystick,4); this->schedule(schedule_selector(HelloWorld::addBall1),1.0f); this->schedule(schedule_selector(HelloWorld::addBall2),2.0f); this->schedule(schedule_selector(HelloWorld::addBall3),3.0f); this->scheduleUpdate();returntrue;}voidHelloWorld::addBall1(floatdt){ autoball1=Sprite::create("ball.png");//使用图片创建小球 ball1->setPosition(Point(207+rand()%460,visibleSize.height));//设置小球的初始位置,这里在x方向使用了随机函数rand使得小球在随机位置出现 this->addChild(ball1,5); this->ballVector.pushBack(ball1);//将小球放进Vector数组 automoveTo=MoveTo::create(rand()%5,Point(ball1->getPositionX(),-10));//移动动作 autoactionDone=CallFunc::create(CC_CALLBACK_0(HelloWorld::removeBall,this,ball1));//当小球移动到屏幕下方时回调removeBall函数,移除小球 autosequence=Sequence::create(moveTo,actionDone,nullptr); ball1->runAction(sequence);//执行动作}voidHelloWorld::addBall2(floatdt){ autoball2=Sprite::create("ball1.png"); ball2->setPosition(Point(207+rand()%460,visibleSize.height)); this->addChild(ball2,5); this->ballVector.pushBack(ball2); automoveTo=MoveTo::create(rand()%5,Point(ball2->getPositionX(),-10)); autoactionDone=CallFunc::create(CC_CALLBACK_0(HelloWorld::removeBall,this,ball2)); autosequence=Sequence::create(moveTo,actionDone,nullptr); ball2->runAction(sequence);}voidHelloWorld::addBall3(floatdt){ autoball3=Sprite::create("ball2.png"); ball3->setPosition(Point(207+rand()%460,visibleSize.height)); this->addChild(ball3,5); this->ballVector.pushBack(ball3); automoveTo=MoveTo::create(rand()%5,Point(ball3->getPositionX(),-10)); autoactionDone=CallFunc::create(CC_CALLBACK_0(HelloWorld::removeBall,this,ball3)); autosequence=Sequence::create(moveTo,actionDone,nullptr); ball3->runAction(sequence);}voidHelloWorld::removeBall(Sprite*ball){ this->removeChild(ball); ballVector.eraseObject(ball);}voidHelloWorld::update(floatdt){ for(autoball:ballVector) { //进行碰撞检测 if(bean->getBoundingBox().intersectsRect(ball->getBoundingBox())) { autoactionDown=CallFunc::create(CC_CALLBACK_0(HelloWorld::removeBall,this,ball)); ball->runAction(actionDown); } } //控制角色移动 if(m_joystick->getDirection()==Joystick_dir::_RIGHT &&bean->getPositionX()+bean->getContentSize().width/2<=680) { bean->setPositionX(bean->getPositionX()+4); } if(m_joystick->getDirection()==Joystick_dir::_LEFT &&bean->getPositionX()-bean->getContentSize().width/2>=200) { bean->setPositionX(bean->getPositionX()-4); } if(m_joystick->getDirection()==Joystick_dir::_STOP) { bean->setPositionX(bean->getPositionX()); }}voidHelloWorld::menuCloseCallback(Ref*pSender){#if(CC_TARGET_PLATFORM==CC_PLATFORM_WP8)||(CC_TARGET_PLATFORM==CC_PLATFORM_WINRT) MessageBox("Youpressedtheclosebutton.WindowsStoreAppsdonotimplementaclosebutton.","Alert");return;#endifDirector::getInstance()->end();#if(CC_TARGET_PLATFORM==CC_PLATFORM_IOS)exit(0);#endif}运行效果如下:

二维游戏动画合成侠客行(一)动画编辑器的使用方法Cocos2d-x自带一个功能强大的免费工具集CocosStudio,它包含了游戏开发中所需要的四大功能工具:动画编辑器、UI编辑器、数据编辑器和场景编辑器,本书中使用的是v版本。动画编辑器:用于编辑游戏中使用的角色动画、特效动画、场景动画等动态的游戏资源。动画编辑器支持碎图导出,整图导出等多种资源优化方式,同时也支持关键帧动画,序列帧动画,骨骼动画等多种动画编辑方式。动画编辑器支持对Flash,PSD,Plist资源的解析。下面我们通过制作一个简单的动画来带大家初步认识CocosStudio。创建项目下载安装好CocosStudio后,打开CocosStudio将出现如下界面:图6-3CocosStudio运行界面选择AnimationEditor->文件->新建,创建新项目,这里我们命名为UI_Example,创建好项目之后将会出现图6-4所示界面,界面左上角显示的是画布大小。图6-4AnimationEditor界面导入资源在新创建项目资源面板点击鼠标右键即可导入资源,导入后资源面板状态如图6-6所示:图6-5资源图片button.png图6-6资源面板编辑动画1)渲染窗口有两种模式,形体模式和动画模式。形体模式:用户可以在该模式下组装角色部件或绑定骨骼。动画模式:编辑、调整和生成动画。2)在形体模式将导入的五边形图片素材拖放到渲染窗口,复制2份,将三个五边形分别命名为p1,p2,p3摆出如图形状:图6-7p1,p2,p33)切换进入动画模式在渲染区拉出参考线如图,交点即为A,B,C,D,E,F:在动画帧区,在时间轴p1,p2,p3上分别都在15帧和30帧处用鼠标右键添加关键帧:图6-9添加动画帧在时间轴上做如下操作:a.鼠标左键点击选中第15帧关键帧,此时把p1移动到C点,p2移动到A点,p3移动到E点;b.然后再选中时间轴第30帧关键帧,此时把p1移动到D点,p2移动到B点,p3移动到F点;到此动画设定完成,可以点击动画帧区播放键预览动画。导出动画选择文件->导出项目使用默认参数即可导出动画,打开发布目录,文件结构如下图,需要使用时需要将所有文件放在同一路径。(二)本实例的骨骼动画本例使用的素材资源来源于cocos2d-x官方提供的cpptest中的资源,打开引擎中cpptest下的Resources目录可以找到人物现有的动作可以不经过修改就能满足项目的需求,但是需要在一些动作的末尾添加帧事件:在loading动作的最后一帧,选中该帧,在右侧属性栏的帧事件写入loading_end相同方法在攻击动画最后一帧加上帧事件:attack_end以同样的方式对怪物也做相同的处理。(三)程序的实现头文件包含及常量的定义放在单独的文件config_set.h内:#ifndef__CONFIG_SET_H__#define__CONFIG_SET_H__#include"cocos2d.h"#include"cocostudio/CocoStudio.h"#include"ui/CocosGUI.h"USING_NS_CC;usingnamespacecocos2d;usingnamespacecocostudio;usingnamespacecocos2d::ui;enumState{ STAND, MOVELEFT, MOVERIGHT, ATTACK, DEATH, SMITTEN};#endif封装英雄类:Hero英雄类的内部实现需要注意的地方是处理受到攻击后播放受攻击动画的末尾,应该触发帧事件,然后让英雄回归到正常的待机状态;同样,在英雄跑动结束时,也应该回归正常的待机状态,具体实现:#ifndef__HERO_H__//Hero.h#define__HERO_H__#include"config_set.h"classHero:publicSprite{public: Hero(); ~Hero(); staticHero*create(Vec2position); voidupdate(floatdelta); voidplay(Statestate); voidhurt();//被击中 voidshowBloodTips(ints);//显示扣血数字 voidflyend(Label*label);//扣血数字移动并消失 virtualboolinit(Vec2position); voidonFrameEvent(cocostudio::Bone*bone,conststd::string&evt,intoriginFrameIndex,intcurrentFrameIndex); //setandget Armature*getArmature(){returnm_armature;} boolisAttack(){returnm_isAttack;} voidsetAttack(boolattack){m_isAttack=attack;} intgetLife(){returnm_life;} voidsetLife(intlife){m_life=life;} boolisDeath(){returnm_isdead;} intgetMaxLife(){returnm_max_life;}private: Armature*m_armature; Statem_state; boolm_isrunning; boolm_isdead; boolm_isAttack;//是否正在攻击 boolm_ishurt;//被击状态 intm_life;//生命值 intm_max_life;//最大生命值};#endif实现文件为Hero.cpp#include"Hero.h"Hero::Hero(){ m_isrunning=false; m_isdead=false; m_isAttack=false; m_ishurt=false; m_max_life=500; m_life=m_max_life;}Hero::~Hero(){}Hero*Hero::create(Vec2position){ Hero*pRet=new(std::nothrow)Hero(); if(pRet&&pRet->init(position)) { pRet->autorelease(); returnpRet; }else { deletepRet; pRet=NULL; returnNULL; }}boolHero::init(Vec2position){ if(!Sprite::init()) { returnfalse; } ArmatureDataManager::getInstance()->addArmatureFileInfo("Chapter06/AnimationScene/animation/Hero/Hero.ExportJson"); m_armature=Armature::create("Hero"); if(m_armature==NULL) { CCLOG("heroloaderror!"); returnfalse; } m_armature->setPosition(Vec2::ZERO); m_armature->getAnimation()->play("loading"); m_armature->getAnimation()->setFrameEventCallFunc(CC_CALLBACK_0(Hero::onFrameEvent,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4)); this->addChild(m_armature); this->setPosition(position); this->scheduleUpdate(); returntrue;}voidHero::update(floatdelta){ if(m_life<=0) { play(DEATH); } switch(m_state) { caseSTAND: if((m_isrunning==true)&&(m_isdead==false)&&(m_ishurt==false))//跑动结束只执行一次loading动画,避免点击attack动作无法播放 { m_armature->getAnimation()->play("loading"); m_isrunning=false; } break; caseMOVELEFT: if((this->getPositionX()>0)&&(m_isdead==false)&&(m_ishurt==false)&&(m_isAttack==false)) { if(m_isrunning==false) { m_armature->getAnimation()->play("run"); m_isrunning=true; } if(m_armature->getScaleX()!=-1) { m_armature->setScaleX(-1); } this->setPositionX(this->getPositionX()-4); } break; caseMOVERIGHT: if((m_isAttack==false)&&(this->getPositionX()<Director::getInstance()->getVisibleSize().width)&&(m_isdead==false)&&(m_ishurt==false)) { if(m_isrunning==false)//m_isrunning控制变量防止update时不断执行play("run")则永远显示run动画第一帧 { m_armature->getAnimation()->play("run"); m_isrunning=true; } if(m_armature->getScaleX()!=1.0) { m_armature->setScaleX(1); } this->setPositionX(this->getPositionX()+4); } break; caseATTACK: if(m_isdead==false&&(m_ishurt==false)) { m_isAttack=true; m_armature->getAnimation()->play("attack"); } break; caseDEATH: if(m_isdead==false) { m_isdead=true; m_armature->getAnimation()->play("death"); } break; caseSMITTEN: if(m_isdead==false) { if(m_ishurt==true) { m_armature->getAnimation()->play("smitten"); m_ishurt=false; } } break; }}voidHero::onFrameEvent(cocostudio::Bone*bone,conststd::string&evt,intoriginFrameIndex,intcurrentFrameIndex){ if(strcmp(evt.c_str(),"attack_end")==0) { m_armature->getAnimation()->play("loading"); m_isAttack=false; } if(strcmp(evt.c_str(),"smitten_end")==0) { m_armature->getAnimation()->play("loading"); }}voidHero::play(Statestate){ if(state==SMITTEN)//控制被击中时颤抖动画只播放一次 { m_ishurt=true; } m_state=state;}voidHero::hurt(){ //根据基础伤害造成随机伤害 showBloodTips(30); this->play(SMITTEN);}//显示扣血voidHero::showBloodTips(ints){ inthitCount=1; inthitRand=rand()%10; if(hitRand>3&&hitRand<8) { hitCount=2; }elseif(hitRand>7) { hitCount=3; } for(inti=0;i<hitCount;i++) { inthurt_blood=s+rand()%8; setLife(m_life-hurt_blood);//扣血 autolabel=Label::createWithBMFont("fonts/futura-48.fnt",StringUtils::format("-%d",hurt_blood)); label->setColor(Color3B::RED); this->addChild(label,5); label->setPosition(Vec2(0,0)+Vec2(20+rand()%80,10+rand()%80)); label->runAction(Sequence::create( MoveBy::create(0.7f,Vec2(0,30)), CallFunc::create(CC_CALLBACK_0(Hero::flyend,this,label)), NULL )); }}voidHero::flyend(Label*label){ label->setVisible(false); label->removeFromParent();}接下来怪物类的封装和英雄类类似:#ifndef__ENEMY_H__//Ememy.h#define__ENEMY_H__#include"config_set.h"classEnemy:publicSprite{public: Enemy(); ~Enemy(); staticEnemy*create(Vec2position); voidupdate(floatdelta); voidplay(Statestate);//播放动画 voidhurt();//被击中 voidshowBloodTips(ints);//显示扣血数字 voidflyend(Label*label);//扣血数字移动并消失 virtualboolinit(Vec2position); voidonFrameEvent(cocostudio::Bone*bone,conststd::string&evt,intoriginFrameIndex,intcurrentFrameIndex); //setandget Armature*getArmature(){returnm_armature;} boolisAttack(){returnm_isAttack;} voidsetAttack(boolattack){m_isAttack=attack;} intgetLife(){returnm_life;} voidsetLife(intlife){m_life=life;} boolisDeath(){returnm_isdead;} intgetMaxLife(){returnm_max_life;}private: Armature*m_armature; Statem_state;//人物动画状态 boolm_isrunning;//是否正在跑动 boolm_isdead;//是否死亡 boolm_isAttack;//攻击状态 boolm_ishurt;//被击状态 intm_life;//生命值 intm_max_life;//最大生命值};#endif实现文件为:#include"Enemy.h"//Emeny.cppEnemy::Enemy(){ m_isrunning=false; m_isdead=false; m_isAttack=false; m_ishurt=false; m_max_life=500; m_life=m_max_life;}Enemy::~Enemy(){}Enemy*Enemy::create(Vec2position){ Enemy*pRet=new(std::nothrow)Enemy(); if(pRet&&pRet->init(position)) { pRet->autorelease(); returnpRet; }else { deletepRet; pRet=NULL; returnNULL; }}boolEnemy::init(Vec2position){ if(!Sprite::init()) { returnfalse; } ArmatureDataManager::getInstance()->addArmatureFileInfo("Chapter06/AnimationScene/animation/tauren/tauren.ExportJson"); m_armature=Armature::create("tauren"); if(m_armature==NULL) { CCLOG("taurenloaderror!"); returnfalse; } m_armature->setPosition(Vec2::ZERO); m_armature->getAnimation()->play("loading"); m_armature->getAnimation()->setFrameEventCallFunc(CC_CALLBACK_0(Enemy::onFrameEvent,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4)); this->addChild(m_armature); this->setPosition(position); this->scheduleUpdate(); returntrue;}voidEnemy::update(floatdelta){ if(m_life<=0) { play(DEATH); } switch(m_state) { caseSTAND: if((m_isAttack==false)&&(m_isrunning==true)&&(m_isdead==false)&&(m_ishurt==false))//跑动结束只执行一次loading动画,避免点击attack动作无法播放 { m_armature->getAnimation()->play("loading"); m_isrunning=false; } break; caseMOVELEFT: if((m_isAttack==false)&&(this->getPositionX()>0)&&(m_isdead==false)&&(m_ishurt==false)) { if(m_isrunning==false) { m_armature->getAnimation()->play("run"); m_isrunning=true; } if(m_armature->getScaleX()!=1) { m_armature->setScaleX(1); } this->setPositionX(this->getPositionX()-3); } break; caseMOVERIGHT: if((m_isAttack==false)&&(this->getPositionX()<Director::getInstance()->getVisibleSize().width)&&(m_isdead==false)&&(m_ishurt==false)) { if(m_isrunning==false)//m_isrunning控制变量防止update时不断执行play("run")则永远显示run动画第一帧 { m_armature->getAnimation()->play("run"); m_isrunning=true; } if(m_armature->getScaleX()!=-1.0) { m_armature->setScaleX(-1); } this->setPositionX(this->getPositionX()+3); } break; caseATTACK: if(m_isdead==false&&(m_ishurt==false)) { m_isAttack=true; m_armature->getAnimation()->play("attack"); } break; caseDEATH: if(m_isdead==false) { m_isdead=true; m_armature->getAnimation()->play("death"); } break; caseSMITTEN: if(m_isdead==false) { if(m_ishurt==true) { m_armature->getAnimation()->play("smitten"); m_ishurt=false; } } break; }}voidEnemy::onFrameEvent(cocostudio::Bone*bone,conststd::string&evt,intoriginFrameIndex,intcurrentFrameIndex){ if(strcmp(evt.c_str(),"attack_end")==0) { m_armature->getAnimation()->play("loading"); m_isAttack=false; } if(strcmp(evt.c_str(),"smitten_end")==0) { m_armature->getAnimation()->play("loading"); }}voidEnemy::play(Statestate){ if(state==SMITTEN) { m_ishurt=true; } m_state=state;}voidEnemy::hurt(){ //根据基础伤害造成随机伤害 showBloodTips(30); play(SMITTEN);}//显示扣血voidEnemy::showBloodTips(ints){ inthitCount=1; inthitRand=rand()%10; if(hitRand>3&&hitRand<8) { h

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论