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() 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() 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() 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());通过这样已经写好了全部。 其实这个算法不够高效,也存在一些精确问题,下次会有更加完善的方法分享给大家 想制作属于自己的网页小导游吗?也可以说是萌宠,一定要持续关注哦 (例子) 我们会给她加入导航和问好等一系列语言和一些其他帮助功能,假如在参加网页设计赛事的时候用上,说不定会成为加分项哦 拜拜~