cocos2d-x 炮台旋转和子弹移动的一点小技巧

来源:互联网 发布:深圳市软件著作权补贴 编辑:程序博客网 时间:2024/04/28 02:56

一般在游戏中我们避免不了处理旋转或者子弹发射什么的,就比如塔防游戏来说吧,我们需要判断敌人往哪里走,炮塔就往哪里转,转完然后朝着一个方向发射子弹是一个方向而不是朝一个点,就比如保卫萝卜,子弹穿过怪物继续朝那个方向飞行,直到飞往屏幕外才移除),下面来简单分析一下实现的过程,需要涉及到一点点平面向量的数学知识。

(注意匀速)

1. 旋转 : 朝着某个点的方向匀速旋转

2.发射:让子弹朝着某个点的方向匀速移动


我们来分步骤实现,先实现旋转功能:


嗯,现在假设平面中有点A和点B,A是炮塔,B是敌人,现在我们需要让炮塔A的方向朝着敌人B旋转,因为炮塔放置的时候方向向上,所以我们要旋转的角度为α,如图


现在首先,我们创建敌人和塔

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //敌人  
  2. auto enemy = Sprite::create("enemy.png");  
  3. enemy->setPostion(Point(100,200));  
  4. this->addChild(enemy);  
  5.   
  6. //塔  
  7. auto tower = Sprite::create("tower.png");  
  8. tower->setPostion(Point(200,100));  
  9. this->addChild(tower);  

然后我们让塔旋转瞄准敌人,只是为了能射它一脸(呵呵?)

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //让塔的方向旋转对准敌人  
  2.   
  3. //射击方向向量  
  4. Point shootVector = enemy->getPosition() - tower->getPosition();  
  5. //向量标准化(即向量长度为1)  
  6. Point normalizedVector = ccpNormalize(shootVector) ;  
  7. //算出旋转的弧度  
  8. float radians = atan2(normalizedVector.y, - normalizedVector.x);  
  9. //将弧度转换成角度  
  10. float degree = CC_RADIANS_TO_DEGREES(radians);  
  11.   
  12.   
  13. //匀速旋转需要我们设置一下速度,这里假设旋转速度为 2π (rad/s)  
  14. float rotateSpeed = 2 * M_PI;  
  15. //那么旋转1弧度所用时间为  
  16. float rotate_1rad_time = 1 / rotateSpeed;  
  17. //所以旋转的时长为  
  18. float rotateDuration = fabs(radians * rotate_1rad_time);  
  19.   
  20.   
  21. //最后执行旋转  
  22. _sprite->runAction(RotateTo::create(rotateDuration,degree- 90));  

需要注意一下

(1)假设点A为塔,B为敌。则 向量  shootVector = OB -OA = AB  

(2)atan2(y,x)是就是反正切函数, 算出的是  点(x,y)与x轴正方向的夹角,返回的是角的弧度值

(3)所以degree算出的角度其实是与x轴正方向的夹角

(4)由于炮塔方向向上,所以  【旋转的角度  α 】= degree - 90


如果你想不起来什么是反正切,那没关系,看下面假设和图(再想不起来我只能呵呵了)

假设 tan(α) = y / x , 则有 α = arctan(y / x)


旋转完后接下来我们再实现射击功能:


假设有塔,子弹和敌人,位置如图,我们需要把子弹由位置A沿着AB方向 匀速射到C(C点在屏幕外)



我们先创建敌人,塔和子弹


[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //敌人  
  2. auto enemy = Sprite::create("enemy.png");  
  3. enemy->setPostion(Point(100,200));  
  4. this->addChild(enemy);  
  5.   
  6. //塔  
  7. auto tower = Sprite::create("tower.png");  
  8. tower->setPostion(Point(200,100));  
  9. this->addChild(tower);  
  10.   
  11. //子弹,和塔在一个位置  
  12. auto tower = Sprite::create("bullet.png");  
  13. tower->setPostion(Point(200,100));  
  14. this->addChild(tower);  

然后这次我们真的射它一脸(再次呵呵)


[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //射击方向向量  
  2. Point shootVector = enemy->getPosition() - bullet->getPosition();  
  3. //向量标准化(即向量长度为1)  
  4. Point normalizedVector = ccpNormalize(shootVector);  
  5. //移动长度向量  
  6. Point overShootVector = normalizedVector * 900;  
  7. //超出屏幕的点  
  8. Point offScreenPoint = bullet->getPosition() + overShootVector;  
  9.   
  10. //假设速度为500(pix/s)  
  11. float moveSpeed = 500;  
  12. //移动时间  
  13. float moveDuration = overShootVector / moveSpeed;  
  14.   
  15. //执行设计  
  16. auto move = MoveTo::create(moveDuration,offScreenPoint);  
  17. CallFunc* moveDone = CallFunc::create(CC_CALLBACK_0(shootFinish,this,bullet));  
  18. bullet->runAction(Sequence::create(move,moveDone,NULL));  
射击结束后移除子弹

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //射击结束后移除  
  2. void HelloWorld::shootFinish(Node* pNode){  
  3.     Sprite* bullet = (Sprite*)pNode;  
  4.     if(bullet != NULL)  
  5.         bullet->stopAllActions();  
  6.         this->removeChild(bullet);  
  7. }  

稍稍解释一下 :

(1)shootVector就是向量AB。

(2)overShootVector = (AB向量标准化)× 900 即得到  AC。比如说你设置的分辨率为 800 x 400 ,那么你可以用标准化向量 × 你最大分辨率再大一点,这样子向量就会超出屏幕之外而且长度又固定。

(3)然后根据向量OC = OA + AC ,算出要移动到的点offScreenPoint(即点C)。

(4)设置一下速度,长度一定了,所以时间 = 长度 / 速度 。


=====================================================


其实也没啥东西,纯属小白教程。。


转载请注明出处:http://blog.csdn.net/shun_fzll/article/details/34430045

0 0
原创粉丝点击