Funcode学习笔记:完成Run、Jump、Idle等动作【后续更新Roll、Attack动作的实现】【By Myself】 |
您所在的位置:网站首页 › 游戏人物跳跃动作怎么做视频 › Funcode学习笔记:完成Run、Jump、Idle等动作【后续更新Roll、Attack动作的实现】【By Myself】 |
先来实现Run和Idle动作吧; 【以下是本菜在写游戏时犯下的一些错误,以及一些灵感,即如何解决逻辑错误的;】 首先,先大概说一下我们的愿景是什么,当我们按下A键时,人物向左边运动,且播放向左边运动的动画,我们按下右键时人物向右边运动,且播放一个向右运动的动画,当我们不按键时,人物不会有运动,且播放Idle动画; 这个思路很好实现; 我们先定义以下变量和方法; class King { bool PressA;//PressA=1时说明A键按下 bool PressD;//PressD=1时说明D键按下 public: CAnimationSprite *KingRed; void KeyChangeSpeedLeft() { KingRed->//设置精灵向左速度 } } void KeyChangeSpeedRight(){ KingRed->//设置精灵向右的速度 } void SpritePlayAnimation(bool AnimatiomRection){//根据PressA和PressD来播放动画 if(AnimationRection) //播放向左的动画 else //播放向右的动画 } }思路是这样的: 当按下就AD键时,funcode自动调用OnKeyDown函数,然后我们在OnKeyDown函数里按照按下键,调用以上3个函数,以实现左右移动和动画的播放; 但是,这里会有一个bug,即一般游戏中,能很明显地感觉到AD键对速度不是相互覆盖的关系,而是相互博弈的关系【什么意思呢?很简单,上面的函数我们可以知道,按下A键后,就直接给人物一个向左的速度,而不会去管是否按下D键,这就是相互覆盖的关系,但是正常游戏为了增加玩家的手感,都会采用AD键博弈的关系,即按下A键后,不是直接让人物直接向左移动,而是给人物一个向左的速度,如果此时D键是按下的,也给了人物一个向右的速度,那么两个速度会相结合,使人物速度为0】;
明白了真正的需求,那么我们就得想办法怎么去实现; 本菜查了funcode的API发现没有给某个方向直接加上一个速度的函数,而只有直接设置某个方向的速度; 这里有一个方法,即我们定义一个变量LevelSt,这个变量的作用是AD键博弈关系和人物速度之间的一个桥梁; LevelSt有3种状态,Level=1时,说明人物要向右移动; LevelSt=0时,说明人物水平无速度; LevelSt=-1,说明人物要向左移动; 当我们按下A键时LevelSt--,当A键弹起时LevelSt++; 当我们按下D键时LevelSt++,当D键弹起时LevelSt--; 然后我们再定义一个函数LevelStChangeLevelSpeed() 如字面意思,这个函数是通过LevelSt改变水平Speed状态的; 我们对上面的King类进行优化: class King { bool PressA; bool PressD; int LevelSt; public: CAnimationSprite *KingRed; King() :LevelSt(0), PressA(0), PressD(0) { KingRed = new CAnimationSprite("KingRed"); }//构造函数 ~King(){ delete KingRed; } void KeyAChangeLevelSt(int Measure){ LevelSt+=Measure; } void KeyDChangeLevelSt(int Measure){ LevelSt+=Measure; } void LevelStChangeLevelSpeed(){ if(LevelSt==1) //设置向右的速度 else if(LevelSt==0) //设置向左的速度 else //设置零速度 } void SpritePlayAnimation(){//根据LevelSt if(LevelSt==1) //播放向左的动画 else if(LevelSt==-1) //播放向右的动画 else //播放Idle动画,毕竟速度为0嘛 } }这个时候我们将各各函数放到CGameMain类中的各各函数中即可; 因为要受键影响,所以KeyDChangeLevelSt和KeyAChangeLevelSt函数应该放到OnKeyDown函数和OnKeyUp函数中,而函数播放是每时每刻在进行的,所以应该放到GameRun函数中; 然后按照以上框架写上写代码; ...bug出现了,因为我们每时每刻都在调用SpritePlayAnimation函数,所以一直在调用播放动画的函数,因为没次调用播放动画的函数,所以都是从第一帧开始播放的,所以我们是看不到一连串图像构成的动画的,而是只能看到第一帧图; 那么我们该怎么修该这个bug呢?? 有一个思路是这样的,当我们播放完动画后再重新播放就行了; 那么我们该怎么判断动画是否播放完了呢? funcode还算是有点用哈,它提供了一个获取当前播放动画的名字的函数; 这里啰嗦几句,说一下什么是动画的名字; 动画的名字是程序与制作好的动画的接口,当我们要在程序中调用对应的动画时,对应的接口就是动画的名字,动画的名字可以在funcode界面制作动画时自定义; funcode提供了一个函数:AnimateSpritePlayAnimation(char* AnimationName,bool IsRestore); 第一个参数就是动画的名字,第二个是一个选择播放完此动画是否回到原先的动画; 好,回归正题; 我们可以用funcode提供的函数:char *GetAnimateSpriteAnimationName();来获取当前动画的名字; 本菜的逻辑是这样的: 先获取当前动画的名字,如果当前的动画名字不等于我们需要播放的动画的名字,那么我们就播放我们需要播放的动画,反之我们不播放; 比如,我们当前要播放向右移动的动画,然后我程序发现正在播放向右移动的动画,那么我们为了不重新播放导致卡帧,我们就不播放。 注意,实现这套逻辑要将IsRestore参数调为1,即我们播放完该动画后要回到之前的动画; 那么下面是我们优化后的类: class King { bool PressA; bool PressD; int LevelSt; public: CAnimationSprite *KingRed; King() :LevelSt(0), PressA(0), PressD(0) { KingRed = new CAnimationSprite("KingRed"); }//构造函数 void KeyAChangeLevelSt(int Measure) { LevelSt += Measure; } void KeyDChangeLevelSt(int Measure) { LevelSt += Measure; } void LevelStChangeLevelSpeed() { if (LevelSt == 1) //设置向右的速度 else if (LevelSt == 0) //设置向左的速度 else //设置零速度 } void SpritePlayAnimation() {//根据LevelSt static std::string AnimationName; AnimationName = KingRed->GetAnimateSpriteAnimationName(); if (LevelSt == 1 && AnimationName != KingRunLeft) //播放向左的动画 else if (LevelSt == -1 && AnimationName != KingRunRight) //播放向右的动画 else if (AnimationName != KingIdle)//播放Idle动画,毕竟速度为0嘛 } }那么下面来实现Jump动作了; 这个的话,比较好弄。 因为现在动作多了起来,我们为了后期继续写下去,我们定义一些变量来记录当前的状态,因为有一些动作是要建立在一些状态之上才能调用的; 比如跳跃要在处于地面上的基础之上,Run动作要在处于地面的基础之上【除非你的角色是斗宗强者】 所以我们要新加以下变量: int VertSt;//垂直速度>0时VertSt=1,垂直速度0,那么我们就播放Jump动画,如果垂直速度=0.05时,我们认为人物在地面上,即将IsGround=1;如果垂直速度不等于0,那么IsGround=0; 然后我们要来实现跳跃动作; 首先要在funcode界面给人物一个重力: 这个其实很好弄,当在IsGround=1且按下K键时,我们给人物一个向上的速度; 因为有重力,所以速度会递减,如何我们在GameRun中不断用funcode提供的获取垂直速度的函数来判断VertSt的数值,如何不断用VertSt判断该播放那个动画:
如果VertSt>0播放Jump,如果=0.05){ IsGround=1; OnGroundTime=0; } } void VertSpeedChangeVertSt(){ static SpeedY; SpeedY=KingRed->GetSpriteLinearVelocityY(); if(SpeedY0) VertSt=-1; else VertSt=0; } void SpritePlayAnimation(){//根据LevelSt static std::string AnimationName; AnimationName=KingRed->GetAnimateSpriteAnimationName(); if(IsGround==0){//说明在地面上 if(LevelSt==1&&AnimationName!=KingRunLeft) //播放向左的动画 else if(LevelSt==-1&&AnimationName!=KingRunRight) //播放向右的动画 else if(AnimationName!=KingIdle)//播放Idle动画,毕竟速度为0嘛 }else{ if(VertSt==1&&AnimationName!="KingJump") //播放向上跳跃的动画 else if(Vert==-1&&AnimationName!="KingFall")//播放Fall动画 } } } 大概的思路就是如此; 以后会更新Attack和Roll动作; 为了可以拓展出更多的动画,我们必须写一些具有普适性的函数,和一些有普适性的变量,以及播放动画遍历的函数尽量路径统一,否则会多出很多bug,写出一坨屎山; 这里本菜总结出一个大概的框架,即人物状态因该为如何: 等待输入->播放动画->状态判断和状态校正->等待输入; |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |