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文件,给英雄添加更多操作,让它升级,不想要了把它从炮台删除


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

四:源码&资源

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

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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值