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);
那么最后展演示样例如以下,怪物分组出来啦......


三:下次内容

英雄没有尽职。不攻击怪物!!!


四:

----------------------------------

资源&代码

----------------------------------
个人愚昧观点。欢迎指正与讨论








本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5090176.html,如需转载请自行联系原作者


相关文章
uni-app 176添加背景提示音(一)
uni-app 176添加背景提示音(一)
198 1
|
关系型数据库 MySQL 数据安全/隐私保护
在 Docker 中部署 Mysql 并挂载配置文件
在 Docker 中部署 Mysql 并挂载配置文件
|
8月前
|
弹性计算 运维 网络协议
卓越效能,极简运维,Serverless高可用架构
本文介绍了Serverless高可用架构方案,当企业面对日益增长的用户访问量和复杂的业务需求时如何实现更高的灵活性、更低的成本和更强的稳定性。
计算机组成原理(9)----硬布线控制器
计算机组成原理(9)----硬布线控制器
413 1
|
10月前
|
安全 数据挖掘 网络安全
网站建站如何选择合适的服务器配置
建站初期应进行长期数据分析与预测,合理选择服务器配置。主要依据同时在线人数、CPU性能、内存大小及带宽类型,同时考虑安全防护,如选择带防火墙的高防服务器,确保网站稳定运行与良好用户体验。
308 0
|
机器学习/深度学习 人工智能 自然语言处理
【2024泰迪杯】C 题:竞赛论文的辅助自动评阅 问题分析及Python 代码实现
本文介绍了2024泰迪杯C题“竞赛论文的辅助自动评阅”的问题分析和Python代码实现,涵盖了论文质量特征构造、自动评分模型建立以及如何利用自然语言处理技术和大语言模型进行论文自动评阅的方法。
251 2
【2024泰迪杯】C 题:竞赛论文的辅助自动评阅 问题分析及Python 代码实现
|
机器学习/深度学习 自然语言处理 并行计算
扩散模型
本文详细介绍了扩散模型(Diffusion Models, DM),一种在计算机视觉和自然语言处理等领域取得显著进展的生成模型。文章分为四部分:基本原理、处理过程、应用和代码实战。首先,阐述了扩散模型的两个核心过程:前向扩散(加噪)和逆向扩散(去噪)。接着,介绍了训练和生成的具体步骤。最后,展示了模型在图像生成、视频生成和自然语言处理等领域的广泛应用,并提供了一个基于Python和PyTorch的代码示例,帮助读者快速入门。
|
人工智能 数据挖掘 Python
提升办公生产力工具——AI数据分析应用小浣熊
办公小浣熊广泛应用于日常数据分析、财务分析、商业分析、销售预测、市场分析等多个领域,为用户提供了强大的支持。
提升办公生产力工具——AI数据分析应用小浣熊
|
机器学习/深度学习 数据采集 自然语言处理
【Deep Learning A情感文本分类实战】2023 Pytorch+Bert、Roberta+TextCNN、BiLstm、Lstm等实现IMDB情感文本分类完整项目(项目已开源)
亮点:代码开源+结构清晰+准确率高+保姆级解析 🍊本项目使用Pytorch框架,使用上游语言模型+下游网络模型的结构实现IMDB情感分析 🍊语言模型可选择Bert、Roberta 🍊神经网络模型可选择BiLstm、LSTM、TextCNN、Rnn、Gru、Fnn共6种 🍊语言模型和网络模型扩展性较好,方便读者自己对模型进行修改
1077 0
|
存储 网络协议 安全
《熬夜整理》保姆级系列教程-玩转Wireshark抓包神器教程(1)-初识Wireshark
【2月更文挑战第1天】《熬夜整理》保姆级系列教程-玩转Wireshark抓包神器教程(1)-初识Wireshark
503 3