Previous: http://www.cocoachina.com/bbs/read.php?tid=203510
- Rotation
旋转
In the Tower.h:
在Tower.h里面:
#pragma once
#include "cocos2d.h"
#include "Creep.h"
class Tower: public Sprite
{
public:
……
Creep* getClosestTarget();
……
};
```
In tower.cpp:
在tower.cpp里面:
Creep* Tower::getClosestTarget()
{
Creep *closestCreep = NULL;
double maxDistant = 99999; // It should be bigger than the range.
DataModel *m = DataModel::getModel();
for each(Sprite *target in m->targets)
// for(Vector::iterator i = m->targets.begin(); i < m->targets.end(); ++i) // Use these code if your VC doesn’t support C++11.
{
// Sprite *target = *i; // Use these code if your VC doesn’t support C++11.
Creep *creep = (Creep *)target;
double curDistance = ccpDistance(this->getPosition(), creep->getPosition());
if (curDistance < maxDistant) {
closestCreep = creep;
maxDistant = curDistance;
}
}
if (maxDistant < this->range)
return closestCreep;
return NULL;
}
```
把这些代码加进‘void MachineGunTower::towerLogic(float dt)’:
void MachineGunTower::towerLogic(float dt) {
this->target = this->getClosestTarget();
if(this->target != NULL)
{
Point shootVector = this->target->getPosition() - this->getPosition();
float shootAngle = ccpToAngle(shootVector);
float cocosAngle = CC_RADIANS_TO_DEGREES(-1 * shootAngle);
float rotateSpeed = 0.5 / M_PI;
float rotateDuration = fabs(shootAngle * rotateSpeed);
this->runAction(Sequence::create(RotateTo::create(rotateDuration, cocosAngle), NULL));
}
}
```
8. Ammo
是的。没错。现在是时间装填子弹了。这里或许会是最为有趣和激动的事情了。在完成这个教程后,我希望你知道如何去制作不同类型的防御塔,就像我们当时创建不同的敌人那样。并且对体力、射速、机动性和伤害值设定不同的属性。
首先,我们要做的事创建子弹——我们的类‘Projectile’。创建另一对文档——Projectile.h和Projectile.cpp。
In the DataModel.h:
在DataModel里面:
#include "Projectile.h"
```
和
Vector projectiles;
```
你知道应该要把他们放置在哪里。
In the Projectile.h:
#pragma once
#include "cocos2d.h"
USING_NS_CC;
class Projectile: public Sprite
{
public:
static Projectile* projectile();
};
```
In the Projectile.cpp:
#include "Projectile.h"
Projectile* Projectile::projectile()
{
Projectile* projectile = (Projectile*)Sprite::create("Projectile.png");
if (projectile != NULL)
{
return projectile;
} else {
return NULL;
}
}
```
现在我们添加一些新方法进“void TutorialScene::update(float dt)”。(这个方法名我们已经添加进了TutorialScene.cpp里面。)
void TutorialScene::update(float dt) {
DataModel *m = DataModel::getModel();
Vector projectilesToDelete;
for each(Projectile *projectile in m->projectiles)
// for (int i = 0; i < m->projectiles.size(); i++) // Use these code if your VC doesn’t support C++11.
{
// Projectile* projectile = (Projectile*)(m->projectiles.at(i)); // Use these code if your VC doesn’t support C++11.
Rect projectileRect = Rect(projectile->getPositionX() - (projectile->getContentSize().width / 2),
projectile->getPositionY() - (projectile->getContentSize().height / 2),
projectile->getContentSize().width,
projectile->getContentSize().height);
Vector targetsToDelete;
for each(Creep *target in m->targets)
// for (int i = 0; i < m->targets.size(); i++) // Use these code if your VC doesn’t support C++11.
{
// Creep* target = (Creep*)(m->targets.at(i)); // Use these code if your VC doesn’t support C++11.
Rect targetRect = Rect(target->getPositionX() - (target->sprite->getContentSize().width / 2),
target->getPositionY() - (target->sprite->getContentSize().height / 2),
target->sprite->getContentSize().width,
target->sprite->getContentSize().height);
if (projectileRect.intersectsRect(targetRect))
{
projectilesToDelete.pushBack(projectile);
Creep *creep = target;
creep->curHp -= 1;
if (creep->curHp <= 0)
{
targetsToDelete.pushBack(creep);
}
break;
}
}
//for each(Creep *target in targetsToDelete)
for (int i = 0; i < targetsToDelete.size(); i++)
{
Creep* target = (Creep*)(targetsToDelete.at(i));
m->targets.eraseObject(target);
this->removeChild(target, true);
}
}
for each(Projectile *projectile in projectilesToDelete)
// for (int i =0; i < projectilesToDelete.size(); i++) // Use these code if your VC doesn’t support C++11.
{
// Projectile* projectile = (Projectile*)(projectilesToDelete.at(i)); // Use these code if your VC doesn’t support C++11.
m->projectiles.eraseObject(projectile);
this->removeChild(projectile,true);
}
}
```
这里,我们遍历所有的投射物。对每一个投射物我们遍历所有的敌人。并且决定子弹是否和目标重叠。如果结果为真,敌人的体力将会减1,撞击到敌人的子弹将会被放入数组。一旦敌人的体力降为0,我们就将敌人添加进另一个用来删除的数组里。
最后,回到类“Tower”里面,让我们看看开火的机制。
别忘了添加这些代码到Tower.h里面:
#include "Projectile.h"
void finishFiring();
void creepMoveFinished(Node* sender);
Projectile* nextProjectile;
```
在“void MachineGunTower::towerLogic(float dt)”里面:
this->runAction(Sequence::create(RotateTo::create(rotateDuration, cocosAngle), CallFunc::create(this, callfunc_selector(MachineGunTower::finishFiring)), NULL)); // Delete the old one.删掉原本旧的那行代码
```
Then:
void MachineGunTower::finishFiring()
{
DataModel *m = DataModel::getModel();
if (this->target != NULL && this->target->curHp > 0 && this->target->curHp < 100)
{
this->nextProjectile = Projectile::projectile();
this->nextProjectile->setPosition(this->getPosition());
this->getParent()->addChild(this->nextProjectile, 1);
m->projectiles.pushBack(this->nextProjectile);
float delta = 1.0f;
Point shootVector = -(this->target->getPosition() - this->getPosition());
Point normalizedShootVector = ccpNormalize(shootVector);
Point overshotVector = normalizedShootVector * 320;
Point offscreenPoint = (this->getPosition() - overshotVector);
this->nextProjectile->runAction(Sequence::create(MoveTo::create(delta, offscreenPoint), CallFuncN::create(this, callfuncN_selector(MachineGunTower::creepMoveFinished)), NULL));
this->nextProjectile->setTag(2);
this->nextProjectile = NULL;
}
}
void MachineGunTower::creepMoveFinished(Node* sender)
{
DataModel * m = DataModel::getModel();
Sprite *sprite = (Sprite *)sender;
this->getParent()->removeChild(sprite,true);
m->projectiles.eraseObject((Projectile*)sprite);
}
```
一旦你的他面对着敌人,它就会开始射击。这个功能是用来专门制造子弹——“projectile”的。正如你所看到的。在转向正确的方向后,投射物会“runAction”和“MoveTo”到指定的位置。并且我们也设置了射程的最大值。一旦子弹超出了射程,它们就都会被消除。
现在,好好享受吧。
完~
完整代码在6L


