Lentokoneen fysiikat
Posted: Sat Mar 08, 2014 2:38 pm
Julkaisin pikku pelit topicissa pari vuotta sitten lentokoneen fysiikat. Meinasin ne jo silloin laittaa tänne omaan topiciin, mutta se jäi sitten tekemättä. Innostuin kuitenkin eilen illalla vähän parantelemaan tätä ja korjasin ison läjän virheitä kaavoissa. Jos jotakuta kiinnostaa tehdä lentokonepeliä, niin tästä voi ottaa koodia fysiikoihin. Yritin käyttää BAe Hawkin tietoja pohjana tälle, mutta kaikkia tietoja ei löytynyt, niin jouduin heittämään arvoja päästäni ja säätämään sopivaksi. Nyt lennettävyys on kohtuu hyvä ja tuntuu käyttäytyvän kohtuullisesti fysiikanlakien mukaan. Liitteessä on mukana tarvittavat mediat (ja myös alempi koodi) esimerkin suorittamiseen.
Code: Select all
//Lentokoneena: BAe Hawk
SCREEN 1000,600
Const PHYSICS_ACCURACY = 3
Const AIR_DENSITY = 1.225
//Skaalaus
Const PIXEL_TO_METER = 0.1186
Const METER_TO_PIXEL = 8.4317032040472175379426644182125
Const GRAVITY = 9.81
Const ELEVATOR_DISTANCE_FROM_CENTER_OF_MASS = 5.1
Const ELEVATOR_AREA = 0.8 //m^2
Const ELEVATOR_DRAG_COEFFICIENT = 10.0
Const ROTATION_DRAG_COEFFICIENT = 100.0 //
Const WING_AREA = 16.69 //m^2
Const PLANE_MASS = 4000 //Kg
Const PLANE_MOMENT_OF_INERTIA = 4000 //Kg *m^2 Miten tämän saisi selville? Heitetty päästä ominaisuuksiin sopivaksi
Const DRAG_COEFFICIENT_X = 2.3 //Kerrottuna pinta-alalla TODO: Näillä arvoilla toimii, mutta ne eivät vastaa todellisuutta...
Const DRAG_COEFFICIENT_Y = 10.0
Const LIFT_DF_COEFFICIENT = 1.6
Const MOTOR_MAX_FORCE = 29130 //N
Const LIFT_COEFFICIENT_COUNT = 72
Dim LiftCoefficient(LIFT_COEFFICIENT_COUNT) As Float
Dim ElevatorLiftCoefficient(LIFT_COEFFICIENT_COUNT) As Float
InitLiftCoefficient()
floor=MakeObjectFloor()
grid=LoadImage("whitegrid.bmp")
PaintObject floor,grid
plane = LoadObject("aircraft.png", 180)
planeVX# = 50 //m/s
planeVY# = 0 //m/s
planeVA# = 0 //deg/s
planeThrottle# = 1.0 //Kaasun asento
elevatorAngle# = 0
DrawToWorld ON
Repeat
planeThrottle# = Max(0.0,Min(1.0,planeThrottle+(UpKey()-DownKey())*0.01))
ElevatorAngle# = CurveAngle((RightKey()-LeftKey())*45.0,elevatorAngle#,30)
If KeyHit(cbKeyR) Then
planeVX# = 100 //m/s
planeVY# = 0 //m/s
planeVA# = 0 //deg
planeA# = 0
EndIf
planeA# = ObjectAngle(plane)
planeX# = ObjectX(plane)*PIXEL_TO_METER
planeY# = ObjectY(plane)*PIXEL_TO_METER
timestep# = 1.0/60.0/PHYSICS_ACCURACY
For physics_step = 1 To PHYSICS_ACCURACY
//Nollataan voimat
planeFX# = 0
planeFY# = 0
planeFA# = 0
//Suunta vektori
planeAX# = Cos(planeA#)
planeAY# = Sin(planeA#)
//Muunnettaan lentokoneen liike sen omaan koordinaatistoon
planeLVX# = planeVX#*planeAX# + planeVY#*planeAY#
planeLVY# = planeVY#*planeAX# - planeVX#*planeAY#
airspeed# = Distance(0,0,planeVX#,planeVY#)
AngleOfAttack# = WrapAngle(-GetAngle(0,0,planeLVX#,-planeLVY#))
//Lasketaan noste
lift# = CalcLift(AngleOfAttack,airspeed#)
df# = CalcDF(AngleOfAttack, airspeed#)
aoaAX# = Cos(angleOfAttack)
aoaAY# = Sin(angleOfAttack)
//Lasketaan ilmanvastus
airresistY# = 0.5*AIR_DENSITY*planeLVY#*planeLVY#*DRAG_COEFFICIENT_Y
airresistX# = 0.5*AIR_DENSITY*planeLVX#*planeLVX#*DRAG_COEFFICIENT_X
airresistA# = 0.5*AIR_DENSITY*planeVA#*planeVA#*ROTATION_DRAG_COEFFICIENT
//Ilmanvastuksen etumerkit oikein
If planeLVX# > 0.0 Then airresistX# = -airresistX#
If planeLVY# > 0.0 Then airresistY# = -airresistY#
If planeVA# > 0.0 Then airresistA# = -airresistA#
liftLVX# = lift# * aoaAY
liftLVY# = lift# * aoaAX#
planeLFY# = (liftLVY# + df# + airresistY#) //Noste + ilmanvastus
planeLFX# = (airresistX# + liftLVX# + planeThrottle*MOTOR_MAX_FORCE)//Ilmanvastus + moottorin voima
planeFA# = (airresistA# + CalcElevatorLift(angleOfAttack+elevatorAngle#,airspeed#)*ELEVATOR_DISTANCE_FROM_CENTER_OF_MASS)
planeFX# = planeLFX#*planeAX# - planeLFY#*planeAY#
planeFY# = planeLFX#*planeAY# + planeLFY#*planeAX# - GRAVITY * PLANE_MASS
planeVX# = planeVX# + (planeFX# / PLANE_MASS) * timestep#
planeVY# = planeVY# + (planeFY# / PLANE_MASS) * timestep#
planeVA# = planeVA# + (planeFA# / PLANE_MOMENT_OF_INERTIA) * timestep#
//LIsätään sijaintiin ja kulmaan liikkeet
planeX# = planeX# + planeVX#*timestep#
planeY# = planeY# + planeVY#*timestep#
planeA# = planeA# + planeVA#*timestep#
Next physics_step
Text 10,10,"VX#:"+LSet(Str(planeVX#) + "m/s" , 12)+" VY#:"+LSet(Str(planeVY#) + "m/s", 12)+" VA#:"+LSet(Str(planeVA#) +"deg/s", 13)+" Angle:"+LSet(Str(planeA#) + "deg", 13)+" Lift:"+LSet(Str(lift#) + "N", 10)
Text 10,20,"ARX:"+LSet(Str(airresistX#) + "N", 10)+" ARY:"+LSet(Str(airresistX#) + "N", 10)
Text 10,30,"LVX:"+planeLVX#
Text 10,40,"Throttle:"+planeThrottle#+" Elevator angle:"+DirAngle(ElevatorAngle#)
Text 10,50,"Elevator force:"+elevatorForce#+ "AoA:"+DirAngle(AngleOfAttack#)
Text 10,60,"FX#:"+planeFX#+" FY#:"+planeFY#+" FA#:"+planeFA#
Text 10,70,"FPS:" + FPS() + " Air speed:" + Distance(0, 0, planeVX#, planeVY#)
PositionObject plane,planeX#*METER_TO_PIXEL,planeY#*METER_TO_PIXEL
RotateObject plane,planeA#
CloneCameraPosition plane
DrawGame
DrawScreen
Forever
Function InitLiftCoefficient()
//http://en.wikipedia.org/wiki/File:Lift_curve.svg
//0deg
//For i = 0 To 72
// LiftCoefficient(i) = Sin(i * 5.0 + 10) * 1.6 * (1 - (i / 150))
//Next i
LiftCoefficient(0) = 0.6
LiftCoefficient(1) = 1.0
LiftCoefficient(2) = 1.5
LiftCoefficient(3) = 1.8
LiftCoefficient(4) = 1.6
LiftCoefficient(5) = 1.4
LiftCoefficient(6) = 1.25
LiftCoefficient(7) = 1.08
LiftCoefficient(8) = 0.9
LiftCoefficient(9) = 0.6
LiftCoefficient(10) = 0.4
LiftCoefficient(11) = 0.3
LiftCoefficient(12) = 0.2
LiftCoefficient(13) = 0.1
LiftCoefficient(14) = 0.05
LiftCoefficient(15) = -0.05
LiftCoefficient(16) = -0.1
LiftCoefficient(17) = -0.15
//90deg
LiftCoefficient(18) = -0.22
LiftCoefficient(19) = -0.3
LiftCoefficient(20) = -0.3
LiftCoefficient(21) = -0.25
LiftCoefficient(22) = -0.25
LiftCoefficient(23) = -0.3
LiftCoefficient(24) = -0.3
LiftCoefficient(25) = -0.3
LiftCoefficient(26) = -0.3
LiftCoefficient(27) = -0.3
LiftCoefficient(28) = -0.3
LiftCoefficient(29) = -0.3
LiftCoefficient(30) = -0.3
LiftCoefficient(31) = -0.3
LiftCoefficient(32) = -0.3
LiftCoefficient(33) = -0.3
LiftCoefficient(34) = -0.3
LiftCoefficient(35) = -0.3
//180deg
LiftCoefficient(36) = -0.3
LiftCoefficient(37) = -0.25
LiftCoefficient(38) = -0.20
LiftCoefficient(39) = -0.15
LiftCoefficient(40) = -0.10
LiftCoefficient(41) = -0.05
LiftCoefficient(42) = -0.0
LiftCoefficient(43) = -0.0
LiftCoefficient(44) = -0.0
LiftCoefficient(45) = -0.0
LiftCoefficient(46) = -0.0
LiftCoefficient(47) = 0
LiftCoefficient(48) = 0
LiftCoefficient(49) = 0
LiftCoefficient(50) = 0
LiftCoefficient(51) = 0
LiftCoefficient(52) = 0
LiftCoefficient(53) = 0
//270deg
LiftCoefficient(54) = 0
LiftCoefficient(55) = 0
LiftCoefficient(56) = 0
LiftCoefficient(57) = 0
LiftCoefficient(58) = 0
LiftCoefficient(59) = 0
LiftCoefficient(60) = 0
LiftCoefficient(61) = -1.0
LiftCoefficient(62) = -1.5
LiftCoefficient(63) = -1.4
LiftCoefficient(64) = -1.4
LiftCoefficient(65) = -1.4
LiftCoefficient(66) = -1.3
LiftCoefficient(67) = -1.2
LiftCoefficient(68) = -1.2
LiftCoefficient(69) = -0.9
LiftCoefficient(70) = -0.5
LiftCoefficient(71) = 0.1
//360deg
LiftCoefficient(72) = 0.6
LiftCoefficient(72) = 0.6
LiftCoefficient(71) = 0.0
LiftCoefficient(70) = -0.5
LiftCoefficient(69) = -0.9
LiftCoefficient(68) = -1.2
LiftCoefficient(67) = -1.9
LiftCoefficient(66) = -2.8
LiftCoefficient(65) = -3.3
LiftCoefficient(64) = -3.9
LiftCoefficient(63) = -4.8
LiftCoefficient(62) = -5.5
LiftCoefficient(61) = -5.5
LiftCoefficient(60) = -5.5
For i = 0 To 72
ElevatorLiftCoefficient(i) = -((1.0-Abs((i Mod 18)-9)/9.0))*ELEVATOR_DRAG_COEFFICIENT
If (i > 18 And i < 36) Or (i > 54) Then ElevatorLiftCoefficient(i)= -ElevatorLiftCoefficient(i)
ElevatorLiftCoefficient(i) = ElevatorLiftCoefficient(i)
Next i
//TODO: Tarkempi taulukko + enemmän arvoja
EndFunction
Function DirAngle(a#)
a = WrapAngle(a)
If a > 180 Then Return a - 360
Return a
EndFunction
Function CalcElevatorLift(AngleOfAttack#,airspeed#)
aoa# = WrapAngle(AngleOfAttack#)/360.0*LIFT_COEFFICIENT_COUNT
aoamin# = ElevatorLiftCoefficient(Int(Max(0,RoundDown(aoa#))))
aoamax# = ElevatorLiftCoefficient(Int(Min(LIFT_COEFFICIENT_COUNT,RoundUp(aoa#))))
Return 0.5*AIR_DENSITY*airspeed#*airspeed#*ELEVATOR_AREA*(aoamin+(aoamax-aoamin)*(((aoa#-RoundDown(aoa#)) / 4.0)/LIFT_COEFFICIENT_COUNT))
EndFunction
Function CalcDF(aoa#, airspeed#)
c# = Sin(aoa#) * LIFT_DF_COEFFICIENT
Return 0.5 * airspeed# * airspeed# * c# * WING_AREA * AIR_DENSITY
EndFunction
Function CalcLift(AngleOfAttack#,airspeed#)
aoa# = WrapAngle(AngleOfAttack#)/360.0*LIFT_COEFFICIENT_COUNT
aoamin# = LiftCoefficient(Int(Max(0,RoundDown(aoa#))))
aoamax# = LiftCoefficient(Int(Min(LIFT_COEFFICIENT_COUNT,RoundUp(aoa#))))
Return 0.5*AIR_DENSITY*airspeed#*airspeed#*WING_AREA*(aoamin+(aoamax-aoamin)*(((aoa#-RoundDown(aoa#)) / 4.0)/LIFT_COEFFICIENT_COUNT))
EndFunction