用过Torque3D的人都知道,在这个引擎中可以在编辑模式下设定路径 然后AI就会按照这个路径运动,现在unity3D也可以啦 分享给大家 希望能有点帮助~总共3个文件
把第一个个文件放在新建的gameobject上 例如cube,然后creat empty创建空object作为splineparent,再创建4个或者多个sphere1,2,3,4作为它的子物体,然后将splineparent拖到这个代码var SplineParent : GameObject中,最后会看到cube按照sphere1到4的顺序运动~
JavaScript - SplineController.js
enum eOrientationMode { NODE = 0, TANGENT }
var SplineParent : GameObject;
var Duration : float = 10.0;
var OrientationMode : eOrientationMode = eOrientationMode.NODE;
var WrapMode : eWrapMode = eWrapMode.ONCE;
var AutoStart : boolean = true;
var AutoClose : boolean = true;
var HideOnExecute : boolean = true;
private var mSplineInterp : SplineInterpolator = null;
private var mTransforms : Array = null;
@script AddComponentMenu("Splines/Spline Controller")
function OnDrawGizmos()
{
var trans : Array = GetTransforms();
if (trans.length < 2)
return;
var interp = new SplineInterpolator();
SetupSplineInterpolator(interp, trans);
interp.StartInterpolation(null, false, WrapMode);
var prevPos : Vector3 = trans[0].position;
for (c=1; c <= 100; c++)
{
var currTime:float = c * Duration / 100.0;
var currPos = interp.GetHermiteAtTime(currTime);
var mag:float = (currPos-prevPos).magnitude * 2.0;
Gizmos.color = Color(mag, 0.0, 0.0, 1.0);
Gizmos.DrawLine(prevPos, currPos);
prevPos = currPos;
}
}
function Start()
{
mSplineInterp = gameObject.AddComponent(SplineInterpolator);
mTransforms = GetTransforms();
if (HideOnExecute)
DisableTransforms();
if (AutoStart)
FollowSpline();
}
function SetupSplineInterpolator(interp:SplineInterpolator, trans:Array) : void
{
interp.Reset();
if (AutoClose)
var step : float = Duration / trans.length;
else
step = Duration / (trans.length-1);
for (var c:int = 0; c < trans.length; c++)
{
if (OrientationMode == OrientationMode.NODE)
{
interp.AddPoint(trans[c].position, trans[c].rotation, step*c, Vector2(0.0, 1.0));
}
else if (OrientationMode == OrientationMode.TANGENT)
{
if (c != trans.length-1)
var rot : Quaternion = Quaternion.LookRotation(trans[c+1].position - trans[c].position, trans[c].up);
else if (AutoClose)
rot = Quaternion.LookRotation(trans[0].position - trans[c].position, trans[c].up);
else
rot = trans[c].rotation;
interp.AddPoint(trans[c].position, rot, step*c, Vector2(0.0, 1.0));
}
}
if (AutoClose)
interp.SetAutoCloseMode(step*c);
}
// We need this to sort GameObjects by name
class NameComparer extends IComparer
{
function Compare(trA : Object, trB : Object) : int {
return trA.gameObject.name.CompareTo(trB.gameObject.name);
}
}
//
// Returns children transforms already sorted by name
//
function GetTransforms() : Array
{
var ret : Array = new Array();
if (SplineParent != null)
{
// We need to use an ArrayList because there´s not Sort method in Array...
var tempTransformsArray = new ArrayList();
var tempTransforms = SplineParent.GetComponentsInChildren(Transform);
// We need to get rid of the parent, which is also returned by GetComponentsInChildren...
for (var tr : Transform in tempTransforms)
{
if (tr != SplineParent.transform)
tempTransformsArray.Add(tr);
}
tempTransformsArray.Sort(new NameComparer());
ret = Array(tempTransformsArray);
}
return ret;
}
//
// Disables the spline objects, we generally don't need them because they are just auxiliary
//
function DisableTransforms() : void
{
if (SplineParent != null)
{
SplineParent.SetActiveRecursively(false);
}
}
//
// Starts the interpolation
//
function FollowSpline()
{
if (mTransforms.length > 0)
{
SetupSplineInterpolator(mSplineInterp, mTransforms);
mSplineInterp.StartInterpolation(null, true, WrapMode);
}
}
JavaScript - SplineInterpolator.js
enum eEndPointsMode { AUTO = 0, AUTOCLOSED, EXPLICIT }
enum eWrapMode { ONCE = 0, LOOP }
private var mEndPointsMode = eEndPointsMode.AUTO;
class SplineNode
{
var Point : Vector3;
var Rot : Quaternion;
var Time : float;
var EaseIO : Vector2;
function SplineNode(p:Vector3, quaternion, t:float, io:Vector2) { Point=p; Rot=q; Time=t; EaseIO=io; }
function SplineNode(o : SplineNode) { Point=o.Point; Rot=o.Rot; Time=o.Time; EaseIO=o.EaseIO; }
}
private var mNodes : Array = null;
private var mState : String = "";
private var mRotations : boolean = false;
private var mOnEndCallback:Object;
function Awake()
{
Reset();
}
function StartInterpolation(endCallback : Object, bRotations : boolean, mode : eWrapMode)
{
if (mState != "Reset")
throw "First reset, add points and then call here";
mState = mode == eWrapMode.ONCE? "Once" : "Loop";
mRotations = bRotations;
mOnEndCallback = endCallback;
SetInput();
}
function Reset()
{
mNodes = new Array();
mState = "Reset";
mCurrentIdx = 1;
mCurrentTime = 0.0;
mRotations = false;
mEndPointsMode = eEndPointsMode.AUTO;
}
function AddPoint(pos : Vector3, quat : Quaternion, timeInSeconds : float, easeInOut : Vector2)
{
if (mState != "Reset")
throw "Cannot add points after start";
mNodes.push(SplineNode(pos, quat, timeInSeconds, easeInOut));
}
function SetInput()
{
if (mNodes.length < 2)
throw "Invalid number of points";
if (mRotations)
{
for (var c:int = 1; c < mNodes.length; c++)
{
// Always interpolate using the shortest path -> Selective negation
if (Quaternion.Dot(mNodes[c].Rot, mNodes[c-1].Rot) < 0)
{
mNodes[c].Rot.x = -mNodes[c].Rot.x;
mNodes[c].Rot.y = -mNodes[c].Rot.y;
mNodes[c].Rot.z = -mNodes[c].Rot.z;
mNodes[c].Rot.w = -mNodes[c].Rot.w;
}
}
}
if (mEndPointsMode == eEndPointsMode.AUTO)
{
mNodes.Unshift(mNodes[0]);
mNodes.push(mNodes[mNodes.length-1]);
}
else if (mEndPointsMode == eEndPointsMode.EXPLICIT && (mNodes.length < 4))
throw "Invalid number of points";
}
function SetExplicitMode() : void
{
if (mState != "Reset")
throw "Cannot change mode after start";
mEndPointsMode = eEndPointsMode.EXPLICIT;
}
function SetAutoCloseMode(joiningPointTime : float) : void
{
if (mState != "Reset")
throw "Cannot change mode after start";
mEndPointsMode = eEndPointsMode.AUTOCLOSED;
mNodes.push(new SplineNode(mNodes[0] as SplineNode));
mNodes[mNodes.length-1].Time = joiningPointTime;
var vInitDir : Vector3 = (mNodes[1].Point - mNodes[0].Point).normalized;
var vEndDir : Vector3 = (mNodes[mNodes.length-2].Point - mNodes[mNodes.length-1].Point).normalized;
var firstLength : float = (mNodes[1].Point - mNodes[0].Point).magnitude;
var lastLength : float = (mNodes[mNodes.length-2].Point - mNodes[mNodes.length-1].Point).magnitude;
var firstNode : SplineNode = new SplineNode(mNodes[0] as SplineNode);
firstNode.Point = mNodes[0].Point + vEndDir*firstLength;
var lastNode : SplineNode = new SplineNode(mNodes[mNodes.length-1] as SplineNode);
lastNode.Point = mNodes[0].Point + vInitDir*lastLength;
mNodes.Unshift(firstNode);
mNodes.push(lastNode);
}
private var mCurrentTime = 0.0;
private var mCurrentIdx = 1;
function Update ()
{
if (mState == "Reset" || mState == "Stopped" || mNodes.length < 4)
return;
mCurrentTime += Time.deltaTime;
// We advance to next point in the path
if (mCurrentTime >= mNodes[mCurrentIdx+1].Time)
{
if (mCurrentIdx < mNodes.length-3)
{
mCurrentIdx++;
}
else
{
if (mState != "Loop")
{
mState = "Stopped";
// We stop right in the end point
transform.position = mNodes[mNodes.length-2].Point;
if (mRotations)
transform.rotation = mNodes[mNodes.length-2].Rot;
// We call back to inform that we are ended
if (mOnEndCallback != null)
mOnEndCallback();
}
else
{
mCurrentIdx = 1;
mCurrentTime = 0.0;
}
}
}
if (mState != "Stopped")
{
// Calculates the t param between 0 and 1
var param : float = (mCurrentTime - mNodes[mCurrentIdx].Time) / (mNodes[mCurrentIdx+1].Time - mNodes[mCurrentIdx].Time);
// Smooth the param
param = MathUtils.Ease(param, mNodes[mCurrentIdx].EaseIO.x, mNodes[mCurrentIdx].EaseIO.y);
transform.position = GetHermiteInternal(mCurrentIdx, param);
if (mRotations)
{
transform.rotation = GetSquad(mCurrentIdx, param);
}
}
}
function GetSquad(idxFirstPoint : int, t : float) : Quaternion
{
var Q0 : Quaternion = mNodes[idxFirstPoint-1].Rot;
var Q1 : Quaternion = mNodes[idxFirstPoint].Rot;
var Q2 : Quaternion = mNodes[idxFirstPoint+1].Rot;
var Q3 : Quaternion = mNodes[idxFirstPoint+2].Rot;
var T1 : Quaternion = MathUtils.GetSquadIntermediate(Q0, Q1, Q2);
var T2 : Quaternion = MathUtils.GetSquadIntermediate(Q1, Q2, Q3);
return MathUtils.GetQuatSquad(t, Q1, Q2, T1, T2);
}
function GetHermiteInternal(idxFirstPoint : int, t : float) : Vector3
{
var t2 = t*t; var t3 = t2*t;
var P0 : Vector3 = mNodes[idxFirstPoint-1].Point;
var P1 : Vector3 = mNodes[idxFirstPoint].Point;
var P2 : Vector3 = mNodes[idxFirstPoint+1].Point;
var P3 : Vector3 = mNodes[idxFirstPoint+2].Point;
var tension : float = 0.5; // 0.5 equivale a catmull-rom
var T1 : Vector3 = tension * (P2 - P0);
var T2 : Vector3 = tension * (P3 - P1);
var Blend1 : float = 2*t3 - 3*t2 + 1;
var Blend2 : float = -2*t3 + 3*t2;
var Blend3 : float = t3 - 2*t2 + t;
var Blend4 : float = t3 - t2;
return Blend1*P1 + Blend2*P2 + Blend3*T1 + Blend4*T2;
}
function GetHermiteAtTime(timeParam : float) : Vector3
{
if (timeParam >= mNodes[mNodes.length-2].Time)
return mNodes[mNodes.length-2].Point;
for (var c:int = 1; c < mNodes.length-2; c++)
{
if (mNodes[c].Time > timeParam)
break;
}
var idx:int = c-1;
var param : float = (timeParam - mNodes[idx].Time) / (mNodes[idx+1].Time - mNodes[idx].Time);
param = MathUtils.Ease(param, mNodes[idx].EaseIO.x, mNodes[idx].EaseIO.y);
return GetHermiteInternal(idx, param);
}
JavaScript - MathUtils.js
class MathUtils
{
//
//
//
static function GetQuatLength(q : Quaternion) : float
{
return Mathf.Sqrt(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
}
//
//
//
static function GetQuatConjugate(q : Quaternion) : Quaternion
{
return Quaternion(-q.x, -q.y, -q.z, q.w);
}
//
// Logarithm of a unit quaternion. The result is not necessary a unit quaternion.
//
static function GetQuatLog(q : Quaternion) : Quaternion
{
var res : Quaternion = q;
res.w = 0;
if (Mathf.Abs(q.w) < 1.0)
{
var theta : float = Mathf.Acos(q.w);
var sin_theta : float = Mathf.Sin(theta);
if (Mathf.Abs(sin_theta) > 0.0001)
{
var coef:float = theta/sin_theta;
res.x = q.x*coef;
res.y = q.y*coef;
res.z = q.z*coef;
}
}
return res;
}
//
// Exp
//
static function GetQuatExp(q : Quaternion) : Quaternion
{
var res : Quaternion = q;
var fAngle:float = Mathf.Sqrt(q.x*q.x + q.y*q.y + q.z*q.z);
var fSin:float = Mathf.Sin(fAngle);
res.w = Mathf.Cos(fAngle);
if (Mathf.Abs(fSin) > 0.0001)
{
var coef:float = fSin/fAngle;
res.x = coef*q.x;
res.y = coef*q.y;
res.z = coef*q.z;
}
return res;
}
//
// SQUAD Spherical Quadrangle interpolation [Shoe87]
//
static function GetQuatSquad (t : float, q0 : Quaternion, q1 : Quaternion, a0 : Quaternion, a1 : Quaternion)
{
var slerpT:float = 2.0*t*(1.0-t);
var slerpP = Slerp(q0, q1, t);
var slerpQ = Slerp(a0, a1, t);
return Slerp(slerpP, slerpQ, slerpT);
}
static function GetSquadIntermediate (q0uaternion, q1uaternion, q2uaternion)
{
var q1Inv : Quaternion = GetQuatConjugate(q1);
var p0 = GetQuatLog(q1Inv*q0);
var p2 = GetQuatLog(q1Inv*q2);
var sum : Quaternion = Quaternion(-0.25*(p0.x+p2.x), -0.25*(p0.y+p2.y), -0.25*(p0.z+p2.z), -0.25*(p0.w+p2.w));
return q1*GetQuatExp(sum);
}
//
// Smooths the input parameter t. If less than k1 ir greater than k2, it uses a sin. Between k1 and k2 it uses
// linear interp.
//
static function Ease(t : float, k1 : float, k2 : float) : float
{
var f:float; var s:float;
f = k1*2/Mathf.PI + k2 - k1 + (1.0-k2)*2/Mathf.PI;
if (t < k1)
{
s = k1*(2/Mathf.PI)*(Mathf.Sin((t/k1)*Mathf.PI/2-Mathf.PI/2)+1);
}
else
if (t < k2)
{
s = (2*k1/Mathf.PI + t-k1);
}
else
{
s= 2*k1/Mathf.PI + k2-k1 + ((1-k2)*(2/Mathf.PI))*Mathf.Sin(((t-k2)/(1.0-k2))*Mathf.PI/2);
}
return (s/f);
}
//
// We need this because Quaternion.Slerp always does it using the shortest arc
//
static function Slerp (p : Quaternion, q : Quaternion, t : float) : Quaternion
{
var ret : Quaternion;
var fCos : float = Quaternion.Dot(p, q);
if ((1.0 + fCos) > 0.00001)
{
if ((1.0 - fCos) > 0.00001)
{
var omega : float = Mathf.Acos(fCos);
var invSin : float = 1.0/Mathf.Sin(omega);
var fCoeff0 : float = Mathf.Sin((1.0-t)*omega)*invSin;
var fCoeff1 : float = Mathf.Sin(t*omega)*invSin;
}
else
{
fCoeff0 = 1.0-t;
fCoeff1 = t;
}
ret.x = fCoeff0*p.x + fCoeff1*q.x;
ret.y = fCoeff0*p.y + fCoeff1*q.y;
ret.z = fCoeff0*p.z + fCoeff1*q.z;
ret.w = fCoeff0*p.w + fCoeff1*q.w;
}
else
{
fCoeff0 = Mathf.Sin((1.0-t)*Mathf.PI*0.5);
fCoeff1 = Mathf.Sin(t*Mathf.PI*0.5);
ret.x = fCoeff0*p.x - fCoeff1*p.y;
ret.y = fCoeff0*p.y + fCoeff1*p.x;
ret.z = fCoeff0*p.z - fCoeff1*p.w;
ret.w = p.z;
}
return ret;
}
}
Unity3D小地图代码
@script ExecuteInEditMode()
public var blip : Texture; //定義一個指針文件代表角色
public var radarBG : Texture; //地圖背景圖片,我直接用場景里我創建的render texture
public var centerObject : Transform; //選擇角色的物體的位置信息
public var mapScale = 0.3; //地圖縮放
public var mapCenter = Vector2(50,50); //地圖中心
function OnGUI () {
bX=centerObject.transform.position.x * mapScale;
bY=centerObject.transform.position.z * mapScale;
bX=centerObject.transform.position.x * mapScale;
bY=centerObject.transform.position.z * mapScale;
GUI.DrawTexture(Rect(mapCenter.x-32,mapCenter.y-32,,),radarBG);
// 上面的mapCenter.x-32是地圖的x位置,mapCenter.y-32是y位置,,是地圖的大小
DrawBlipsForEnemies();
}
function DrawBlipsForCows(){
var gos : GameObject[];
gos = GameObject.FindGameObjectsWithTag("Cow");
var distance = Mathf.Infinity;
var position = transform.position;
for (var go : GameObject in gos) {
drawBlip(go,blip);
}
}
function drawBlip(go,aTexture){
centerPos=centerObject.position;
extPos=go.transform.position;
dist=Vector3.Distance(centerPos,extPos);
dx=centerPos.x-extPos.x;
dz=centerPos.z-extPos.z;
deltay=Mathf.Atan2(dx,dz)*Mathf.Rad2Deg - 270 - centerObject.eulerAngles.y;
bX=dist*Mathf.Cos(deltay * Mathf.Deg2Rad);
bY=dist*Mathf.Sin(deltay * Mathf.Deg2Rad);
bX=bX*mapScale;
bY=bY*mapScale;
if(dist<=200){
GUI.DrawTexture(Rect(mapCenter.x+bX,mapCenter.y+bY,2,2),aTexture);
}
}
function DrawBlipsForEnemies(){
var gos : GameObject[];
gos = GameObject.FindGameObjectsWithTag("Enemy");
var distance = Mathf.Infinity;
var position = transform.position;
for (var go : GameObject in gos) {
drawBlip(go,blip);
}
}
後半部份自己慢慢理解下,存為js文件即可使用
unity3d的动力学汽车脚本
这是从官网论坛上收集的一个汽车脚本,经过验证可以使用。由于skidmarks这个配套的脚本没有找到,所以把skidmarks相关的语句都屏蔽了,所以很遗憾没有刹车印的效果,其他的没有改。
拿出来共享,感兴趣的一起研究下。
汽车脚本代码看起来都比较复杂,主要是老外的编程底子牛,什么都写到代码里自动生成了。其实有些东西可以在编辑器里完成,这样就省不少代码了。还有制动和变速箱部分用了不少代码,这个可能要点汽车发动机知识,反正我是一点都没看懂。
不想研究的可以直接拿来用。
使用方法如下:
1、把脚本直接连到汽车车身网格上,车身要有Rigidbody Component,要有四个轮子网格做子物体。 要想有声音的话还要有AudioSource Component。
2、打开Inspector,选择汽车脚本,把四个轮子连接到相对应的Transform参数上。设置wheelRadius参数为你轮子网格的大小。WheelCollider是自动生成的,所以无需手动添加。这样就能保证运行了,其他的声音和灰尘可以再添加。
脚本源代码如下:
#pragma strict
//maximal corner and braking acceleration capabilities
var maxCornerAccel=10.0;
var maxBrakeAccel=10.0;
//center of gravity height - effects tilting in corners
var cogY = 0.0;
//engine powerband
var minRPM = 700;
var maxRPM = 6000;
//maximum Engine Torque
var maxTorque = 400;
//automatic transmission shift points
var shiftDownRPM = 2500;
var shiftUpRPM = 5500;
//gear ratios
var gearRatios = [-2.66, 2.66, 1.78, 1.30, 1.00];
var finalDriveRatio = 3.4;
//a basic handling modifier:
//1.0 understeer
//0.0 oversteer
var handlingTendency = 0.7;
//graphical wheel objects
var wheelFR : Transform;
var wheelFL : Transform;
var wheelBR : Transform;
var wheelBL : Transform;
//suspension setup
var suspensionDistance = 0.3;
var springs = 1000;
var dampers = 200;
var wheelRadius = 0.45;
//particle effect for ground dust
var groundDustEffect : Transform;
private var queryUserInput = true;
private var engineRPM : float;
private var steerVelo = 0.0;
private var brake = 0.0;
private var handbrake = 0.0;
private var steer = 0.0;
private var motor = 0.0;
//private var skidTime = 0.0;
private var onGround = false;
private var cornerSlip = 0.0;
private var driveSlip = 0.0;
private var wheelRPM : float;
private var gear = 1;
//private var skidmarks : Skidmarks;
private var wheels : WheelData[];
private var wheelY = 0.0;
private var rev = 0.0;
//Functions to be used by external scripts
//controlling the car if required
//===================================================================
//return a status string for the vehicle
function GetStatus(gui : GUIText) {
gui.text="v="+(rigidbody.velocity.magnitude * 3.6).ToString("f1") + " km/h\\ngear= "+gear+"\\nrpm= "+engineRPM.ToString("f0");
}
//return an information string for the vehicle
function GetControlString(gui : GUIText) {
gui.text="Use arrow keys to control the jeep,\\nspace for handbrake.";
}
//Enable or disable user controls
function SetEnableUserInput(enableInput)
{
queryUserInput=enableInput;
}
//Car physics
//===================================================================
//some whee calculation data
class WheelData{
var rotation = 0.0;
var coll : WheelCollider;
var graphic : Transform;
var maxSteerAngle = 0.0;
var lastSkidMark = -1;
var powered = false;
var handbraked = false;
var originalRotation : Quaternion;
};
function Start () {
//setup wheels
wheels=new WheelData[4];
for(i=0;i<4;i++)
wheels[i] = new WheelData();
wheels[0].graphic = wheelFL;
wheels[1].graphic = wheelFR;
wheels[2].graphic = wheelBL;
wheels[3].graphic = wheelBR;
wheels[0].maxSteerAngle=30.0;
wheels[1].maxSteerAngle=30.0;
wheels[2].powered=true;
wheels[3].powered=true;
wheels[2].handbraked=true;
wheels[3].handbraked=true;
for(w in wheels)
{
if(w.graphic==null)
Debug.Log("You need to assign all four wheels for the car script!");
if(!w.graphic.transform.IsChildOf(transform))
Debug.Log("Wheels need to be children of the Object with the car script");
w.originalRotation = w.graphic.localRotation;
//create collider
colliderObject = new GameObject("WheelCollider");
colliderObject.transform.parent = transform;
colliderObject.transform.position = w.graphic.position;
w.coll = colliderObject.AddComponent(WheelCollider);
w.coll.suspensionDistance = suspensionDistance;
w.coll.suspensionSpring.spring = springs;
w.coll.suspensionSpring.damper = dampers;
//no grip, as we simulate handling ourselves
w.coll.forwardFriction.stiffness = 0;
w.coll.sidewaysFriction.stiffness = 0;
w.coll.radius = wheelRadius;
}
//get wheel height (height forces are applied on)
wheelY=wheels[0].graphic.localPosition.y;
//setup center of gravity
rigidbody.centerOfMass.y = cogY;
//find skidmark object
// skidmarks = FindObjectOfType(typeof(Skidmarks));
//shift to first
gear=1;
}
//update wheel status
function UpdateWheels()
{
//calculate handbrake slip for traction gfx
handbrakeSlip=handbrake*rigidbody.velocity.magnitude*0.1;
if(handbrakeSlip>1)
handbrakeSlip=1;
totalSlip=0.0;
onGround=false;
for(w in wheels)
{
//rotate wheel
w.rotation += wheelRPM / 60.0 * -rev * 360.0 * Time.fixedDeltaTime;
w.rotation = Mathf.Repeat(w.rotation, 360.0);
w.graphic.localRotation= Quaternion.Euler( w.rotation, w.maxSteerAngle*steer, 0.0 ) * w.originalRotation;
//check if wheel is on ground
if(w.coll.isGrounded)
onGround=true;
slip = cornerSlip+(w.powered?driveSlip:0.0)+(w.handbraked?handbrakeSlip:0.0);
totalSlip += slip;
var hit : WheelHit;
var c : WheelCollider;
c = w.coll;
if(c.GetGroundHit(hit))
{
//if the wheel touches the ground, adjust graphical wheel position to reflect springs
w.graphic.localPosition.y-=Vector3.Dot(w.graphic.position-hit.point,transform.up)-w.coll.radius;
//create dust on ground if appropiate
if(slip>0.5 && hit.collider.tag=="Dusty")
{
groundDustEffect.position=hit.point;
groundDustEffect.particleEmitter.worldVelocity=rigidbody.velocity*0.5;
groundDustEffect.particleEmitter.minEmission=(slip-0.5)*3;
groundDustEffect.particleEmitter.maxEmission=(slip-0.5)*3;
groundDustEffect.particleEmitter.Emit();
}
//and skid marks
/*if(slip>0.75 && skidmarks != null)
w.lastSkidMark=skidmarks.AddSkidMark(hit.point,hit.normal,(slip-0.75)*2,w.lastSkidMark);
else
w.lastSkidMark=-1; */
}
// else w.lastSkidMark=-1;
}
totalSlip/=wheels.length;
}
//Automatically shift gears
function AutomaticTransmission()
{
if(gear>0)
{
if(engineRPM>shiftUpRPM&&gear if(engineRPM gear--; } } //Calculate engine acceleration force for current RPM and trottle function CalcEngine() : float { //no engine when braking if(brake+handbrake>0.1) motor=0.0; //if car is airborne, just rev engine if(!onGround) { engineRPM += (motor-0.3)*25000.0*Time.deltaTime; engineRPM = Mathf.Clamp(engineRPM,minRPM,maxRPM); return 0.0; } else { AutomaticTransmission(); engineRPM=wheelRPM*gearRatios[gear]*finalDriveRatio; if(engineRPM if(engineRPM //fake a basic torque curve x = (2*(engineRPM/maxRPM)-1); torqueCurve = 0.5*(-x*x+2); torqueToForceRatio = gearRatios[gear]*finalDriveRatio/wheelRadius; return motor*maxTorque*torqueCurve*torqueToForceRatio; } else //rpm delimiter return 0.0; } } //Car physics //The physics of this car are really a trial-and-error based extension of //basic "Asteriods" physics -- so you will get a pretty arcade-like feel. //This may or may not be what you want, for a more physical approach research //the wheel colliders function HandlePhysics () { var velo=rigidbody.velocity; wheelRPM=velo.magnitude*60.0*0.5; rigidbody.angularVelocity=new Vector3(rigidbody.angularVelocity.x,0.0,rigidbody.angularVelocity.z); dir=transform.TransformDirection(Vector3.forward); flatDir=Vector3.Normalize(new Vector3(dir.x,0,dir.z)); flatVelo=new Vector3(velo.x,0,velo.z); rev=Mathf.Sign(Vector3.Dot(flatVelo,flatDir)); //when moving backwards or standing and brake is pressed, switch to reverse if((rev<0||flatVelo.sqrMagnitude<0.5)&&brake>0.1) gear=0; if(gear==0) { //when in reverse, flip brake and gas tmp=brake; brake=motor; motor=tmp; //when moving forward or standing and gas is pressed, switch to drive if((rev>0||flatVelo.sqrMagnitude<0.5)&&brake>0.1) gear=1; } engineForce=flatDir*CalcEngine(); totalbrake=brake+handbrake*0.5; if(totalbrake>1.0)totalbrake=1.0; brakeForce=-flatVelo.normalized*totalbrake*rigidbody.mass*maxBrakeAccel; flatDir*=flatVelo.magnitude; flatDir=Quaternion.AngleAxis(steer*30.0,Vector3.up)*flatDir; flatDir*=rev; diff=(flatVelo-flatDir).magnitude; cornerAccel=maxCornerAccel; if(cornerAccel>diff)cornerAccel=diff; cornerForce=-(flatVelo-flatDir).normalized*cornerAccel*rigidbody.mass; cornerSlip=Mathf.Pow(cornerAccel/maxCornerAccel,3); rigidbody.AddForceAtPosition(brakeForce+engineForce+cornerForce,transform.position+transform.up*wheelY); handbrakeFactor=1+handbrake*4; if(rev<0) handbrakeFactor=1; veloSteer=((15/(2*velo.magnitude+1))+1)*handbrakeFactor; steerGrip=(1-handlingTendency*cornerSlip); if(rev*steer*steerVelo<0) steerGrip=1; maxRotSteer=2*Time.fixedDeltaTime*handbrakeFactor*steerGrip; fVelo=velo.magnitude; veloFactor=fVelo<1.0?fVelo:Mathf.Pow(velo.magnitude,0.3); steerVeloInput=rev*steer*veloFactor*0.5*Time.fixedDeltaTime*handbrakeFactor; if(velo.magnitude<0.1) steerVeloInput=0; if(steerVeloInput>steerVelo) { steerVelo+=0.02*Time.fixedDeltaTime*veloSteer; if(steerVeloInput } else { steerVelo-=0.02*Time.fixedDeltaTime*veloSteer; if(steerVeloInput>steerVelo) steerVelo=steerVeloInput; } steerVelo=Mathf.Clamp(steerVelo,-maxRotSteer,maxRotSteer); transform.Rotate(Vector3.up*steerVelo*57.295788); } function FixedUpdate () { //query input axes if necessarry if(queryUserInput) { brake = Mathf.Clamp01(-Input.GetAxis("Vertical")); handbrake = Input.GetButton("Jump")?1.0:0.0; steer = Input.GetAxis("Horizontal"); motor = Mathf.Clamp01(Input.GetAxis("Vertical")); } else { motor = 0; steer = 0; brake = 0; handbrake = 0; } //if car is on ground calculate handling, otherwise just rev the engine if(onGround) HandlePhysics(); else CalcEngine(); //wheel GFX UpdateWheels(); //engine sounds audio.pitch=0.5+0.2*motor+0.8*engineRPM/maxRPM; audio.volume=0.5+0.8*motor+0.2*engineRPM/maxRPM; } //Called by DamageReceiver if boat destroyed function Detonate() { //destroy wheels for( w in wheels ) w.coll.gameObject.active=false; //no more car physics enabled=false; } @script RequireComponent (Rigidbody) @script RequireComponent (AudioSource) 漂浮效果 using UnityEngine; using System.Collections; public class Floater : MonoBehaviour { public float waterLevel, floatHeight; public Vector3 buoyancyCentreOffset; public float bounceDamp; void FixedUpdate () { Vector3 actionPoint = transform.position + transform.TransformDirection(buoyancyCentreOffset); float forceFactor = 1f - ((actionPoint.y - waterLevel) / floatHeight); if (forceFactor > 0f) { Vector3 uplift = -Physics.gravity * (forceFactor - rigidbody.velocity.y * bounceDamp); rigidbody.AddForceAtPosition(uplift, actionPoint); } } } 输入文字时让人物停止不动 var playName = "None"; static var currentControl ; function Update() { if( currentControl) return;//当有任何输入框被点击时屏蔽之后的内容 if (Input.GetKey(KeyCode.UpArrow)||Input.GetKey(KeyCode.W)){ transform.Translate(Vector3.forward*0.5); } if (Input.GetKey(KeyCode.DownArrow)||Input.GetKey(KeyCode.S)){ transform.Translate(Vector3.forward*-0.5); } if (Input.GetKey(KeyCode.LeftArrow)||Input.GetKey(KeyCode.A)){ transform.Rotate(Vector3.down *2); } if (Input.GetKey(KeyCode.RightArrow)||Input.GetKey(KeyCode.D)){ transform.Rotate(Vector3.up *2); } } function OnGUI(){ playName = GUI.TextField(Rect(10,10,100,20),playName); //当鼠标按在除输入框的 任意位置时 if( Input.GetMouseButtonDown( 0 ) && GUIUtility.hotControl == 0 ) GUIUtility.keyboardControl = 0; currentControl = GUIUtility.keyboardControl ; } ps:不管输入框在那个Scrpit中,只要在想屏蔽的地方的OnGUI加上面的代码就行, if( Input.GetMouseButtonDown( 0 ) && GUIUtility.hotControl == 0 ) GUIUtility.keyboardControl = 0;不用重复加入。 动态加载贴图或模型 var mesh1 : GameObject; function Start() { mesh1 = Instantiate(Resources.Load("model")); //加载模型 mesh1.transform.position=Vector3(1020,14,720); //模型出现的位置 } function Update () { renderer.material.mainTexture = Resources.Load("a"); //加载材质 } 下载本文