本节课的视频教程地址是:第二课在此
在开始第二节课之前,这里需要声明的是,
首先:本系列课程是为了结合Cocos2d-x 3.x 的基本组件和核心模块的学习而制作的,开发所使用的版本是3.0,但是代码稍加修改就可以运用在3.X的其他版本上。
其次:本游戏项目是一个非商业化项目,游戏资源和代码都会在后续的课程中释放出来,供大家参考使用,提供的代码所使用的解决方案是最基础和简单的,没有对引擎源码进行改造,提供给有一定Cocos2d-x的初学者,希望学习的人能再此基础上进行思考,并加以改进。
So,各位大神见笑了,可绕道~~
上一节课我们对游戏的基本需求进行了一个大概的分析,知道了游戏的基本内容,游戏中基本角色属性和游戏的基本规则特点。这节课我们就将对我们游戏项目的基本类进行分析和实现。
主要内容是:
/*! * \file ActionTool.h * \date 2015/05/07 22:10 * * \author SuooL * Contact: hu1020935219@gmail.com * * \brief 工具类:创建动画 * * TODO: long description * * \note */ #ifndef ActionTool_H__ #define ActionTool_H__ #include "cocos2d.h" USING_NS_CC; class ActionTool { public: static Animate* animationWithFrameName(const char *frameName, int iloops, float delay); static Animate* animationWithFrameAndNum(const char *frameName, int num, float delay); }; #endif // ActionTool_H__s
/*! * \class ActionTool * * \ingroup GroupName * * \brief 动画创建器 * * TODO: long description * * \note * * \author SuooL * * \version 1.0 * * \date 五月 2015 * * Contact: hu1020935219@gmail.com * */ #include "ActionTool.h" Animate* ActionTool::animationWithFrameName(const char *frameName, int iloops, float delay) { SpriteFrame* frame = NULL; Animation* animation = Animation::create(); int index = 1; // 遍历具有frameName特征的图片帧 do { String * name = String::createWithFormat("%s%d", frameName, index++); // 当前是第index帧 frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(name->getCString()); if (frame== NULL) { break; } animation->addSpriteFrame(frame); } while (true); // 设置Animation的一些基本属性 animation->setDelayPerUnit(delay); animation->setRestoreOriginalFrame(true); Animate* animate = Animate::create(animation); // 返回一个Animate return animate; } Animate* ActionTool::animationWithFrameAndNum(const char *frameName, int framecount, float delay) { SpriteFrame* frame = NULL; Animation* animation = Animation::create(); // 遍历图片帧 for (int index = 1; index <= framecount; index++) { String * name = String::createWithFormat("%s%d", frameName, index++); frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(name->getCString()); animation->addSpriteFrame(frame); } animation->setDelayPerUnit(delay); animation->setRestoreOriginalFrame(true); Animate* animate = Animate::create(animation); /* // 第二中实现方式,用一个帧图片的向量数组,创建Animation Vector<SpriteFrame*> animFrames; char str[20]; for (int k = 1; k <= framecount; k++) { sprintf(str, "%s%d.png", frameName, k); SpriteFrame *frame = SpriteFrameCache::getInstance()->spriteFrameByName(str); animFrames.pushBack(frame); } return Animate::create(Animation::createWithSpriteFrames(animFrames, delay));*/ return animate; }
public: // 根据图片名创建英雄 void InitHeroSprite(char *hero_name, int iLevel); // 返回当前英雄 Sprite* GetSprite(); // 设置动画,run_directon为精灵脸朝向,false朝右,frameName为图片帧名字 void SetAnimation(const char *frameName, float delay, bool run_directon); // 停止动画 void StopAnimation(); // 跳起动画 void JumpUpAnimation(const char *name_each, float delay, bool run_directon); // 跳落动画 void JumpDownAnimation(const char *name_each, float delay, bool run_directon); // 跳落动画结束 void JumpEnd(); // 攻击动画 void AttackAnimation(const char *name_each, float delay, bool run_directon); // 攻击动画结束 void AttackEnd(); // 死亡动画 void DeadAnimation(const char *name_each, float delay, bool run_directon); // 死亡动画结束 void DeadEnd(); // 受伤动画 void HurtByMonsterAnimation(const char *name_each, float delay, bool run_directon); // 受伤动画结束 void HurtByMonsterEnd(); // 判断英雄是否运动到了窗口的中间位置,visibleSize为当前窗口的大小 bool JudgePositosn(Size visibleSize); bool IsDead; // HP & MP 值 float m_iCurrentHp; float m_iTotleHp; float m_iCurrentMp; float m_iTotleMp; float percentage; float m_iSpeed; bool m_bIsAction; // 查看当前是否已经在打怪了 bool m_bIsJumping; // 查看是否在跳 bool IsRunning; // 判断是否在跑动画 bool IsAttack; // 判断是否在攻击动画 bool IsHurt; // 判断是否受伤 bool HeroDirecton; // 英雄运动的方向 bool m_bCanCrazy; // 判断是否处于狂暴状态 CREATE_FUNC(Hero); private: Sprite* m_HeroSprite; // 精灵 char *Hero_name; // 用来保存初始状态的精灵图片名称CPP文件的部分方法的实现代码:
// 受伤 void Hero::HurtByMonsterAnimation(const char *name_each, float delay, bool run_directon) { if (IsHurt || IsDead) return; //受伤优先 if (IsRunning || IsAttack) { m_HeroSprite->stopAllActions();//当前精灵停止所有动画 //恢复精灵原来的初始化贴图 this->removeChild(m_HeroSprite, true);//把原来的精灵删除掉 m_HeroSprite = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(Hero_name));//恢复精灵原来的贴图样子 m_HeroSprite->setFlippedX(HeroDirecton); this->addChild(m_HeroSprite); IsRunning = false; IsAttack = false; } Animate* action = ActionTool::animationWithFrameName(name_each, 1, delay); //创建回调动作,受伤动画结束调用HurtEnd() CallFunc* callFunc = CallFunc::create(this, callfunc_selector(Hero::HurtByMonsterEnd)); //创建连续动作 ActionInterval* hurtackact = Sequence::create(action, callFunc, NULL); m_HeroSprite->runAction(hurtackact); IsHurt = true; } // 受伤结束 void Hero::HurtByMonsterEnd() { m_iCurrentHp -= 20.0f; IsHurt = false; percentage = m_iCurrentHp / m_iTotleHp * 100.0f; if (m_iCurrentHp < 0.0f) { DeadAnimation("dead", 0, HeroDirecton); } } // 死亡 void Hero::DeadAnimation(const char *name_each, float delay, bool run_directon) { m_HeroSprite->stopAllActions(); // 调整方向 if (HeroDirecton != run_directon) { HeroDirecton = run_directon; m_HeroSprite->setFlippedX(run_directon); } // 创建动作 Animate* act = ActionTool::animationWithFrameName(name_each, 1, delay); //创建回调动作,攻击结束后调用AttackEnd() CallFunc* callFunc = CallFunc::create(this, callfunc_selector(Hero::DeadEnd)); //创建连续动作 ActionInterval* attackact = Sequence::create(act, callFunc, NULL); m_HeroSprite->runAction(attackact); Director::getInstance()->getScheduler()->setTimeScale(0.5); } // 死亡结束 void Hero::DeadEnd() { IsDead = true; //恢复死亡的样子 this->removeChild(m_HeroSprite, true); //把原来的精灵删除掉 m_HeroSprite = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("monsterDie6.png")); //恢复死亡的样子 m_HeroSprite->setFlippedX(HeroDirecton); this->addChild(m_HeroSprite); } // 判断位置 bool Hero::JudgePositosn(Size visibleSize) { if (this->getPositionX() > (visibleSize.width / 2.0 + 2.0) || (this->getPositionX() < visibleSize.width / 2.0 - 2.0)) // 精灵到达mid? return false; else return true;//到达中间位置 }
public: Monster(void); ~Monster(void); // 公有属性 // 怪物种类 int m_iType; //判断是否在跑动画 bool IsRunning; //判断是否在攻击动画 bool IsAttack; //判断是否在受伤动画 bool IsHurt; //判断是否死亡 bool Isdead; //怪物运动的方向 bool MonsterDirecton; // 方法 // 根据图片名创建怪物,不带血条的怪物 void InitMonsterSprite(char *name, char *a, char *die, char *walk, char *dieLast, int m_iLevel); //返回英雄 Sprite* GetSprite(); //设置走动动画,num为图片数目,run_directon为精灵脸朝向,false朝右,name_each为name_png中每一小张图片的公共名称部分 void SetAnimation(const char *name_each, bool run_directon, float delay, int iLoops); //停止走动动画 void StopAnimation(); //攻击动画 void AttackAnimation(const char *name_each, bool run_directon, float delay, int iLoops); //攻击动画结束 void AttackEnd(); //受伤动画 void HurtAnimation(const char *name_each, bool run_directon, float delay, int iLoops); //受伤动画结束 void HurtEnd(); //死亡动画 void DeadAnimation(const char *name_each, bool run_directon, float delay, int iLoops); //死亡动画结束 void DeadEnd(); //怪物死亡闪烁结束 void BlinkEnd(); //在可视范围内,怪物跟随英雄运动 void FollowRun(Hero* m_hero, GameMap* m_map); //判断是否攻击 void JudegeAttack(float dt); //怪物启动监听英雄 void StartListen(Hero* m_hero, GameMap* m_map); //监听函数,每隔3秒检测下,计算英雄与怪物的距离 void updateMonster(float delta); //更新函数,如果英雄在可视范围内,不断触发 void update(float delta); CREATE_FUNC(Monster); private: Sprite* m_MonsterSprite; // 怪物精灵 char *Monster_name; // 用来保存初始状态的精灵图片名称 char *Monster_a; // 怪物攻击帧 char *Monster_die; // 死亡帧 char *Monster_walk; // 行走帧 char *Die_name; Hero* my_hero; // 当前英雄 GameMap* my_map; // 当前地图 float dis; // 当前怪物和英雄的距离 int m_iHP;这里具体实现部分代码可以参考http://cn.cocos2d-x.org/tutorial/show?id=2242
原文:http://blog.csdn.net/suool/article/details/46236317