本节课的视频教程地址是:第二课在此
在开始第二节课之前,这里需要声明的是,
首先:本系列课程是为了结合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