该文是接续cocos2d-x.org网站上的 Tutorials:How to make a cocos2d-x simple game。
基本照搬子山龙王翻译的文章(译)如何使用cocos2d开发一个简单的iphone游戏:旋转炮塔。(第二部分),把其中Object-c代码修改为c++代码。
1.准备工作:
阅读cocos2d-x.org网站上的Tutorials,生成的代码可在此下载
接下来,下载新的 player sprite 和
projectile sprite图片,然后把它们加到工程Resource文件夹里面。
然后,修改代码,把每个sprite添加进去。
HelloWorldScene.cpp的init方法中:
CCSprite *player = CCSprite::spriteWithFile("Player2.png");
HelloWorldScene.cpp的ccTouchesEnded方法中:
CCSprite *projectile = CCSprite::spriteWithFile("Projectile2.png");
注意,这一次我们并没有指定精灵的宽度和高度,而是让cocos2d替我们来处理这些事情。
编译并运行你的工程,如果一切顺利的话,你将会看到一个炮塔正在发射子弹。然后,这并不是很好,因为炮塔在射击的时候并没有面朝那个方向。因此,接下来让我们来解决这个问题。
2.旋转并射击
在我们旋转炮塔之前,首先,我们需要保存Player精灵的引用,以便后面旋转它的时候使用。打开HelloWorldScene.h,然后修改类文件并包含以下成员变量:
CCSprite *_player;
然后修改init方法中的代码,把Player对象加入到层(layer)中。代码如下:
//the new add player code
_player = CCSprite::spriteWithFile("Player2.png");
_player->setPosition( ccp(_player->getContentSize().width/2, winSize.height/2) );
this->addChild(_player);
//注释掉原来的添加player代码
//CCSprite *player = CCSprite::spriteWithFile("Player2.png");
//player->setPosition( ccp(player->getContentSize().width/2, winSize.height/2) );
//this->addChild(player);
好了,现在让我们取出player对象的引用并且旋转它吧!为了旋转它,我们首先需要计算出旋转的角度。为了解决这个问题,想想我们在高中时候学过的三角代数吧。还记得sin cos tan吗?为了便于
理解,下面使用一张图来解释一下:tan = 对面/邻边。
如上所示,我们想要旋转的角度是arctangent(angle),即对offY/offX求arctangent运算。
然而,这里还有两件事情,我们需要放在心上。首先,当我们计算actangent(offY/offX)的时候,这个结果是弧度,但是cocos2d使用的却是角度。还好,cocosd2d提供了一个非常方便的宏,可以使得角度和弧度之间方便转化。
第二点,我们假定上面的图中angle的偏转是正20度,但是,cocos2d里面顺时针方向为正(而不是上图所示的逆时针为正)。让我们看到下面这个图:
因此,为了得到正确的方向,我们把运算结果乘以一个-1就可以了。比如,如果我们把上面那幅图片里的角度乘以-1的话,我们就得够得到-20度,这个角度其实就是逆时针方向的20度。(感觉老外说话好啰嗦啊,聪明的读者恐怕早就明白了吧!:)
好了,讲得够多了!让我们来写一点代码吧。在ccTouchesEnded里面加入以下代码,添加位置在你的projectile->runAction之前。
//Determine angle to face
float angleRadians = atanf((float)offRealY/(float)offRealX);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle =-1* angleDegrees;
_player->setRotation(cocosAngle);
编译并运行工程,现在我们的炮塔在射击的时候可以改变方向了。
3.旋转之后再射击
目前来说还不错,但是有一点点怪。因为,这个炮塔好像突然一下跳到一个方向射击,有点不够流畅。我们可以解决这个问题,但是在这之前,我们需要重构一下代码。
首先,打开HelloWorldScene.h,然后在你的类里添加如下成员变量:
CCSprite *_nextProjectile;
然后,修改你的ccTouchesEnded方法,并且添加一个新的方法,叫做finishShoot,如下所示:
if (_nextProjectile !=NULL){
return;
}
// Choose one of the touches to work with
CCTouch* touch = (CCTouch*)(touches->anyObject());
CCPoint location = touch->locationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
if(location.x <= 20) return;
// Set up initial location of projectile
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
_nextProjectile = CCSprite::spriteWithFile("Projectile2.png");
_nextProjectile->retain();
_nextProjectile->setPosition(ccp(20,winSize.height/2));
// Determinie offset of location to projectile
int offX = location.x - _nextProjectile->getPosition().x;
int offY = location.y - _nextProjectile->getPosition().y;
// Bail out if we are shooting down or backwards
if(offX<0)
{
return;
}
// Ok to add now - we've double checked position
//this->addChild(_nextProjectile);
// Determine where we wish to shoot the projectile to
int realX = winSize.width + (_nextProjectile->getContentSize().width/2);
float ratio = (float)offY / (float)offX;
int realY = (realX * ratio) + _nextProjectile->getPosition().y;
CCPoint realDest = ccp(realX, realY);
// Determine the length of how far we're shooting
int offRealX = realX - _nextProjectile->getPosition().x;
int offRealY = realY - _nextProjectile->getPosition().y;
float length = sqrtf((offRealX * offRealX) + (offRealY*offRealY));
float velocity = 480/1; // 480pixels/1sec
float realMoveDuration = length/velocity;
//Determine angle to face
float angleRadians = atanf((float)offRealY/(float)offRealX);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle =-1* angleDegrees;
float rotateSpeed =0.5/ M_PI; // Would take 0.5 seconds to rotate 0.5 radians, or half a circle
float rotateDuration = fabs(angleRadians * rotateSpeed);
_player->runAction(CCSequence::actions(CCRotateTo::actionWithDuration((ccTime)rotateDuration,cocosAngle),
CCCallFunc::actionWithTarget(this,callfunc_selector(HelloWorld::finishShoot)),
NULL
));
//_player->setRotation(cocosAngle);
_nextProjectile->runAction( CCSequence::actions(CCMoveTo::actionWithDuration(realMoveDuration, realDest),
CCCallFuncN::actionWithTarget(this, callfuncN_selector(HelloWorld::spriteMoveFinished)),
NULL) );
// Add to projectiles array
_nextProjectile->setTag(2);
//_projectiles->addObject(_nextProjectile);
void HelloWorld::finishShoot() {
// Ok to add now - we've finished rotation!
this->addChild(_nextProjectile);
_projectiles->addObject(_nextProjectile);
// Release
_nextProjectile->release();
_nextProjectile = NULL;
}
这看上去好像有许多代码,但是,实际上我们改动的并不多--大部分只是做一些小小的重构。下面是我们所修改的内容的一个列表:
1.在函数开头检查nextProjectile的值是否为nil。这意味着我们当前的touch事件正发生在射击过程之中。也就是说,炮塔已经发射出一个子弹了。
2.之前,我们使用一个projectile的局部变量,并把它加入到了当前的场景中。在这个
版本中,我们增加了一个nextProjectile的成员变量,但是并没有马上加到当前场景中。因为后要还要使用。
3.定义炮塔旋转的角度,半秒钟旋转半个圆。记住,一个圆有2 PI个弧度。
4.计算旋转特定的角度需要多长时间,这里是拿弧度乘以速度。
5.接下来,我们使用一个sequence action来旋转我们的炮塔。最后,调用一个函数,把projectile加入到当前场景当中去。
好,大功告成!编译并运行工程,现在炮塔可以旋转,并且很流畅地射击了!
全部代码下载:simpleGame2.zip
- simpleGame.zip (171.9 KB)
- 下载次数: 2
- simpleGame2.zip (172.3 KB)
- 下载次数: 0