您的位置:首页 > 其它

追逐算法之--牛鞭的子弹是怎样练成的(6)--贝塞尔强化

2013-04-13 02:09 204 查看
水一滴一滴的滴在地上,此刻的时间仿佛已经凝固。。。

“一根,两根,三根。。。”今天又整整掉了10根头发。。。一个健康的成年男性的大约有15w根头发,如果我每天掉10根,并以每年10%的通货膨胀率来计算的话,我掉完全部的头发大约需要30年,“什。。什。。。什么,30年。。。我和我们的主程还有30年的差距!不!这他娘的不科学,我们主程今年还不到30。。。他。。他。。他上辈子一定是断了膀子的长臂猿!”

说句实在话,我刚来公司大半个月,最喜欢的就是我们的主程了,几乎什么语言都会,几乎什么都能写,看他的代码就是一种享受,各种高超的设计模式穿插其中,帅的一比啊,他编程的时候都是同时使用三台电脑的,一台写代码,一台进行比对,还有一台用来测试程序,一看就是高帅富。在我写程序的时候,他还时常来主动帮我解决问题,给我提出了很代码设计上的意见,上一次为了锻炼我,还把项目里的一个核心模块交给我来做 ! 年纪轻轻就当上了主程,我以后要是能像他一样,我他妈死也值了!不夸张的说,我人生中第一份工作就遇到个这么牛逼哄哄的主程,真是积了八辈子德了!!

我们主程平时很忙,我很难有机会跟它单独请教,今天晚上主程叫我一起出去吃饭,我那个兴奋啊,终于有机会能向主程请教一点经验了,我小心翼翼的问他“xx哥,你好牛啊,你是怎么学的啊,都聪明绝顶了!”,xx哥笑了笑对我语重心长的说“呵呵,我上个月才剔的头”。“。。。。。。。。”。。。其实吧。。。我们主程也就那样。。

说句实在话,我刚来公司大半个月,最讨厌的就是我们的主程了,几乎什么语言都会,几乎什么都不通,看他的代码就是一种折磨,各种过度设计穿插其中,傻的一比啊,他编程的时候都是同时使用三台电脑的,一台挂qq,一台下载AV,还有一台拿来LOL,一看就是纯屌丝。在我写程序的时候,他还时常来主动过来挑刺,给我提了很多无关紧要的问题,上一次为了自己偷懒,还把项目里的一个垃圾模块交给我来做 ! 都快奔三了才当上主程,我以后要是像他一样我,我他妈就去死!不夸张的说,我人生中第一份工作就遇到个这么傻逼兮兮的主程,真是倒了八辈子霉了!!

今天我们要开始本期的最后一课了,我们要使用贝塞尔曲线,来让我们的子弹更加变态,说起贝塞尔我这个纯文科生表示真的不熟,我只认识一个大哲学家叫胡塞尔的,为此偶特意上网查了一下贝塞尔。

首先说说,贝塞尔曲线是用来干嘛的?贝塞尔目前主要是用在工业设计上,在计算机图形学中也有广泛的使用,它可以方便的来描绘出各种形状的光滑曲线,并且在数学上如果这条曲线的起始点,终点,控制点是确定的,那么这条曲线也必然是确定的唯一一条。

实际上我们经常会接触到贝塞尔曲线,比如说轿车的流线型曲线就是贝塞尔曲线,比如你在ps中使用的钢笔工具,就是典型的贝塞尔曲线。贝塞尔曲线分为二次贝塞尔和三次贝塞尔 ,二次贝塞尔一般用来画一条有任意弧度的曲线,而三次贝塞尔曲线之间的组合则可以画出各种神奇的形状了。

这样的线段如果用向量来描述那么会是非常复杂的。又或者我们希望做一个光滑的s型或者w型轨迹的子弹,那么这个时候,向量就确实无能为力了,而我们使用贝塞尔曲线就可以简单快捷的完成,下面的教程中,我只使用2次贝塞尔曲线做一个有较大弧度的子弹。

那么我们为什么要用贝塞尔来强化子弹呢?

首先来看一下标准的二次贝塞尔曲线的方程

二次标准方程为:


其中的P0点表示曲线起点,P1表示曲线的控制点,P2表示曲线的终点,t表示时间刻度





好下面我们就开始动手吧,首先我们先要写一个贝塞尔曲线类BZCarve,这个类的用法是在创建BZCarve时,我们将我们的飞机坐标作为曲线的起点,将敌机坐标作为终点,然后取这两点间的中点,进行适当的偏移得到一个坐标作为曲线的控制点,然后将这三点作为参数传入构造函数。

package planet;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
public class BZCarve {
//起始点
Point start = new Point (0,0);
//控制点
Point inflect = new Point (0,0);
//目标点
Point target = new Point (0,0);
//路径点列表
List<Point> pointList = new ArrayList<Point>();
public BZCarve(Point startPoint, Point inflectPoint, Point targetPoint){
this.start=startPoint;
this.inflect =inflectPoint;
this.target =targetPoint;
}

//产生贝塞尔坐标
private Point checkBZ(float t){
//贝塞尔曲线公式 (1 - t)^2 P1 + 2 t (1 - t) P2 + t^2 P3(t在0-1范围内)
float rx = (1 - t)*(1 - t)* start.x + 2 *t *(1 - t) *inflect.x + t*t *target.x;
float ry = (1 - t)*(1 - t)* start.y + 2 *t *(1 - t) *inflect.y + t*t *target.y;
return new Point((int)rx,(int)ry);
}

//初始化,并计算所有贝塞尔路径点
public void init(){
float r =0;
//共生成50个路径点,每个路径点的t增加0.08
for (int i = 0 ;i< 50;i++){
int t = i ;
r=r+0.08f;
//将计算出的新路径点,加入到路径列表中
this.pointList.add(this.checkBZ(r));
}
}

public List<Point> getPointList() {
return pointList;
}
}


之后我们在Bullet中添加两个属性

//贝塞尔曲线路径点列表
private List<Point> pointList=null;
//当前应该取得贝塞尔曲线的路径点序号
private int pathIndex =0;
然后我们在BulletType中添加两颗不同向的贝塞尔子弹,再增加一种贝塞尔射击方式

//左向贝塞尔子弹
int MY_BULLET_BZ_TRACK_1=7;
//右向贝塞尔子弹
int MY_BULLET_BZ_TRACK_2=8;
//贝塞尔子弹
int MY_SHOT_BZ_BULLET_1 = 6;
然后我们在Bullet中添加相应的update和draw函数的内容

//左向BZ子弹
case TypeConst.MY_BULLET_BZ_TRACK_1:
//获得的路径点坐标
Point targetPos =this.pointList.get(pathIndex++);
this.x =targetPos.x;
this.y =targetPos.y;
break;
//右向BZ子弹
case TypeConst.MY_BULLET_BZ_TRACK_2:
Point targetPos1 =this.pointList.get(pathIndex++);
this.x =targetPos1.x;
this.y =targetPos1.y;
break;
draw函数中,我们增加

case TypeConst.MY_BULLET_BZ_TRACK_1:
g.setColor(Color.GREEN);
g.fillOval((int)this.x,(int)this.y, rdiusW, rdiusH);
break;
case TypeConst.MY_BULLET_BZ_TRACK_2:
g.setColor(Color.GREEN);
g.fillOval((int)this.x,(int)this.y, rdiusW, rdiusH);
break;
然后我们在Bullet的构造函数中,将起点,终点,和控制点,计算好,传入贝塞尔曲线的构造函数进行计算并取得路径点

//设置左向贝塞尔曲线
if (this.bulletType == TypeConst.MY_BULLET_BZ_TRACK_1){
this.targetV=this.getNestEnemy();
//设置贝塞尔曲线控制点
int inflectX = (int) (x + (this.targetV.x-x)/2)-350;
int inflectY = (int) (y + (this.targetV.y-y)/2)-250;
//创建贝塞尔曲线  传入贝塞尔曲线起点 ,传入贝塞尔曲线控制点,传入贝塞尔曲线终点
BZCarve crave=new BZCarve(new Point((int)x,(int)y),new Point(inflectX,inflectY),
new Point((int)this.targetV.x,(int)this.targetV.y));
//初始化贝塞尔曲线的计算,获得路径点
crave.init();
//获取路径点列表
this.pointList =crave.getPointList();
}
//设置右向贝塞尔曲线(同上)
if (this.bulletType == TypeConst.MY_BULLET_BZ_TRACK_2 ){
this.targetV=this.getNestEnemy();
//设置贝塞尔曲线控制点
int inflectX = (int) (x + (this.targetV.x-x)/2)+350;
int inflectY = (int) (y + (this.targetV.y-y)/2)-250;
//创建贝塞尔曲线  传入贝塞尔曲线起点 ,传入贝塞尔曲线控制点,传入贝塞尔曲线终点
BZCarve crave=new BZCarve(new Point((int)x,(int)y),new Point(inflectX,inflectY),
new Point((int)this.targetV.x,(int)this.targetV.y));
//初始化贝塞尔曲线的计算,获得路径点
crave.init();
//获取路径点列表
this.pointList =crave.getPointList();
}


ok这样子弹就算是做好了,下面我们来在MyPlanet中增加这种子弹,我们在fire中添加,一次发射,发射两颗贝塞尔弹,一颗是左向的,一颗是右向的

//贝塞尔子弹
case TypeConst.MY_SHOT_BZ_BULLET_1:
new Bullet(this.x+25,this.y-5,false,TypeConst.MY_BULLET_BZ_TRACK_1).setInitV(new PVector(0,0));
new Bullet(this.x+40,this.y-5,false,TypeConst.MY_BULLET_BZ_TRACK_2).setInitV(new PVector(0,0));
break;
好,现在我们的飞机子弹已经超越牛鞭了,运行一下看看效果吧!





到此为止,人工智能中的所有追踪算法和要做成一款优秀射击类游戏的核心秘密,我已经全部无偿的奉献给大家了,为了不让大家,拿了我的源码就直接去卖个几亿,我这里就不把飞机和场景换成炫丽的图片,不把子弹换成华丽的粒子效果了,不论是创造幸福还是创造性福,都得靠我们自己的双手,大家可以运用我所说的这些算法,在自己的平台上发挥想象力做出超商业级的游戏!

源码地址:http://download.csdn.net/detail/azhangzhengtong/5252850

下期预告《物理拟真与拦截算法---三胖你丫是纯爷们!》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: