獎勵小功能

首先當敵人被擊毀時根據隨機數判斷是否出現一個獎勵。以下代碼簡單,就不做多解釋

void Enemy::doHurt() {
	float percentage = this->_hp / this->_sourceHp;
	if(Config::sharedConfig()->getIsOpenSlot()) {
		this->_topSlot->setScaleY(percentage);
	}
	if(this->_hp <= 0) {
		...
<span style="white-space:pre">		</span>
		float appearRate = CCRANDOM_0_1();
		Award* award = NULL;
		if(appearRate < 0.2f) {
			if(GameLayer::shareGameLayer()->getIsAppearShader() == false && this->_id != 3 && 
				Config::sharedConfig()->getIsTsuihikidanMode() == false) {
					GameLayer::shareGameLayer()->setIsAppearShader(true);
					award = Award::getOrCreate(SHADER);
			}
		}else {
			appearRate = CCRANDOM_0_1();
			if(0.2f > appearRate && appearRate < 0.45f) {
				if(GameLayer::shareGameLayer()->getIsAppearShield() == false && this->_id != 3) {
					GameLayer::shareGameLayer()->setIsAppearShield(true);
					award = Award::getOrCreate(PROTECTED_BODY);
				}
			} 
		}
		if(award && award != NULL) {
			award->setVisible(true);
			award->setPosition(this->getPosition());
			award->startAction();
			award->scheduleUpdate();
		}

	}
}
獎勵現在只做了三個,分別是:護盾、增加恢復值、敵人血量減半。用三個枚舉值記錄:

typedef enum {
	PROTECTED_BODY,
	ADD_RESUME_VALUE,
	SHADER
}AWARD_TYPE;
最終出現的獎勵效果是由三個精靈組成:


其中,小光圈繞着圓形的環做圓周運動,中間的主體精靈做翻轉動作,當碰到屏幕的任何一邊後會根據其碰撞的角度做90度的反彈,當碰到主角後觸發獎勵功能。定義完了顯示效果後便是實現它。

class Award : public CCNode
{
public:
	Award();//構造
	bool init();//初始化
	virtual void execute() = 0;//獎勵的實現功能
	void startAction();//開始動作
	void doAction();//執行動作
	void endAction();//結束動作
	CCRect collideRect();//碰撞判斷矩形
	static void preSet();//重置
	static Award* getOrCreate(AWARD_TYPE awardType);//根據不同的獎勵類別獲取或創建不同的獎勵
	CC_SYNTHESIZE_READONLY(AWARD_TYPE, _awardType, AwardType);//獎勵類別
	
	CC_SYNTHESIZE_READONLY(float, _speed, Speed);//速度
	CC_SYNTHESIZE(int, _direction, Direction);//方向
	CC_SYNTHESIZE(bool, _active, Active);//激活


	void update(float dt);//更新
protected:
	CCSprite* _circle;//圓環
	CCSprite* _body;//獎勵主體
	CCSprite* _halo;//小光圈
private:
	bool _leftCollision;//是否碰到左邊的屏幕
	bool _rightCollision;//是否碰到右邊的屏幕
	bool _topCollision;//是否碰到上邊的屏幕
	bool _bottomCollision;//是否碰到下邊的屏幕

};
其中獎勵的基類中有個虛函數execute,這個函數是真正的實現獎勵的功能的真正觸發點,由各自的子類實現各自的獎勵功能(這裏採用狀態機的實現方式,而不用變量_awardType去做switch或if的判斷,這樣可以讓程序的可維護性和代碼的可讀性更高)。除了觸發功能點外其餘的動作都交由這個基類來實現(畢竟對於子類來說他們就是實現的功能不一樣而已,其餘的像碰壁檢測等動作都是一樣的)。

實現類:

Award::Award() {//初始化成員變量
	_leftCollision = false;
	_rightCollision = false;
	_topCollision = false;
	_bottomCollision = false;

	_circle = NULL;
	_body = NULL;
	_halo = NULL;
}
bool Award::init() {//初始化圓環和小光圈(主體由子類去完成)
	_circle = CCSprite::createWithSpriteFrameName("circle.png");
	_halo = CCSprite::createWithSpriteFrameName("halo.png");
	this->addChild(_circle);
	this->addChild(_halo);
	_halo->setPosition(ccp(_circle->getContentSize().width / 2, 0));

	return true;
}
void Award::preSet() {
	for(unsigned int i = 0; i < 3; i++) {//分別預創建三個獎勵
		ProtectedBodyAward::create();
		AddResumeAward::create();
		ShaderAward::create();
	}
}
void Award::startAction() {//開始動作
	if(_body) {
		//主體精靈做翻轉動作,可以由引擎自帶的CCOrbitCamera類來實現
		CCActionInterval* orbit = CCOrbitCamera::create(1, 1, 0, 0, 180, 180, 0);
		_body->runAction(CCRepeatForever::create(CCSequence::create(orbit, orbit->reverse(), NULL)));
	}
	//小光圈做圓周運動,有自定義的CircleAction類來實現
	_halo->runAction(CCRepeatForever::create(CircleAction::create(10, _circle->getPosition(), _circle->getContentSize().width / 2)));
}
void Award::endAction() {//結束動作
	this->stopAllActions();
}
void Award::doAction() {//當主角碰到獎勵時觸發該方法
	this->setActive(false);//設置不激活
	this->unscheduleUpdate();//停止調度更新
	this->endAction();//停止所有動作
	this->execute(); //觸發獎勵功能
	this->setVisible(false);//設置不可見
}
void Award::update(float dt) {
	CCPoint p = this->getPosition();
	CCSize size = _circle->getContentSize();
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();
	if(this->_direction < 1) {
		this->_direction = (int)(CCRANDOM_0_1() * 360.0f);
	}
	//碰壁檢測
	if(p.x - size.width / 2 <= 10 || p.y - size.height / 2 <= 10 || p.x + size.width / 2 >= ScreenWidth - 10 || p.y + size.height / 2 >= ScreenHeight - 10) {
		if(p.x - size.width / 2 <= 10 && !_leftCollision) {//碰到左壁
			if(this->_direction > 180) {
				this->_direction = this->_direction + 90;
			}else {
				this->_direction = this->_direction - 90;
			}
			_leftCollision = true;
			_rightCollision = false;
			_topCollision = false;
			_bottomCollision = false;
		}else if(p.y - size.height / 2 <= 10 && !_bottomCollision) {//碰到下壁
			if(this->_direction > 270) {
				this->_direction = this->_direction + 90;
			}else {
				this->_direction = this->_direction - 90;
			}
			_leftCollision = false;
			_rightCollision = false;
			_topCollision = false;
			_bottomCollision = true;
		}else if(p.x + size.width / 2 >= winSize.width - 10 && !_rightCollision) {//碰到右壁
			if(this->_direction < 180) {
				this->_direction = this->_direction + 90;
			}else {
				this->_direction = this->_direction - 90;
			}
			_leftCollision = false;
			_rightCollision = true;
			_topCollision = false;
			_bottomCollision = false;
		}else if(p.y + size.height / 2 >= ScreenHeight - 10 && !_topCollision){//碰到上壁
			if(this->_direction < 90) {
				this->_direction = this->_direction - 90;
			}else {
				this->_direction = this->_direction + 90;
			}
			_leftCollision = false;
			_rightCollision = false;
			_topCollision = true;
			_bottomCollision = false;
		}
		//計算最終的反彈角度
		if(this->_direction > 360) {
			this->_direction = this->_direction % 360;
		}else if(this->_direction < 0) {
			this->_direction = 360 + this->_direction;
		}
		float r = CC_DEGREES_TO_RADIANS(this->_direction);
		float c = cosf(r);
		float s = sinf(r);

		p = this->getPosition();
		this->setPosition(ccp(p.x + this->_speed * dt * c, p.y + this->_speed * dt *  s));
	}else {
		float r = CC_DEGREES_TO_RADIANS(this->_direction);
		float c = cosf(r);
		float s = sinf(r);
		this->setPosition(ccp(p.x + this->_speed * dt * c, p.y + this->_speed * dt *  s));
	}
}
Award* Award::getOrCreate(AWARD_TYPE awardType) {
	CCArray* array = Container::sharedContainer()->getAwards();
	CCObject* iterator;
	Award* award = NULL;
	CCARRAY_FOREACH(array, iterator) {
		award = (Award*)(iterator);
		if(award && award->getAwardType() == awardType && award->getActive() == false) {
			award->setActive(true);
			//設置初始化角度
			int direction = (int)(CCRANDOM_0_1() * 360);
			if(direction < 90) {
				direction = direction + 90;
			}else if(direction > 270) {
				direction = direction - 90;
			}
			award->setDirection(direction);
			return award;
		}
	}
	if(awardType == PROTECTED_BODY) {
		award = ProtectedBodyAward::create();
	}else if(awardType == ADD_RESUME_VALUE) {
		award = AddResumeAward::create();
	}else if(awardType == SHADER) {
		award = ShaderAward::create();
	}
	return award;
}
CCRect Award::collideRect() {//構造碰撞體
	CCPoint p = this->getPosition();
	CCSize size = _circle->getContentSize();
	return CCRectMake(p.x - size.width / 2, p.y - size.height / 2, size.width, size.height);
}


實現了基類後便要實現三個不同獎勵功能的子類:

1)護盾:

class ProtectedBodyAward : public Award {
public:
	static ProtectedBodyAward* create();
	bool init();
	void execute();
};
ProtectedBodyAward* ProtectedBodyAward::create() {
	ProtectedBodyAward* protectedBodyAward = new ProtectedBodyAward();
	protectedBodyAward->init();
	Container::sharedContainer()->getAwards()->addObject(protectedBodyAward);
	protectedBodyAward->release();
	protectedBodyAward->setVisible(false);
	GameLayer::shareGameLayer()->addChild(protectedBodyAward);
	return protectedBodyAward;
}
bool ProtectedBodyAward::init() {
	bool result = false;
	if(Award::init()) {
		this->_active = true;
		this->_awardType = PROTECTED_BODY;//獎勵類別
		this->_speed = 150;
		int direction = (int)(CCRANDOM_0_1() * 360);
		if(direction < 90) {
			direction = direction + 90;
		}else if(direction > 270) {
			direction = direction - 90;
		}
		this->_direction = direction;
		_body = CCSprite::createWithSpriteFrameName(shield_png);//主體精靈
		this->addChild(_body);
	}
	return result;
}
void ProtectedBodyAward::execute() {
	GameLayer::shareGameLayer()->getShip()->getProtectBody()->protectStart();//觸發護盾
}
其餘的兩個都是一樣的,都是在execute中實現不同的功能,隨後在跟主角碰撞時觸發下doAction方法即可。

//獎勵判斷
	CCArray* awards = Container::sharedContainer()->getAwards();
	Award* award = NULL;
	for (unsigned int j = 0; j < awards->count(); j++) {
		award = (Award*)awards->objectAtIndex(j);
		if(award->getActive()) {
			if(this->_ship->boundingBox().intersectsRect(award->collideRect())) {
				if(this->_isAppearShield && award->getAwardType() == PROTECTED_BODY) {
					if(this->_ship->getIsProtected() == false && this->_ship->getProtectBody()->getActive() == false) {
						award->doAction();
					}
				}else if(this->_isAppearShader && award->getAwardType() == SHADER) {
					award->doAction();
					this->scheduleOnce(schedule_selector(GameLayer::endShader), STATIC_DATA_FLOAT("shader_time"));
				}else if(award->getAwardType() == ADD_RESUME_VALUE){
					award->doAction();
				}
			}
		}
	}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章