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


    三:下次内容

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


    四:

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

    资源&代码

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

  • 相关阅读:
    CUDA教程三、cuda的随机数生成
    python 使用element tree 解析 xml
    [转载] Shell正则表达式大全
    git 更新项目中子模块的版本
    git 切换到本地不存在但远端存在的分支
    vue.js3:在css中使用变量(vue@3.2.6)
    mybatis做update:动态传入要更新的字段名和字段值(mybatis 3.5.7)
    npm全局安装和非全局安装的区别(node v16.13.1 / npm 8.4.1)
    vue.js3:用mitt发送接收事件消息(vue@3.2.6 / mitt@3.0.0)
    vue3: 动态修改favicon(网站的ico 图标)(vue@3.2.26)
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5090176.html
Copyright © 2020-2023  润新知