Funcode学习笔记:完成Run、Jump、Idle等动作【后续更新Roll、Attack动作的实现】【By Myself】

article/2025/9/3 4:19:58

先来实现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】;

f702d48257a641909a08b0effdf4cd6f.png

 8bc8b1727b3e466e93334090c414c0ca.png

明白了真正的需求,那么我们就得想办法怎么去实现;

本菜查了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时,VertSt=-1,垂直速度为0时VertSt=0;
bool IsGround;//当位于地面上时IsGround=1,否则为0

先说一下我们的愿景:按下K时给人物一个向上的速度,如果角色垂直速度>0,那么我们就播放Jump动画,如果垂直速度<0那么我们播放Fall函数;

那么我们怎么判断是否在地面上呢?

我们可以用写一个函数JudIsGround(float Time);我们可以利用funcode中GameRun函数提供的一个参数fDeltaTime,这个参数是上一帧到这一帧之间的时间差,我们可以将这个变量传入到JudIsGround中:

我们先在JudIsGround函数中定义一个static变量OnGroundTime;

当垂直速度为0时,即VertSt=0时,我们OnGroundTime+=fDeltaTime;

当OnGroundTime>=0.05时,我们认为人物在地面上,即将IsGround=1;

如果垂直速度不等于0,那么IsGround=0;

然后我们要来实现跳跃动作;

首先要在funcode界面给人物一个重力:

c56dfe3ac38c4f0a93cd21a2d1941484.png

这个其实很好弄,当在IsGround=1且按下K键时,我们给人物一个向上的速度;

因为有重力,所以速度会递减,如何我们在GameRun中不断用funcode提供的获取垂直速度的函数来判断VertSt的数值,如何不断用VertSt判断该播放那个动画:

d592d031bbee4d6081360afa736c1153.png

 b3025f31c9df461aa80142a72c8126b6.png

 如果VertSt>0播放Jump,如果<0播放Fall;

那么优化后的类如下:

class King{bool PressA;bool PressD;int LevelSt;int VertSt;bool IsGround;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 JudIsGrond(float Time){static float OnGroundTime;if(VertSt==0) OnGroundTime+=Time;else IsGround=0;if(OnGroundTime>=0.05){IsGround=1;OnGroundTime=0;}}void VertSpeedChangeVertSt(){static SpeedY;SpeedY=KingRed->GetSpriteLinearVelocityY();if(SpeedY<0) VertSt=1;//funcode中向上时速度小于0else if(SpeedY>0) VertSt=-1;else VertSt=0;}void SpritePlayAnimation(){//根据LevelStstatic 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,写出一坨屎山;

这里本菜总结出一个大概的框架,即人物状态因该为如何:

等待输入->播放动画->状态判断和状态校正->等待输入;


http://chatgpt.dhexx.cn/article/04kEscoR.shtml

相关文章

funcode小游戏暑假大作业,开源,新颖,游戏名:凿空,免费。

Funcode小游戏暑期大作业新颖制作 &#x1f601;里面有五个关卡&#xff0c;每个关卡玩法不同&#xff0c;虽然技术含量不高&#xff0c;但是绝对够新颖。 &#x1f602;本款游戏名叫凿空&#xff0c;小组合作制品&#xff0c;当时对代码没那么了解&#xff0c;所以写起来比较乱…

手把手教你做多重线性逐步回归

1.案例背景与分析策略 1.1 案例背景介绍 某研究收集到美国50个州关于犯罪率的一组数据&#xff0c;包括人口、面积、收入、文盲率、高中毕业率、霜冻天数、犯罪率共7个指标&#xff0c;现在我们想考察一下州犯罪率和哪些指标有关。数据上传SPSSAU后&#xff0c;在 “我的数据…

讲讲逐步回归

总第178篇/张俊红 01.前言 前面我们讲过了多元线性回归。这一篇我们来讲讲逐步回归。什么是逐步回归呢&#xff1f;就是字面意思&#xff0c;一步一步进行回归。 我们知道多元回归中的元是指自变量&#xff0c;多元就是多个自变量&#xff0c;即多个x。这多个x中有一个问题需要…

多重共线性产生原因及处理办法+R语言+糖尿病数据案例分析+逐步回归法

1、多重共线性 多重共线性一般是在&#xff08;1&#xff09;时间序列数据和&#xff08;2&#xff09;横截面数据中会发生。 产生的影响 &#xff08;1&#xff09;OLS得到的回归参数估计值很不稳定 &#xff08;2&#xff09;回归系数的方差随共线性强度增加而增长 &#…

SPSS多元线性回归及逐步回归教程

点击分析->回归->线性会出来如图 选择自变量&#xff0c;因变量。点击左侧然后点击即可选择变量并将它添加到自变量、因变量。 点击统计&#xff0c;需要额外勾选共线性诊断和然后点击继续&#xff0c;点击 设置成如图 。 解释&#xff1a;---------------------------…

Python OLS 双向逐步回归

算法基本思路&#xff1a;首先需要确定一个因变量y以此构建一元回归方程&#xff0c;再找到已通过显著性检验的一元线性回归方程中F值最大的解释变量x0&#xff0c;将其并入回归方程中&#xff0c;再分别将剩余的解释变量与解释变量x0作为OLS函数的自变量集拟合回归方程&#x…

逐步回归分析

逐步回归分析 在实际问题中,首先碰到的问题是如何确定自变量。通常是根据所研究的问题,结合经济理论,罗列出对因变量可能有影响的一些因素作为自变量。 因此,我们需要挑选出对因变量有显著影响的自变量,构造最优的回归方程。 逐步回归的基本思想是:将变量一个一个引入,…

向前逐步回归

向前逐步回归 我们在进行拟合的时候&#xff0c;没有必要将所有变量都引入到我们的函数之中&#xff0c;这种操作往往会导致过拟合&#xff0c;而过拟合带来的致命影响就是泛化能力差&#xff0c;最小二乘法估计参数的时候无法终止学习的过程。向前逐步回归的引入则可以控制学…

SPSSAU中逐步回归法——探索分析单支股票数据(实践)

数据说明&#xff1a; 还是选择万兴科技的股票数据来做回归分析&#xff0c;和《股票时序分析和时序模型&#xff08;实践&#xff09;》这篇文章使用数据一致。需要说明由于spssau免费账号最多输入50项数据&#xff0c;所以使用的都是近50期数据。 spssau上的相关分析图 pyth…

多元逐步回归算法

先谈一下个人对多元逐步回归的理解&#xff1a;多元逐步回归的最本质的核心是最小二乘原理&#xff0c;本方法中调用smf方法。# encoding: utf-8""" 功能&#xff1a;多元逐步回归 描述&#xff1a;基于python实现多元逐步回归的功能 作者&#xff1a;CHEN_C_W …

【模型开发】逐步回归

1.定义 当变量中含有对被解释变量影响不大的解释变量时&#xff0c;可能因为误差平方和的自由度减小而使方差的估计增大&#xff0c;从而影响回归预测的精度&#xff0c;适当的选择一个变量建立一个最优的回归方程十分重要。 逐步回归&#xff08;Stepwise Regression&#xff…

matlab逐步回归分析法,天大matlab大作业逐步回归分析方法.doc

天大matlab大作业逐步回归分析方法.doc 逐步回归分析方法在实际中&#xff0c;影响Y的因素很多&#xff0c;这些因素可能存在多重共线性(相关性)&#xff0c;这就对系数的估计带来不合理的解释&#xff0c;从而影响对Y的分析和预测。“最优”的回归方程就是包含所有对Y有影响的…

【R语言数据科学】(十九):变量选择(一)逐步回归法

【R语言数据科学】 🌸个人主页:JOJO数据科学📝个人介绍:统计学top3高校统计学硕士在读💌如果文章对你有帮助,欢迎✌关注、👍点赞、✌收藏、👍订阅专栏✨本文收录于【R语言数据科学】本系列主要介绍R语言在数据科学领域的应用包括: R语言编程基础、R语言可视化、R…

4.1程序控制流图

程序控制流图&#xff0c;简称流图&#xff0c;是对程序流程图进行简化后得到的&#xff0c;它可以更加突出的表示程序控制流的结构。 控制流图中包括两种图形符号&#xff1a; 节点控制流线 复合条件要分解为简单条件 判定节点&#xff08;谓词节点&#xff09; 由判定节点发…

流程控制(上)

大家好&#xff0c;我是Python领域的博主。 如果你是编程爱好者可以小编一起学习&#xff0c;在这里我每天都会发Python的基础知识&#xff0c;以及相关的代码。 如果文章有什么错误的地方&#xff0c;请不吝赐教。 觉得博主文章写的还错的话&#xff0c;请三连支持一下博主哦 …

使用soot和graphviz画Java的控制流图

辛苦两天了&#xff0c;啥也不说&#xff0c;先来张图&#xff1a; 看着可真漂亮&#xff0c;O(∩_∩)O哈哈~ 实验环境是Ubuntu。 1.JDK的版本必须是1.7或者以下&#xff0c;JDK1.8不行&#xff0c;总会报错&#xff0c; 2.下载sootclasses-2.5.0.jar包&#xff1a;http://d…

软件测试----------------- 控制流图 圈复杂度 独立路径 测试用例

最近在学软件测试&#xff0c;学到了画&#xff0c;控制流图 圈复杂度 独立路径 测试用例&#xff0c;这里&#xff0c;有些不理解&#xff0c;就网上查了下&#xff0c;发现好多老哥写错了&#xff0c;大佬写的甚至收费79。 我试着写写&#xff0c;如果有不足的&#xff0c;大…

LLVM CFG控制流图可视化

LLVM CFG控制流图可视化 准备 安装必要组件 sudo apt-get install -y graphviz-doc libgraphviz-dev graphviz示例程序 /// file 1.c int x 10; int y 11; int main(){int z 12; for (int i 0;i < 10;i){z * x * y;} return 0; }生成LLVM IR 文件 clang -S -em…

白盒测试--控制流测试(白盒测试,逻辑覆盖,路径测试(基路径测试、循环测试),控制流图)

文章目录 白盒测试概念白盒测试方法--控制流测试语句覆盖判定覆盖&#xff08;分支覆盖&#xff09;条件覆盖判定-条件覆盖条件组合覆盖路径覆盖 路径测试基路径测试循环测试 控制流图基本控制流图复合逻辑下的控制流图图矩阵环形复杂度 白盒测试概念 又叫结构测试&#xff0c…

控制流分析(Control Flow Analysis)

控制流(Control Flow)&#xff1a;操作的序列 控制流分析(Control Flow Analysis)&#xff1a;通过分析程序去发现每一过程内控制流层次结构。 控制流分析的原因&#xff1a; 控制流分析(CFA)能够帮助我们理解控制流图&#xff08;control-flow graphs,CFG&#xff09;的结构…