Here's what I have so far... I have two different methods of rotating the objects (moddir and mod2dir) but neither matches up with the actual angling of the object and it's movement. The quat and vec3 code is from Leadwerk's code. I'm stumped...
Strict Import sidesign.minib3d Local width:Int=800,height:Int=600,depth:Int=32,mode:Int=1 Local move:Float =2.0 Local ps:Int = 150 Local ht:Int = 100 Local pathlen:Float = Sqr((14.3*14.3)+(4.1*4.1)) Local pathang:Float = ASin(4.1/14.3) Graphics3D width,height,depth,mode Local cam:TCamera = CreateCamera() PositionEntity cam,0,ht,0 cam.CameraRange(1,5000) Local cam2:Tcamera = CreateCamera() PositionEntity Cam2,0,ht,0 cam2.CameraViewport 0,400,200,200 cam2.RotateEntity 90,0,0 cam2.EntityParent(cam) Local light:TLight = CreateLight(1) LightRange(light,5000) PositionEntity light,0,700,0 '***********************MAP***************** Local terr1:TMesh = LoadMesh("resource/map/map1.b3d") Local terr2:TMesh = LoadMesh("resource/map/map2.b3d") Local terr3:TMesh = LoadMesh("resource/map/map3.b3d") Local terr4:TMesh = LoadMesh("resource/map/map4.b3d") Local tex:TTexture = LoadTexture("resource/map/grass6.bmp") PositionEntity terr1,0,0,0 ScaleEntity terr1,ps,ht,ps EntityTexture terr1,tex PositionEntity terr2,0,0,ps*4 ScaleEntity terr2,ps,ht,ps EntityTexture terr2,tex PositionEntity terr3,0,0,-ps*4 ScaleEntity terr3,ps,ht,ps EntityTexture terr3,tex PositionEntity terr4,ps*4,0,0 ScaleEntity terr4,ps,ht,ps EntityTexture terr4,tex '*********************Sky********************* Local sky:TMesh=CreateSphere(12) ScaleEntity sky,1000,500,1000 FlipMesh sky EntityFX sky,1 Local sky_tex:TTexture=LoadTexture("resource/textures/skybox.png") EntityTexture sky,sky_tex light.EntityParent(sky) '*********************Fighter******************** Local player:Tfighter = Tfighter.Make(-10,50,30) Local shadow:Tfighter = Tfighter.Make(10,50,30) EntityTexture (shadow.air,shadow.redtex) '*********************Setup ****************** Local cx#=0 Local cy#=0 Local cz#=0 Local pitch#=0 Local yaw#=0 Local roll#=0 ' used by fps code Local old_ms:Float=MilliSecs() Local renders:Float Local fps:Float '******************* Step loop ***************** HideMouse() '**********************Main Loop *************** Repeat If KeyHit(KEY_ENTER) Then DebugStop ' control camera If KeyDown(KEY_UP) Then cz#=cz#+move If KeyDown(KEY_LEFT) Then cx#=cx#-move If KeyDown(KEY_RIGHT) Then cx#=cx#+move If KeyDown(KEY_DOWN) Then cz#=cz#-move If KeyDown(KEY_W) Then pitch#=pitch#+1.0 If KeyDown(KEY_A) Then yaw#=yaw#+1.0 If KeyDown(KEY_S) Then pitch#=pitch#-1.0 If KeyDown(KEY_D) Then yaw#=yaw#-1.0 If KeyHit(KEY_H) Then player.Move() shadow.Move() End If If KeyHit(KEY_J) Then player.ModDir(0,30,0) shadow.Mod2Dir(0,30,0) End If If KeyHit(KEY_G) Then player.ModDir(0,-30,0) shadow.Mod2Dir(0,-30,0) End If If KeyHit(KEY_Y) Then player.ModDir(30,0,0) shadow.Mod2Dir(30,0,0) End If If KeyHit(KEY_N) Then player.ModDir(-30,0,0) shadow.Mod2Dir(-30,0,0) End If If KeyHit(KEY_I) Then player.ModDir(0,0,30) shadow.Mod2Dir(0,0,30) End If If KeyHit(KEY_K) Then player.ModDir(0,0,-30) shadow.Mod2Dir(0,0,-30) End If MoveEntity cam,cx#*0.5,cy#*0.5,cz#*0.5 PositionEntity(sky,EntityX(cam),0,EntityZ(cam)) RotateEntity cam,pitch#,yaw#,roll# cx#=0 cy#=0 cz#=0 cx#=0 cy#=0 cz#=0 RenderWorld renders=renders+1 ' calculate fps If MilliSecs()-old_ms>=1000 old_ms=MilliSecs() fps=renders renders=0 EndIf BeginMax2D() DrawText "FPS: "+String(fps),0,0 DrawText "Memory: "+GCMemAlloced(),0,20 DrawText "X: "+player.x+", Y: "+player.y+", Z: "+player.z,0,40 DrawText "Phi: "+player.phi+", Theta: "+player.theta+", Psi: "+player.psi,0,60 EndMax2D() Flip 1 Until KeyDown(KEY_ESCAPE) Or AppTerminate() End Type Tfighter Field x#,y#,z#,oldx#,oldy#,oldz# Field air:TMesh = LoadMesh ("resource/models/MECVair2.b3d") Field airtex:TTexture = LoadTexture ("resource/textures/MECVair2.png") Field redtex:TTexture = LoadTexture ("resource/textures/pathbase.png") Field phi%,theta%, psi%,oldphi%,oldtheta%,oldpsi% Field thrust%=15,lift#=0.0 Function Make:Tfighter (xin#=0.0,yin#=0.0,zin#=0.0,pitch%=0,yaw%=0,roll%=0) Local temp:Tfighter = New Tfighter temp.x = xin temp.y = yin temp.z = zin temp.phi = -pitch temp.theta = -yaw temp.psi = -roll temp.thrust=15 EntityTexture (temp.air,temp.airtex) PositionEntity (temp.air, temp.x,temp.y,temp.z) RotateEntity(temp.air,temp.phi,temp.theta,temp.psi) Return temp End Function Method Move() oldx = x oldy = y oldz = z Local speed% = 0 x=x+(Cos(theta)*Cos(phi)*thrust)'+((Sin(theta)*Sin(phi)-Cos(theta)*Sin(phi)*Cos(psi))*lift) z=z+(Sin(theta)*Cos(phi)*thrust)'+((-Cos(theta)*Sin(psi)-Sin(theta)*Sin(phi)*Cos(psi))*lift) y=y+(Sin(phi)*thrust)'+(Cos(phi)*Cos(psi)*lift) PositionEntity(air,x,y,z) End Method Method SetDir(a%=0,b%=0,c%=0) oldphi=phi oldtheta=theta oldpsi=psi phi = a theta = b psi = c RotateEntity(air,phi,theta,psi) End Method Method ModDir(pitch%=0,yaw%=0,roll%=0) oldphi=phi oldtheta=theta oldpsi=psi phi = phi+pitch theta = theta-yaw psi = psi-roll RotateEntity(air,psi,theta,phi) End Method Method Mod2Dir(pitch%=0,yaw%=0,roll%=0) oldphi=phi oldtheta=theta oldpsi=psi Local tempeu:TVec3 = Vec3(phi,theta,psi) Local qdir:TQuat = tempeu.ToQuat() qdir.normalize() Local temp2:TVec3 = Vec3(pitch,yaw,roll) Local qchange:TQuat = temp2.toQuat() qchange.normalize() Local FinalQ:TQuat = qdir.times(qchange) finalq.normalize() phi=finalq.pitch() theta=Finalq.yaw() psi=finalq.roll() RotateEntity(air,phi,theta,psi,True) End Method End Type Function Vec3:TVec3( x#=0.0,y#=0.0/0.0,z#=0.0/0.0 ) Local t:TVec3=New TVec3 If IsNan(y) y=x If IsNan(z) z=y t.x=x t.y=y t.z=z Return t EndFunction Function Quat:TQuat( x#,y#,z#,w# ) Local t:TQuat=New TQuat t.x=x t.y=y t.z=z t.w=w Return t EndFunction Type TVec3 {value} Field x#,y#,z# {attribute} Method Length#() Return Sqr( x*x+y*y+z*z ) End Method Method Dot#( v:TVec3 ) Return x*v.x+y*v.y+z*v.z End Method Method Inverse:TVec3() Return Vec3( -x,-y,-z ) End Method Method Reciprocal:TVec3() Return Vec3( 1/x,1/y,1/z ) End Method Method Normalize:TVec3() Local t#=Sqr( x*x+y*y+z*z ) If t=0.0 Return vec3(0.0,0.0,0.0) Return Vec3( x/t,y/t,z/t ) End Method Method Scale:TVec3( scale# ) Return Vec3( x*scale,y*scale,z*scale ) End Method Method DistanceTo#( v:TVec3 ) Local dx#=x-v.x,dy#=y-v.y,dz#=z-v.z Return Sqr( dx*dx+dy*dy+dz*dz ) End Method Method Plus:TVec3( v:TVec3 ) Return Vec3( x+v.x,y+v.y,z+v.z ) End Method Method Minus:TVec3( v:TVec3 ) Return Vec3( x-v.x,y-v.y,z-v.z ) End Method Method Times:TVec3( v:TVec3 ) Return Vec3( x*v.x,y*v.y,z*v.z ) End Method Method DividedBy:TVec3( v:TVec3 ) Return Vec3( x/v.x,y/v.y,z/v.z ) End Method Method Cross:TVec3( v:TVec3 ) Return Vec3( y*v.z-z*v.y,z*v.x-x*v.z,x*v.y-y*v.x ) End Method Method Blend:TVec3( v:TVec3,Alpha# ) Local beta#=1-Alpha Return Vec3( x*beta+v.x*Alpha,y*beta+v.y*Alpha,z*beta+v.z*Alpha ) End Method Method ToQuat:TQuat() Local c1#=Cos(-z/2) Local s1#=Sin(-z/2) Local c2#=Cos(-x/2) Local s2#=Sin(-x/2) Local c3#=Cos( y/2) Local s3#=Sin( y/2) Local c1_c2#=c1*c2 Local s1_s2#=s1*s2 Local t:TQuat=New TQuat t.x=c1*s2*c3 - s1*c2*s3; t.y=c1_c2*s3 + s1_s2*c3; t.z=s1*c2*c3 + c1*s2*s3; t.w=c1_c2*c3 - s1_s2*s3; Return t EndMethod Function FromQuat:TVec3(quat:TQuat) Return quat.toeuler() EndFunction Method Compare:Int(o:Object) Local t:TVec3=TVec3(o) If x<t.x Return -1 If y<t.y Return -1 If z<t.z Return -1 If x>t.x Return 1 If y>t.y Return 1 If z>t.z Return 1 Return 0 EndMethod EndType Type TQuat Field x#,y#,z#,w#=1.0 {attribute} Method Copy:TQuat() Return Quat( x,y,z,w ) End Method Method ToString$() Return "Quat("+x+","+y+","+z+","+w+")" End Method Method Inverse:TQuat() Return Quat( -x,-y,-z,w ) End Method Method ToAngleAxis( angle# Var,axis:TVec3 Var ) Local t#=ACos(w) angle=t*2 If angle>0 t=1/Sin(t) axis=Vec3( x*t,y*t,z*t ) Else axis=Vec3(0,0,0) EndIf End Method Method Yaw#() Return ATan2( 2*y*w-2*z*x,1-2*y*y-2*x*x ) End Method Method Pitch#() Return -ASin( 2*z*y+2*x*w ) End Method Method Roll#() Return -ATan2( 2*z*w-2*y*x,1-2*z*z-2*x*x ) End Method Method ToEuler:TVec3() Local x2#=x*x,y2#=y*y,z2#=z*z Local euler:TVec3=New TVec3 euler.y#=ATan2( 2*y*w-2*z*x,1-2*y2-2*x2 ) euler.x#=-ASin( 2*z*y+2*x*w ) euler.z#=-ATan2( 2*z*w-2*y*x,1-2*z2-2*x2 ) Return euler End Method Method Times:TQuat( q:TQuat ) Local result:TQuat=New TQuat result.x#=w*q.x + x*q.w + y*q.z - z*q.y result.y#=w*q.y + y*q.w + z*q.x - x*q.z result.z#=w*q.z + z*q.w + x*q.y - y*q.x result.w#=w*q.w - x*q.x - y*q.y - z*q.z Return result EndMethod Method Slerp:TQuat( q:TQuat,a# ) Local b#=1-a,f Local d#=x*q.x+y*q.y+z*q.z+w*q.w If d<0 d=-d f=True EndIf If d<1 Local om#=ACos( d )'- Local si#=Sin( om )'- a=Sin( a*om )/si'- b=Sin( b*om )/si'- EndIf If f a=-a Return Quat( x*b + q.x*a , y*b + q.y*a , z*b + q.z*a , w*b + q.w*a ) EndMethod Method Normalize:TQuat() Local q:TQuat=New TQuat Local m#=Sqr(x*x+y*y+z*z+w*w) q.x=x/m q.y=y/m q.z=z/m q.w=w/m Return q EndMethod Function FromAngleAxis:TQuat( angle#,axis:TVec3 ) angle:/2 Local s#=Sin(angle) Local t:TQuat=New TQuat t.x=s*axis.x t.y=s*axis.y t.z=s*axis.z t.w=Cos(angle) Return t EndFunction Function FromEuler:TQuat(euler:TVec3) Return euler.toquat() EndFunction EndType