您的位置:首页 > 移动开发 > Unity3D

基于unity的飞行模拟设计

2015-06-27 14:36 543 查看
  使用unity开发游戏真是非常方便。研究飞行模拟也有一段时日,尝试过物理和数学模拟。从效果上来看,物理模拟较为真实一点。但是操作不好。数学模拟的话,虽然牺牲了飞行效果,操控是非常方便的。

  所谓的数学模拟,就是位移模拟,通过定义起飞速度,加速度等,模拟飞机的飞行过程,包括转向,飞行坠落等。

  来看一下飞机的飞行状态:在地面上,飞机达到起飞速度时,可以拉起飞机,否则,一直在地面上;在空中:当飞机低于起飞速度,下降。大于起飞速度则能保持在空中。飞机不可能倒着飞行的,所以,飞机的速度状态就有:起飞速度,正常速度,最大速度。通过输入改变当前速度,然后通过判断速度所对应的状态处理。

  飞机的转向:飞机的转向,有y轴的转向,控制飞机的左右飞行。x的转向,控制飞机的升降。左右飞行时,飞机自身需要以z轴旋转,来模拟飞机转弯的效果。

  飞机的失速:当飞机在空中的速度低于起飞速度时,飞机下落。当着地时,下落的速度为0.

  整理一下思路:可以通过射线检测的方式获取距离地面的高度,判断飞机是在空中还是地面。通过输入值来调整currentSpeed,通过与飞机的offSpeed,normalSpeed,maxSpeed比较,来判断飞机所处的状态。通过四元数方法,调整飞机的角度,保持飞机的平衡和转向时的偏转效果。

  主要使用到的方法:

  移动:transform.Translate(vector,Space.World);

  旋转:transform.Rotate(vector,Space.World);

  转角:transform.rotation=Quaternion.RotateTowards(transform.rotation,rotation,speed);

高度:Physics.Raycast(ray,outhit,1<<0);height=hit.distance;

  

  飞机的抽象控制方法:

publicabstractvoidMoveLR(floatspeed);//左右移动
publicabstractvoidRoteUD(floatspeed);//上下旋转
publicabstractvoidMoveFB(floatspeed);//速度控制
publicabstractvoidRoteLR(floatspeed);//左右旋转

  publicabstractBalance(Quaternionr,floatspeed);//转角


  publicabstractvoidOperational();//飞行状态



  接下来就是飞行方法的实现:

  

publicoverridevoidMoveFB(floatspeed)//速度控制
{
IsRun=true;//主动控制打开
CurrentSpeed+=speed*aircaft.Acc*Time.deltaTime;//加/减速
CurrentSpeed=Mathf.Clamp(CurrentSpeed,0,aircaft.MaxSpeed);//控制速度在最大值范围内
}
publicoverridevoidMoveLR(floatspeed)//水平移动飞机,飞机的侧飞
{
//左右移动
if((IsSing)||IsOnGround)return;//如果在地面或者飞机处于特技状态
//IsLRB=false;
Vector3vector=body.right;
vector.y=0;

Move(speed*vector*aircaft.MoveLRSpeed*Time.deltaTime*CurrentSpeed/aircaft.MoveFBSpeed);//侧飞

Balance(Quaternion.Euler(body.eulerAngles.x,body.eulerAngles.y,-aircaft.AxisLR*speed),aircaft.RoteLRSpeed*Time.deltaTime);/旋转机身,实现侧飞的效果
//print("MoveLR"+speed);
}
publicoverridevoidOperational()//飞机的状态控制
{
Altigraph();//测量高度

if(CurrentSpeed<aircaft.OffSpeed)//小于起飞速度
{//落下
if(!IsOnGround)//在空中
{
Move(-Vector3.up*Time.deltaTime*10*(1-CurrentSpeed/(aircaft.OffSpeed)));//失重下落
downSpeed=Mathf.Lerp(downSpeed,0.1f,Time.deltaTime);
//print("downSpeed"+downSpeed);
RoteUD(downSpeed);//机身前倾实现下落效果

}
if(!rigidbody)rigidbody=GetComponent<Rigidbody>();
rigidbody.useGravity=IsOnGround;//如果飞机在地面,启用重力,否则不使用重力
}
else{
downSpeed=0;
}
Balance();//保持飞机的平衡
if(!IsRun){//保持飞机以正常速度飞行
if(CurrentSpeed>aircaft.MoveFBSpeed)CurrentSpeed=Mathf.Lerp(CurrentSpeed,aircaft.MoveFBSpeed,Time.deltaTime);

elseif(CurrentSpeed>aircaft.OffSpeed&&!IsOnGround)CurrentSpeed=Random.Range(aircaft.OffSpeed,aircaft.MoveFBSpeed);
elseif(IsOnGround&&CurrentSpeed<aircaft.OffSpeed){
CurrentSpeed=Mathf.Lerp(CurrentSpeed,0,Time.deltaTime);

}
}
Move(body.forward*CurrentSpeed*Time.deltaTime);//调用飞行方法

}
publicoverridevoidRoteLR(floatspeed)//飞机的转向
{
//左右旋转
if((IsSing)||IsOnGround)return;
IsLRB=false;
Rote(speed*Vector3.up*aircaft.RoteLRSpeed*Time.deltaTime*CurrentSpeed/aircaft.MoveFBSpeed);

Balance(Quaternion.Euler(body.eulerAngles.x,body.eulerAngles.y,-aircaft.AxisLR*speed),aircaft.RoteLRSpeed*Time.deltaTime);
//print("RoteLR"+speed);
}

publicoverridevoidRoteUD(floatspeed)//飞机的转向
{
//上下旋转
//速度和角度
if((IsSing)||IsOnGround&&CurrentSpeed<aircaft.MoveFBSpeed/3.6f)return;
if(CurrentSpeed<aircaft.MoveFBSpeed/3.6f&&speed<0)return;
IsFBB=false;
Balance(Quaternion.Euler(aircaft.AxisFB*speed,body.eulerAngles.y,body.eulerAngles.z),aircaft.RoteFBSpeed*Time.deltaTime*CurrentSpeed/aircaft.MoveFBSpeed);
//print("RoteUD"+speed);
}
publicoverridevoidBalance()//飞机的平衡方法,当无输入事件时,飞机自动平衡
{
if(IsSing)return;
if(IsLRB)//z轴平衡(左右)
{
Balance(Quaternion.Euler(body.eulerAngles.x,body.eulerAngles.y,0),aircaft.RoteLRSpeed*Time.deltaTime/1.2f);
}
if(IsFBB)//x轴平衡(上下)
{
Balance(Quaternion.Euler(0,body.eulerAngles.y,body.eulerAngles.z),aircaft.RoteFBSpeed*Time.deltaTime/1.3f);
}
IsLRB=true;//自动平衡打开
IsFBB=true;//自动平衡打开
}


  都是非常简单的代码,关键是如何使用,以及逻辑的处理。

  为了增加飞机飞行的效果,我还设计了飞机的特技飞行:90度转角的左右飞行,以及180度翻转飞行。当然也是使用了基础的公式完成的。左右90度特技飞行:飞机侧身90度,并大角度的转角转向飞机的左或右方。获取相对于飞机在世界坐标的左/右方向V,然后通过判断当前方向与V的角度,来判定是否完成特技飞行。180度转角飞行:飞机绕自身x轴180度旋转,然后恢复平衡。

  因为特技飞行的完成需要一段时间,而这段时间是玩家不需要控制,系统完成后进入正常状态的,所以用到需要协程。

  

IEnumeratorSLR(floatspeed){
//90度转角飞行
speed=(speed>0?1:-1);
Vector3aim=body.right*(speed);
aim.y=0;
while(Vector3.Dot(aim.normalized,body.forward.normalized)<0.99f){
Rote(speed*Vector3.up*aircaft.RoteLRSpeed*Time.deltaTime);

Balance(Quaternion.Euler(body.eulerAngles.x,body.eulerAngles.y,-85*(speed)),aircaft.RoteLRSpeed*Time.deltaTime*3.8f);
Balance(Quaternion.Euler(0,body.eulerAngles.y,body.eulerAngles.z),aircaft.RoteFBSpeed*Time.deltaTime*1.8f);
yieldreturnnewWaitForFixedUpdate();
}
while((body.eulerAngles.z>15)&&(body.eulerAngles.z<180)||(body.eulerAngles.z<345)&&(body.eulerAngles.z>270))
{
Balance(Quaternion.Euler(0,body.eulerAngles.y,body.eulerAngles.z),aircaft.RoteFBSpeed*Time.deltaTime);
Balance(Quaternion.Euler(body.eulerAngles.x,body.eulerAngles.y,0),aircaft.RoteLRSpeed*Time.deltaTime*3);
yieldreturnnewWaitForFixedUpdate();
}
IsSing=false;
}
publicoverridevoidStuntUD(floataxis)
{
if((IsSing)||IsOnGround&&CurrentSpeed<aircaft.MoveFBSpeed/3.6f)return;

if(!IsSing)
{
IsSing=true;
StartCoroutine(SUD(axis));

}
}
IEnumeratorSUD(floatspeed)
{
//180度翻转
speed=(speed>0?1:-1);
Vector3aim=-body.forward;
aim.y=0;
while(Vector3.Dot(aim.normalized,body.forward.normalized)<0.8f)//飞机翻转
{
Vector3v=body.right;
v.y=0;
Rote(body.right*Time.deltaTime*-90*speed);
Move(-Vector3.up*speed*Time.deltaTime*10*(CurrentSpeed/(aircaft.OffSpeed)));
//body.Rotate(Vector3.right*Time.deltaTime*-90,Space.Self);
//Balance(Quaternion.Euler(body.eulerAngles.x,body.eulerAngles.y,0),aircaft.RoteLRSpeed*Time.deltaTime*5);
yieldreturnnewWaitForFixedUpdate();
}
while((body.eulerAngles.z>15)&&(body.eulerAngles.z<180)||(body.eulerAngles.z<345)&&(body.eulerAngles.z>270))//翻转后飞机完成平衡
{
Balance(Quaternion.Euler(0,body.eulerAngles.y,body.eulerAngles.z),aircaft.RoteFBSpeed*Time.deltaTime);
Balance(Quaternion.Euler(body.eulerAngles.x,body.eulerAngles.y,0),aircaft.RoteLRSpeed*Time.deltaTime*3);
yieldreturnnewWaitForFixedUpdate();
}
IsSing=false;
}


  


  以上是飞机的飞行模拟思路以及基本算法实现。玩家操作的代码就是输入检测之类的,然后再调用一下飞行接口就行了,我就不提供了。

  接下来的问题就是AI飞行了,由电脑逻辑控制的AI飞行。如上图,是由计算机控制的飞行。这个AI就一个核心方法,就是飞到目标点。要实现这个功能也很简单,就是计算一下目标点的距离,角度等。然后根据距离以及当前状态控制加减速度,通过角度控制转向。主要使用到Vector.Dot(v1,v2);,然后就是各种情况下的判断和飞行方法的调用。例如当目标在飞机的后方时,可以调用180度翻转,来锁定目标。

  好,我们简单的分析一下如何去写这个AI,获取目标Point,计算距离差,高度差,角度差。通过高度差,控制飞机的升降,距离差控制速度,角度差控制转向。

  嗯,下面就是实现的代码。

  

publicvoidMoveToPoint(Vector3point,floatstopDistance){

Vector3hPoint=point;
hPoint.y=flight.body.position.y;
hDistence=Vector3.Distance(hPoint,flight.body.position);//水平距离
distence=Vector3.Distance(point,flight.body.position);//距离
dHeight=point.y-flight.body.position.y;//高度差
vector=(point-flight.body.position).normalized;
dUDAgle=Vector3.Dot(vector,flight.body.TransformDirection(Vector3.up).normalized);
//获取目标点与当前位置的距离,高度差,判断目标相对于当前位置的前/后,左/右
dFBAgle=Vector3.Dot(vector,(flight.body.TransformDirection(Vector3.forward)).normalized);//判断目标点相对于当前位置的前后
//print(forward);
dLRAgle=Vector3.Dot(vector,(flight.body.TransformDirection(Vector3.right)).normalized);//判断目标点相对于当前位置的左右

//获取这个信息后,接下来就是移动到目标点
//先判断什么?正前方到目标点的角度,如果这个角度在一定范围内,则可以进行移动
//
floataxisFB=0;
if(dFBAgle>objectAI.Precision)
{
//方向偏移在正常范围内
//根据距离判断是否加/减速度
//

if(distence>objectAI.RunDistance*stopDistance||(flight.CurrentSpeed<flight.aircaft.OffSpeed&&!IsLand))
{
axisFB=Random.Range(0f,1f);
}
elseif(distence>objectAI.FreeDistance*stopDistance&&!IsLand)
{
axisFB=Random.Range(-0.5f,0.5f);
}
elseif(distence<objectAI.SlowDistance*stopDistance&&IsLand)
{
axisFB=Random.Range(-1f,0f);
}

}
else{
//方向偏移不在正常范围
//判断距离是否达到停止距离
//判断高度是否在误差之内
//调整左右和前后,来
if(distence<stopDistance)
{
//到达目标点附近,但是角度偏差过大,判断目标的左右,进行旋转
axisFB=Random.Range(0.5f,1f);
flight.RoteLR(dLRAgle);
}
else{

//if(Mathf.Abs(dLRAgle)<0.05f)dLRAgle=0;
if(dFBAgle<-0.75f)
{
flight.StuntUD(flight.Height>100?-1:1);
}
elseif(dFBAgle<-0.25f){
flight.StuntLR(dLRAgle);
}

flight.RoteLR(dLRAgle);
if(!IsLand){
if(Mathf.Abs(dHeight)>5){

flight.RoteUD(-dUDAgle);
}
if(flight.IsOnGround){
flight.RoteUD(-1);
}
}

if(flight.CurrentSpeed<flight.aircaft.MoveFBSpeed)
axisFB=Random.Range(0.5f,1f);
}
}
//flight.RoteLR(dLRAgle);
if(Mathf.Abs(axisFB)>0.01f)
flight.MoveFB(axisFB);
}


  好了,今天的飞行模拟就介绍到这了。预告一下,下一篇文章阿亮将探讨导弹算法的实现(预计目标点位置,而非通过获取目标的当前位置)

  导弹算法已经完成,博客地址:http://www.cnblogs.com/jqg-aliang/p/4768101.html谢谢观看!

本文的链接:http://www.cnblogs.com/jqg-aliang/p/4598515.html。转载请申明出处,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: