zoukankan      html  css  js  c++  java
  • cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第六步---炮台&点击炮台加入英雄&英雄升级

    /* 说明:

    **1.本次游戏实例是《cocos2d-x游戏开发之旅》上的最后一个游戏,这里用3.0重写并做下笔记

    **2.我也问过木头本人啦,他说:随便写,第一别全然照搬代码;第二能够说明是学习笔记---好人大笑

    **3.这里用cocos2d-x 3.0版本号重写,非常多地方不同,可是从重写过程中也非常好的学习了cocos2d-x

    */

    ***每一步相应的全部代码以及用到的资源都会打包在最后给出

    ***为避免代码过多,每一步的代码都做了标记--一看就晓得是第几步实现的避免出错改不回去(难不成还用Git?)

    ***能够依据设计思路(好吧,那名字太高大上。实际就是这一步要干啥)先自己实现---cocos2d-x本来就是如此,同样的功能有很多不同实现方法;先自己折腾是蛮不错的。

    ***为了方便移植到手机上,对于每一步都进行编译android測试;由于非常多时候代码在win32下能够,编译就会出错,给出的代码会是測试过后的。

    本次笔记内容:

    1、设计思路

    2、代码&測试效果

    3、下次内容预览

    4、本次源代码&资源

    一:设计思路

    在前一步中,进入不同级别的游戏关卡之后,载入了之前自己编辑好的炮台的点

    这一步中为这些点用真正的炮台来展示

    然后点击炮台能加入英雄

    1.首先为了后面的扩展,炮台也是应该有属性的,比方等级什么的。那么英雄和怪物相同也是,速度,防御等各种属性。那么能够抽离出一个基类Entity

    2.这一步其中是关于炮台和英雄的 关系,那么首先来设计炮台;炮台继承实体,它通过精灵来展示,而且运行了一个动作---看起来高大上

    3.那么在英雄管理器中,前面载入的点保存在容器里面啦,我们对容器遍历,对于每一个炮台坐标放一个炮台

    4.然后是英雄,这一步中,我们仅仅实现点击炮台产生英雄,英雄的属性和配置文件Csv有关之后说

    5.加入英雄之后,我们再次点击英雄,能够有一些操作,升级!删除!

    二:代码&效果

    首先看看基类:.h

    <span style="font-size:14px;">class Entity : public Node{
    public:
    	Entity();
    	~Entity();
    
    	void bindSprite(Sprite* sprite);
    	Sprite* getSprite();
    
    	void hurtMe(int hurtValue);
    
    	bool isDead();
    
    	Rect boundingBox();
    
    protected:
    	virtual void onDead();
    
    	virtual void onBindSprite();
    
    	virtual void onHurt(int hurtValue);
    private:
    	Sprite* _sprite;
    	bool _isDead;
    
    	CC_SYNTHESIZE(int,_id,ID);
    	CC_SYNTHESIZE(int,_modeID,ModeID);
    	CC_SYNTHESIZE(__String*,_Name,Name);
    	CC_SYNTHESIZE(int,_hp,HP);
    	CC_SYNTHESIZE(int,_defense,Defense);
    	CC_SYNTHESIZE(int,_speed,Speed);
    	CC_SYNTHESIZE(int,_level,Level);
    };</span>
    .cpp

    <span style="font-size:14px;">Entity::Entity(){
    	_sprite = NULL;
    	_Name = __String::create("");
    	_hp = 1;
    	_defense = 1;
    	_isDead = false;
    	_speed = 1;
    	_level = 1;
    }
    Entity::~Entity(){
    }
    
    void Entity::bindSprite(Sprite* sprite){
    	if(this->_sprite != NULL){
    		_sprite->removeFromParentAndCleanup(true);
    	}
    
    	this->_sprite = sprite;
    	this->addChild(_sprite);
    
    	//**6**假设子类绑定时须要其它作用,就重写以下的函数
    	onBindSprite();
    }
    
    Sprite* Entity::getSprite(){
    	return this->_sprite;
    }
    
    void Entity::hurtMe(int hurtValue){
    	if(_isDead){
    		return ;
    	}
    
    	if(hurtValue <= getDefense()){
    		hurtValue = 1;
    	}
    
    	int curHP = getHP();
    	int afterHP = curHP-hurtValue;
    
    	onHurt(hurtValue);
    
    	if(afterHP > 0){
    		setHP(afterHP);
    	}
    	else{
    		_isDead = true;
    		onDead();
    	}
    }
    
    Rect Entity::boundingBox(){
    	Node::boundingBox();
    	if(getSprite() == NULL){
    		return CCRectMake(0,0,0,0);
    	}
    	Point pos = getPosition();
    	Size size =  getSprite()->getContentSize();
    
    	return CCRectMake(pos.x,pos.y,size.width,size.height);
    }
    
    bool Entity::isDead(){
    	return this->_isDead;
    }
    
    //空函数,留给子类
    void Entity::onDead(){
    }
    void Entity::onBindSprite(){
    }
    void Entity::onHurt(int hurtValue){
    }</span>
    能够看到它是有一些的属性,也有受伤、死亡、精灵什么的函数;后面对于不同的实体实现不同的功能

    炮台TowerBorder.h

    <span style="font-size:14px;">class TowerBorder : public Entity{
    public:
    	TowerBorder(); 
    	~TowerBorder();
    
    	CREATE_FUNC(TowerBorder);
    	virtual bool init();
     
    	bool isClickMe(Point pos);//检測是否点击了炮台
    
    private:
    };</span>
    .cpp

    <span style="font-size:14px;">TowerBorder::TowerBorder(){
    }
    TowerBorder::~TowerBorder(){
    }
    
    bool TowerBorder::init(){
    	__String* sFilePath = __String::createWithFormat("sprite/hero/border_%d.png",_level);
    	Sprite* sprite = Sprite::create(sFilePath->getCString());
    
    	bindSprite(sprite);
    
    	ActionInterval* rotateBy = RotateBy::create(25.0f,360,360);
    	auto repeat = RepeatForever::create(rotateBy);
    
    	sFilePath = __String::createWithFormat("sprite/hero/magic_border_%d.png",_level);
    	sprite = Sprite::create(sFilePath->getCString());
    	sprite->setOpacity(80);
    	sprite->runAction(repeat);
    
    	this->addChild(sprite);
    
    	return true;
    }
    
    bool TowerBorder::isClickMe(Point pos){
    	Size size = getSprite()->getContentSize();
    	Point borderPos = getPosition();
    
    	Point srcPos = Point(borderPos.x-size.width,borderPos.y+size.height);
    	Point detPos = Point(borderPos.x+size.width,borderPos.y-size.height);
    
    	if(pos.x>=srcPos.x && pos.x<=detPos.x && pos.y<=srcPos.y && pos.y>=detPos.y){
    		return true;
    	}
    
    	return false;
    }</span>
    然后測试一下:在HeroManager里面加入成员:

    <span style="font-size:14px;">Vector<TowerBorder*> m_towerBorderList;
    void createTowerBorder();</span>
    那么在createTowerPos之后,我们调用createTowerBorder,也就是通过点来加入炮台

    <span style="font-size:14px;">void HeroManager::createTowerPos(int curLevel){
    	/******************省略代码***************/
    	//**6** 载入全然部的点,那么就用点来加入炮台
    	createTowerBorder();
    }
    
    void HeroManager::createTowerBorder(){
    	PosBase* tPos = NULL;
    	for(auto ref : m_towerPosList){
    		tPos = dynamic_cast<PosBase*>(ref);
    
    		if(tPos != NULL){
    			TowerBorder* border = TowerBorder::create();
    			border->setPosition(tPos->getPos());
    			this->addChild(border);
    			
    			m_towerBorderList.pushBack(border);
    		}
    	}
    }</span>
    把之前为了看到点坐标的 调式模式改为false,背景图片不设计透明度。执行測试例如以下:


    接着,实现点击炮台加入英雄,先看看英雄

    <span style="font-size:14px;">class Hero : public Entity{
    public:
    	Hero(); 
    	~Hero();
    
    	static Hero* createFromCsvFileByID(int heroID);
    	bool initFromCsvFileByID(int heroID);
    
    };</span>
    这里是依据ID来加入,也就是说有不同种类的英雄。可是本游戏仅仅有一种---这里理解了也能够自己扩展

    <span style="font-size:14px;">Hero::Hero(){
    }
    Hero::~Hero(){
    }
    
    Hero* Hero::createFromCsvFileByID(int heroID){
    	Hero* hero = new Hero();
    	if(hero && hero->initFromCsvFileByID(heroID)){
    		hero->autorelease();
    	}
    	else{
    		CC_SAFE_DELETE(hero);
    	}
    	return hero;
    }
    
    bool Hero::initFromCsvFileByID(int heroID){
    	Sprite* sprite = Sprite::create(__String::createWithFormat("sprite/hero/hero_%d.png",heroID)->getCString());
    	bindSprite(sprite);
    
    	return true;
    }</span>
    那么我们理解加入英雄的过程:点击随意炮台,然后加入。可是,我们须要解决点击了那个炮台?

    HeroManager里加入函数:

    <span style="font-size:14px;">TowerBorder* findClickTowerBorder(Point pos){
    	TowerBorder* tBorder = NULL;
    	for(auto ref : m_towerBorderList){
    		tBorder = dynamic_cast<TowerBorder*>(ref);
    
    		if(tBorder){
    			if(tBorder->isClickMe(pos)){
    				return tBorder;
    			}
    		}
    	}
    	return NULL;
    }</span>
    同一时候,一个炮台仅仅有一个英雄,那么TowerBorder里面加入:

    <span style="font-size:14px;">Hero* _hero;
    TowerBorder::TowerBorder(){
    	_hero = NULL;
    }
    TowerBorder::~TowerBorder(){
    	CC_SAFE_RELEASE(_hero);
    }
    
    Hero* getHero(){ return _hero;};
    void bindHero(Hero* hero){ _hero = hero; };</span>
    那么,在管理器的触摸事件的end函数中:

    <span style="font-size:14px;">bool HeroManager::initWithLevel(int curLevel){
    	/*****************省略***************/
    	listener->onTouchEnded = [=](Touch* touch,Event* event){
    		/*****************省略**************/
    		TowerBorder* clickBorder = findClickTowerBorder(pos);
    
    		if(clickBorder == NULL){
    			return ;
    		}
    		if(clickBorder->getHero() == NULL){
    			Hero* hero = Hero::createFromCsvFileByID(1);
    			hero->setPosition(clickBorder->getPosition());
    			this->addChild(hero);
    			clickBorder->bindHero(hero);
    		}
    	};
           /*************省略*************************************/
    }</span>
    那么測试,点击炮台加入英雄,效果例如以下:



    三:下节预览

    看看Csv中的英雄属性怎样加到英雄身上---读取Csv&解析Csv文件,给英雄加入很多其它操作,让它升级,不想要了把它从炮台删除


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

    四:源代码&资源

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

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

  • 相关阅读:
    ffmpeg一些filter使用方法、以及一些功能命令
    Hibernate调试——定位查询源头
    emmet语法
    [心得]传统IT转互联网面试经验分享
    Java中的集合类型的继承关系图
    Java的IO操作中有面向字节(Byte)和面向字符(Character)两种方式
    oracle求时间差的常用函数
    jdbc读取新插入Oracle数据库Sequence值的5种方法
    Xpath语法格式整理
    Oracle中 Instr 这个函数
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4095912.html
Copyright © 2011-2022 走看看