实现子弹或敌人跟踪

2018-09-24  本文已影响0人  与时间赛跑_

hello,一些游戏中经常有一些自动跟踪的子弹,一旦发射,就一定可以命中到玩家,同时玩家也是不断运动的,看看效果吧,这里我随便找了一张小图当作子弹或者敌人。

比如王者荣耀的水晶的攻击玩家。

解决这个问题,首先先来分析一下怎么去设计。

首先玩家是不断运动的,子弹在运动的时候需要改变自己的运动轨迹。

子弹在发射的时候总是跟踪着玩家,而且一定会命中

小code到了这一篇,差不多讲完了一个飞行射击游戏的一些常用功能。

这里需要分析4中情况。

1

2(原来可以用箭头和形状啊)

3

4

在每一种情况子弹/敌人的步进方向都不一样。

步进,可以简单理解为各在x , y轴方向上各“走”多少像素。

这里画一张图,方便理解

这里我们只要确定好子弹的步进长度(可以理解为速度)因为它直观的表现出速度,哈哈

然后,剩下的就交给3角函数吧

但是在此之前,还要获取子弹/敌人与我们玩家的之间的角度

看一张图

分别求出A,B,C的坐标

c点的坐标也很容易算出来。对于第1种情况(1图)计算如下

然后可以写代码算出角度了

我们应该在设计这种有跟踪行为的子弹的时候就设计好类

class Emeny{

public:

 static Emeny*create(int type);//创建方法,为静态

 virtual bool init(int type);//初始化方法

 void move(Point pos);//移动方法。通过传递进来玩家的坐标对玩家相对于子弹的方向做出判断

 Point getPos(Point pos);//返回x和y轴的步进

 float  getAngle(Point pos1,Point pos2,Point pos3); //得到玩家相对于子弹的角度

private:

float speed;//子弹步进

}

实现文件

Emeny*Emeny::create(int type){

//这是一种防御的写法,一起的文已经有写过了,这里偷懒就不在写了

 auto emeny=new Emeny();

 if(emeny&&emeny->init(type)){ 

        emeny->autorelease();

 return emeny;

    }else{

     delete emeny;

 return NULL;

    }

}

bool Emeny::init(int type){

 speed=1;//初始化步进长度

 if(type==1){

//判断参数实现子弹类型

 this->initWithFile("blueemeny.png");

 setHp(10);

    }

 if(type==2){

 this->initWithFile("abouton.png");

    }

//把它放在一个位置,这里我直接放在随便一个位置

 this->setPosition(Point(240,160));

 this->setAnchorPoint(Point(0.5,0.5));//设置锚点

 return true;

}

void Emeny::move(Point pos){

 this->setPosition(this->getPosition()+getPos(pos));//这里是通过把传递进来的pos即是玩家的坐标,把它交给getPos()函数去获得各坐标轴的步进长度。

    //子弹或者敌人的运动方法

}

注意:因为控制篇幅,这里没有考虑子弹和玩家处于同一直线的原因,大家可以翻阅上次的360度子弹发射,这篇文章,其实是一样的。

Point Emeny::getPos(Point pos){

 Point nextPos;//判断敌人或者子弹相对于玩家处于那个位置

这里的情况是如下图(其他的也就是上面所说的4种情况之一,这里是通过他们各自所处的x,y轴的位置来判断他们的相对位置)

 if(this->getPositionX()>pos.x&&this->getPositionY()>pos.y){

 float rad=getAngle(pos,this->getPosition(),Point(this->getPositionX(),this->getPositionY()-(this->getPositionY()-pos.y)));// 把A,B,C三个点传递给getAngle()函数

 auto p=CC_DEGREES_TO_RADIANS(rad);

        //把角度转化成幅度

        nextPos=Point(-speed*cos(p),-speed*sin(p));//这种情况的x轴步进为-speed*cos(p),y轴的步进为-speed*sin(p),下面的情况也是差不多的

    }

 if(this->getPositionX()<pos.x&&this->getPositionY()<pos.y){

 float rad=getAngle(pos,this->getPosition(),Point(this->getPositionX(),this->getPositionY()-(this->getPositionY()-pos.y)));

 auto p=CC_DEGREES_TO_RADIANS(rad);

nextPos=Point(speed*cos(p),speed*sin(p));

    }

 if(this->getPositionX()<pos.x&&this->getPositionY()>pos.y){

 float rad=getAngle(pos,this->getPosition(),Point(this->getPositionX(),this->getPositionY()-(this->getPositionY()-pos.y)));

 auto p=CC_DEGREES_TO_RADIANS(rad);

        nextPos=Point(speed*cos(p),-speed*sin(p));

    }

 if(this->getPositionX()>pos.x&&this->getPositionY()<pos.y){

 float rad=getAngle(pos,this->getPosition(),Point(this->getPositionX(),this->getPositionY()-(this->getPositionY()-pos.y)));

 auto p=CC_DEGREES_TO_RADIANS(rad);

        nextPos=Point(-speed*cos(p),speed*sin(p));

    }

 return nextPos;

}

/下面的代码根上次那个《实现360度摇杆。。》是一样的,这里就再重复了

float Emeny::getAngle(Point pos1,Point pos2,Point pos3){

 float dx1,dx2,dy1,dy2;

 float angle;

    dx1=pos2.x-pos1.x;

    dx2=pos3.x-pos1.x;

    dy1=pos2.y-pos1.y;

    dy2=pos3.y-pos1.y;

 float c= sqrt(dx1*dx1+dy1*dy1)*sqrt(dx2*dx2+dy2*dy2);

 if(c==0){

     return -1;

    }

    angle=acos((dx1*dx2+dy1*dy2)/c)/(3.1415)*180;

 return angle;

}

到这里已经实现了所有的方法,现在就调用它吧

 auto  em1=Emeny::create(1);//创建一个子弹

然后用一个时间调度器。在每一帧都执行它 的move方法

这里假设玩家为_player

emeny->move(_player->getPosition());通过这样已经写好了全部。

其实这个算法不够高效,也存在一些精确问题,下次会有更加完善的方法分享给大家

想制作属于自己的网页小导游吗?也可以说是萌宠,一定要持续关注哦

(例子)

我们会给她加入导航和问好等一系列语言和一些其他帮助功能,假如在参加网页设计赛事的时候用上,说不定会成为加分项哦

拜拜~

上一篇下一篇

猜你喜欢

热点阅读