cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第八部---怪物出场
/* 说明:
**1.本次游戏实例是《cocos2d-x游戏开发之旅》上的最后一个游戏,这里用3.0重写并做下笔记
**2.我也问过木头本人啦,他说:随便写。第一别全然照搬代码。第二能够说明是学习笔记---好人
**3.这里用cocos2d-x 3.0版本号重写。非常多地方不同。可是从重写过程中也非常好的学习了cocos2d-x
*/
***每一步相应的全部代码以及用到的资源都会打包在最后给出
***为避免代码过多。每一步的代码都做了标记--一看就晓得是第几步实现的避免出错改不回去(难不成还用Git?)
***为了方便移植到手机上。对于每一步都进行编译android測试。由于非常多时候代码在win32下能够,编译就会出错,给出的代码会是測试过后的。
本次笔记内容:
1,、简单的设计思路
2、代码&效果
3、下次笔记内容
4、本次代码&资源下载
一:简单的设计思路
1、怪物须要移动。若所有放到Monster类里面就太复杂啦,于是乎和前面一样,也抽离出来一个移动控制器,怪物带着一个控制器就能够依照路线行走
2、关于移动控制器,是依据之前编辑好的怪物路线---也就是那些有顺序的点来行走,那么移动控制器得用update来实现自己主动行走
3、英雄临时仅仅有一种,可是怪物有5中,也有其属性
4、每一关的怪物数量。种类也通过plist文件来配置,仅仅只是要手动
二:代码&效果
这里先有一个移动控制器的基类:
#define CHECK_MOVE_SPEED_LVL1 0.1f //移动间隔
#define CHECK_MOVE_SPEED_LVL2 0.04f
#define CHECK_MOVE_SPEED_LVL3 0.03f #define SPEED 1 class ControllerMoveBase : public Node{
public:
ControllerMoveBase();
~ControllerMoveBase();
CC_SYNTHESIZE(int,_speed,Speed); protected:
Entity* _entity; //实体
bool _isMoving; //是否在移动
bool _isXLeft; //x方向是否在左移
bool _isYUp; //y方向是否在上移
int _checkMoveSpeed;//移动间隔 //依据当前Pos。以及目标点。获取下一个点坐标
Point getNextPos(Point curPos,Point destPos);
};
解释一下getNextPos函数,如我们编辑好的地图,两个点。(0,0) (0,500)那么最開始curPos 就是(0。0) 到达目标点之前,目标点一直都是(0,500),一秒之后走到了(0,100);那么此时curPos就是这个。然后继续依照速度计算下一个点
实现:
ControllerMoveBase::ControllerMoveBase(){
_isMoving = false;
_isXLeft = false;
_isYUp = false;
_speed = SPEED;
_checkMoveSpeed = CHECK_MOVE_SPEED_LVL2;
_entity = NULL;
}
ControllerMoveBase::~ControllerMoveBase(){
CC_SAFE_RELEASE(_entity);
} Point ControllerMoveBase::getNextPos(Point curPos,Point destPos){
//移动方向
if(curPos.x > destPos.x){
_isXLeft = true;
}
else{
_isXLeft = false;
} if(curPos.y < destPos.y){
_isYUp = true;
}
else{
_isYUp = false;
} //改变坐标
if(curPos.x < destPos.x && _isXLeft == false){
curPos.x += _speed;
if(curPos.x > destPos.x){
curPos.x = destPos.x;
}
}
else if(curPos.x > destPos.x && _isXLeft){
curPos.x -= _speed;
if(curPos.x < destPos.x){
curPos.x = destPos.x;
}
} if(curPos.y < destPos.y && _isYUp == true) {
curPos.y += _speed;
if(curPos.y > destPos.y) {
curPos.y = destPos.y;
}
}
else if(curPos.y > destPos.y && _isYUp == false) {
curPos.y -= _speed;
if(curPos.y < destPos.y) {
curPos.y = destPos.y;
}
}
return curPos;
}
那么来一个简单的移动控制器。也就是要用到怪物身上的。h
class ControllerSimpleMove : public ControllerMoveBase{
public:
ControllerSimpleMove();
~ControllerSimpleMove();
static ControllerSimpleMove* create(Entity* entity);
bool init(Entity* entity); void moveByPoslist(Vector<PosBase*> posList, int speed, int spanTime); private:
Vector<PosBase*> _movePosList; //依据坐标点移动
PosBase* _curDestPos; //当前的目标点
float _moveSpan; //移动时间间隔
float _moveTimeCnt; //移动计时 //移动update
void checkMoveUpdate(float delta); void nextMovePos(); };
.cpp
ControllerSimpleMove::ControllerSimpleMove(){
_curDestPos = NULL;
_moveTimeCnt = 0;
_moveSpan = 0;
}
ControllerSimpleMove::~ControllerSimpleMove(){
CC_SAFE_RELEASE(_curDestPos);
} ControllerSimpleMove* ControllerSimpleMove::create(Entity* entity){
ControllerSimpleMove* simpleMove = new ControllerSimpleMove();
if(simpleMove && simpleMove->init(entity)){
simpleMove->autorelease();
}
else{
CC_SAFE_DELETE(simpleMove);
}
return simpleMove;
} bool ControllerSimpleMove::init(Entity* entity){
CC_SAFE_RETAIN(entity);
this->_entity = entity; this->schedule(schedule_selector(ControllerSimpleMove::checkMoveUpdate)); return true;
} void ControllerSimpleMove::checkMoveUpdate(float delta){
if(_isMoving)
{
_moveTimeCnt += delta*1000; //移动时间到了
if(_moveTimeCnt >= _moveSpan)
{
_moveTimeCnt = 0; //**8**移动
if(_entity != NULL)
{
Point entityPos = _entity->getPosition();
Point curDestPos = _curDestPos->getPos();
//依据移动速度,来获得下一个点位置
entityPos = getNextPos(entityPos,curDestPos); _entity->setPosition(entityPos); //当走到目标点 PosBase List 中的一个点之后,就要更新目标点
if(entityPos.x == curDestPos.x && entityPos.y == curDestPos.y)
{
if(_movePosList.size() > 0){
nextMovePos();
}
}
}
}
}
} void ControllerSimpleMove::nextMovePos(){
if( _movePosList.size() <= 0){
return;
}
CC_SAFE_RELEASE(_curDestPos);
_curDestPos = (PosBase*)_movePosList.front();
CC_SAFE_RETAIN(_curDestPos); _movePosList.eraseObject(_curDestPos);
} void ControllerSimpleMove::moveByPoslist(Vector<PosBase*> posList, int speed, int spanTime){
this->_speed = speed;
this->_moveSpan = spanTime; if(posList.size() <= 0){
return;
}
this->_movePosList.clear();
this->_movePosList = posList; this->_isMoving = true; nextMovePos(); }
总之能够先从public 成员函数moveByPosList開始看,这里才開始让_isMoving true,然后開始移动一步步移动
接触真正的怪物Monster
enum EnumMonsterPropConfType {
enMonsterPropConf_ID, // 怪物ID
enMonsterPropConf_Name, // 怪物名字
enMonsterPropConf_Level, // 怪物等级
enMonsterPropConf_Type, // 怪物类型
enMonsterPropConf_ModelID, // 怪物模型ID
enMonsterPropConf_Defense, // 防御力
enMonsterPropConf_Hp, // 血量
enMonsterPropConf_Speed, // 移动速度
}; class Monster : public Entity{
public:
Monster();
~Monster(); static Monster* createFromCsvByID(int monsterID);
bool initFromCsvByID(int monsterID); //**8**有一个移动的方法。在怪物管理器中调用让其移动
void moveByPosList(Vector<PosBase*> posList); private:
CC_SYNTHESIZE(int,_level,Level);
CC_SYNTHESIZE(float,_showTime,ShowTime); ControllerSimpleMove* _moveController; };
这里也有一个public成员函数,moveByPosList。这是留给在怪物管理器中,让怪物開始活动的函数
Monster::Monster(){
_moveController = NULL;
}
Monster::~Monster(){
CC_SAFE_RELEASE(_moveController);
} Monster* Monster::createFromCsvByID(int monsterID){
Monster* monster = new Monster(); if(monster && monster->initFromCsvByID(monsterID)){
monster->autorelease();
}
else{
CC_SAFE_DELETE(monster);
}
return monster;
} bool Monster::initFromCsvByID(int monsterID){
//**8**获得ID
const char* chMonsterID = __String::createWithFormat("%d",monsterID)->getCString(); //**8**绑定精灵
const char* monsterSprite = __String::createWithFormat("sprite/monster/monster_%d.png",monsterID)->getCString();
Sprite* sprite = Sprite::create(monsterSprite);
bindSprite(sprite); //**8**绑定移动控制器
_moveController = ControllerSimpleMove::create(this);
this->addChild(_moveController); //**8**属性
CsvUtil* csvUtil = CsvUtil::getInstance();
Size csvSize = csvUtil->getFileRowColNum("csv/Monster.csv"); int line = csvUtil->findValueInWithLine(chMonsterID,enMonsterPropConf_ID,"csv/Monster.csv"); setID(monsterID);
setLevel(csvUtil->getInt(line,enMonsterPropConf_Level,"csv/Monster.csv"));
setModeID(csvUtil->getInt(line,enMonsterPropConf_ModelID,"csv/Monster.csv"));
setDefense(csvUtil->getInt(line,enMonsterPropConf_Defense,"csv/Monster.csv"));
setHP(csvUtil->getInt(line,enMonsterPropConf_Hp,"csv/Monster.csv"));
setSpeed(csvUtil->getInt(line,enMonsterPropConf_Speed,"csv/Monster.csv")); return true;
} void Monster::moveByPosList(Vector<PosBase*> posList){
if(posList.size() <= 0) return ;
_moveController->moveByPoslist(posList,2,getSpeed());
那么这里的属性什么的都和英雄差点儿相同。。
。。
仅仅只是这里须要注意一点点问题,csv/monster.csv要略微改动:怪物ID 从上到下改为1~5。而不是1000~1004、或者直接用本次的资源替换。
然后看看怪物管理器。通过plist文件载入怪物信息。update函数管理怪物出现
class MonsterManager : public Node{
public:
MonsterManager();
~MonsterManager();
static MonsterManager* createWithLevel(int curLevel);
bool initWithLevel(int curLevel); private:
//**8**有多个怪物。每个的出来的时间递增。用showTime累加。一个个登场
float _showTime; //**8**全部的坐标点
Vector<PosBase*> _monsterPosList; //**8**没有出场的怪物,一開始全部怪物都没出来
Vector<Monster*> _notShowMonsterList; //**8**配置文件里的全部怪物
Vector<Monster*> _monsterList; //**8**在init 函数中,创建怪物
void createMonsters(int curLevel); //没有出场怪物数量
int getNotShowMonsterCnt(); //怪物的起始点
PosBase* getMonsterStartPos();
PosBase* getMonsterEndPos(); //**8**展示怪物的update函数
void showMonster(float dt);
};
-----------------------------实现:
MonsterManager::MonsterManager(){
_showTime = 0;
}
MonsterManager::~MonsterManager(){
} MonsterManager* MonsterManager::createWithLevel(int curLevel){
MonsterManager* monsterMgr = new MonsterManager(); if(monsterMgr && monsterMgr->initWithLevel(curLevel)){
monsterMgr->autorelease();
}
else{
CC_SAFE_DELETE(monsterMgr);
}
return monsterMgr;
} bool MonsterManager::initWithLevel(int curLevel){
//**8**依据关卡级别创建怪物
createMonsters(curLevel); //**8**开启update,让怪物有顺序出现
this->schedule(schedule_selector(MonsterManager::showMonster));
return true;
} void MonsterManager::createMonsters(int curLevel){
//**8**载入路线坐标
__String* monsterPosPath = __String::createWithFormat("tollgate/monsterPos_level_%d.plist",curLevel);
PosLoadUtil::getInstance()->loadPosWithFile(_monsterPosList,enMonsterPos,monsterPosPath->getCString(),
this,10,false); //**8**读取当前关卡的怪物配置
__String* monsterConfPath = __String::createWithFormat("tollgate/monster_level_%d.plist",curLevel);
auto monsterConfList = FileUtils::getInstance()->getValueVectorFromFile(monsterConfPath->getCString()); for(auto ref : monsterConfList){
auto temp_map = ref.asValueMap(); int id = temp_map.at("id").asInt();
float showTime = temp_map.at("showTime").asFloat(); if( id != 0 && showTime != 0.0f){
auto monster = Monster::createFromCsvByID(id);
monster->setShowTime(showTime);
monster->setVisible(false); _monsterList.pushBack(monster);
_notShowMonsterList.pushBack(monster);
this->addChild(monster);
}
} } int MonsterManager::getNotShowMonsterCnt(){
return _notShowMonsterList.size();
} PosBase* MonsterManager::getMonsterStartPos(){
return _monsterPosList.front();
} PosBase* MonsterManager::getMonsterEndPos(){
return _monsterPosList.back();
} void MonsterManager::showMonster(float dt){
int notShowMonsterCnt = _notShowMonsterList.size(); if(notShowMonsterCnt > 0){
_showTime += dt;
} PosBase* monsterFirstPos = getMonsterStartPos(); //**8**把本次出场的怪物保存。然后删除。C++中不能在容器遍历的过程中删除,会出错
Vector<Monster*> temp_deletList; for(auto monster : _notShowMonsterList){
if(monster != NULL){
if(_showTime >= monster->getShowTime()){
temp_deletList.pushBack(monster);
monster->setPosition(monsterFirstPos->getPos());
monster->setVisible(true); monster->moveByPosList(_monsterPosList);
}
}
} for(auto deletMonster : temp_deletList){
_notShowMonsterList.eraseObject(deletMonster);
}
}
这里可到后面的资源中game/中获取怪物的管理配置文件
---------------------------------------------
然后在MapLayer中加入成员。以及在init函数中把怪物管理加入
//**8**
_monsterMgr = MonsterManager::createWithLevel(_curLevel);
this->addChild(_monsterMgr);
那么最后展演示样例如以下,怪物分组出来啦......
三:下次内容
英雄没有尽职。不攻击怪物!!!
四:
----------------------------------
----------------------------------
个人愚昧观点。欢迎指正与讨论
cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第八部---怪物出场的更多相关文章
- cocos2d-x 3.0游戏实例学习笔记 《跑酷》 完结篇--源代码放送
说明:这里是借鉴:晓风残月前辈的博客,他是将泰然网的跑酷教程,用cocos2d-x 2.X 版本号重写的,眼下我正在学习cocos2d-X3.0 于是就用cocos2d-X 3.0重写,并做相关笔记 ...
- cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第0步---知识点总结&效果预览&设计思路
/* 说明: **1.本次游戏实例是<cocos2d-x游戏开发之旅>上的最后一个游戏.这里用3.0重写并做下笔记 **2.我也问过木头本人啦,他说:随便写.第一别全然照搬代码:第二能够说 ...
- cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第二步---编辑器(1)--触摸加入点
/* 说明: **1.本次游戏实例是<cocos2d-x游戏开发之旅>上的最后一个游戏,这里用3.0重写并做下笔记 **2.我也问过木头本人啦,他说:随便写,第一别全然照搬代码:第二能够说 ...
- cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第三步---编辑器(2)---更方便很多其它操作更像编辑器
/* 说明: **1.本次游戏实例是<cocos2d-x游戏开发之旅>上的最后一个游戏,这里用3.0重写并做下笔记 **2.我也问过木头本人啦.他说:随便写,第一别全然照搬代码:第二能够说 ...
- cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第一步---開始界面&关卡选择
/* 说明: **1.本次游戏实例是<cocos2d-x游戏开发之旅>上的最后一个游戏,这里用3.0重写并做下笔记 **2.我也问过木头本人啦.他说:随便写,第一别全然照搬代码:第二能够说 ...
- cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第七步---英雄要升级&属性--解析csv配置文件
/* 说明: **1.本次游戏实例是<cocos2d-x游戏开发之旅>上的最后一个游戏,这里用3.0重写并做下笔记 **2.我也问过木头本人啦.他说:随便写,第一别全然照搬代码:第二能够说 ...
- cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第六步---炮台&点击炮台加入英雄&英雄升级
/* 说明: **1.本次游戏实例是<cocos2d-x游戏开发之旅>上的最后一个游戏,这里用3.0重写并做下笔记 **2.我也问过木头本人啦,他说:随便写,第一别全然照搬代码:第二能够说 ...
- cocos2d-x 3.0游戏实例学习笔记 《跑酷》移植到android手机
说明:这里是借鉴:晓风残月前辈的博客.他是将泰然网的跑酷教程.用cocos2d-x 2.X 版本号重写的,眼下我正在学习cocos2d-X3.0 于是就用cocos2d-X 3.0重写,并做相关笔记 ...
- cocos2d-x 3.0游戏实例学习笔记 《跑酷》第一步--- 开始界面
说明:这里是平局:晓风残月前辈的博客.他是将泰然网的跑酷教程.用cocos2d-x 2.X 版本号重写的,眼下我正在学习cocos2d-X3.0 于是就用cocos2d-X 3.0重写,并做相关笔记 ...
随机推荐
- 恢复PasswordChar 默认值、取消密码框设置
//三种都是清空 this.textBox1.PasswordChar = new char(); this.textBox1.PasswordChar = '\0'; this.textBox1.P ...
- NGUI: Documentation
Video Tutorials Basic Tutorial (v.2.5.0+) SD & HD atlas switching (advanced) Packed Font (advanc ...
- nginx的sendfile指令的作用
linux为了解决对读文件产生的从应用空间到内核空间复制数据产生的效率影响引进了零拷贝.什么是零拷贝?这里就不多说了,请参考http://blog.csdn.net/crazyguang/articl ...
- 【UVA】12299-RMQ with Shifts(线段树)
改动的时候因为数据非常小,所以能够直接暴力改动,查询的时候利用线段树即可了. 14337858 option=com_onlinejudge&Itemid=8&page=show_pr ...
- 与众不同 windows phone (15) - Media(媒体)之后台播放音频
原文:与众不同 windows phone (15) - Media(媒体)之后台播放音频 [索引页][源码下载] 与众不同 windows phone (15) - Media(媒体)之后台播放音频 ...
- form表单提交不成功提示
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...
- Spring核心技术
这是第二次看关于Spring的资料,由于刚開始学习Spring的时候是边看视频边学习的,所以更注重的是实现代码,可是对宏观的掌握还是不够,这次主要从宏观的角度来分析一下Spring. 什么是Sprin ...
- Swift - 选择框(UIPickerView)的用法
1,选择框可以让用户以滑动的方式选择值.示例如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ...
- 一int考虑什么类型的多少字节
一int表示的字节数? 问题是,我们经常得到的答案4. 但int究竟占多少个字节,却跟你的机器环境有关. As you can see, the typical data type sizes mat ...
- java.lang.ClassCastException: sun.proxy.$Proxy11 cannot be cast to分析
报这个错,只有一个原因,就是你转化的类型不对. 如果你的类是一个单实体类,也就是没有继承或是接口别的类. public class HjmServiceImpl {} 那么这样写就可以: HjmSer ...