FreeSpace Releases > Scripting Releases

atomspheric flight

(1/4) > >>

Nuke:
ive been awake for like 2 days now developing this thing. i took a look at my old newtonian script, which had a bug that maybe broke colision detection. i was tinkering trying to fix it, i was unable to, but i thought it would be cool to try out some other features. started by adding lift and gravity forces in a hackish way, i didnt like it and got to thinking about adding drag. fortunately the drag equation was simple enough for me to handle. and i plugged it into the game without much hassle. it handled a tad more realistically (for atmo flight).

since there are 4 forces of flight, thrust, drag, lift and weight. i figured i was half way to making freeatmo1 :D. gravity was easy, i looked it up and realized i just needed to plug the ships mass into it to make it work more realistically. i spent most of today working on lift and tweaking vars. lift still isnt perfect but it works. theres something quirky about the direction of the force vector. according to nasa, lift is a force that needs to be perpendicular to the airflow and in the lift direction of the wing. however the function returns a number, and not a vector. needless to say i couldnt find an easy way to do this. multiplying the number by a ship's up vector didnt work to well, and wasnt perpendicular to airflow. tried using a matrix in 10 different ways. tried a cross product which got the best result, but the thing tends to wander and isnt always prependicular to airflow. maybe one of the physics nuts can look at it.

the script is simple, load a mission with some stationary stuff in it, maybe throw in a skybox or some terrain for orientation purposes (stay upright or you will fall like a brick, dont pull up too fast or you will stall). the physics vars are heavily commented to make tweaking a sinch. its set up to handle a ulysses right now. but any ship will work. only player ship gets affected so dont bother thowing in any bad guys. switch to external view to see the force vectors. ive also thrown airspeed and altitude indicators in as well so you can monitor your climb. have fun!


--- Code: ---#Global Hooks
$GameInit:
[
--[[=============================]]--
--[[======= function defs =======]]--
--[[=============================]]--

setscreenvars = function() --scalers and constants for multi res support
local w = gr.getScreenWidth()
local h = gr.getScreenHeight()
local cx = w/2
local cy = h/2
local wf = 0
local hf = 0
local awh = 0
local hires = false

if w >= 1024 then
wf = w / 1024
hf = h / 768
awh = (wf + hf) / 2
hires = true
else
wf = w / 640
hf = h / 480
awh = ((wf + hf) / 2) * 0.625
hires = false
end

return w,h,cx,cy,wf,hf,awh,hires
end

mousejoy = function() --mousejoy function, returns a value from -1 to 1 depending on the mouse's position
local X = io.getMouseX()
local Y = io.getMouseY()

if hires then
X = (X / 511.5) - 1
Y = (Y / 383.5) - 1
else
X = (X / 319.5) - 1
Y = (Y / 239.5) - 1
end

return X,Y
end

round = function(number) --rounds to nearest whole number, for some stupid reason, lua doesnt have this function
local W,F = math.modf(number)
if F < 0 then
if F <= -0.5 then W = W - 1 end
else
if F >= 0.5 then W = W + 1 end
end

return W
end

prograderet = function(x,y,vel)
x, y = x*wf, y*hf --round theese, our vector gets jumpy

gr.setColor(72,192,72,222)

gr.drawGradientLine(x + (12*awh), y + (12*awh), x + (6*awh), y + (6*awh) )
gr.drawGradientLine(x - (12*awh), y - (12*awh), x - (6*awh), y - (6*awh) )
gr.drawGradientLine(x - (12*awh), y + (12*awh), x - (6*awh), y + (6*awh) )
gr.drawGradientLine(x + (12*awh), y - (12*awh), x + (6*awh), y - (6*awh) )

vel = tostring(vel)

gr.setColor(128,192,128,222)
gr.drawString(vel, x - (gr.getStringWidth(vel) / 2), y - (2*awh) )
end

w,h,cx,cy,wf,hf,awh,hires = setscreenvars()

--[[=============================]]--
--[[======= physics specs =======]]--
--[[=============================]]--
--theese are for the ulysses, i picked this fighter because its essentially a flying wing.
--eventually i plan on making theese loadable via text file. yweek theese abit, try to
--make other profiles for other ships


--max thrust values in newtons, will load from file per ship eventually
--ramp the up thrust for ships without good wings will fly sorta like a helicopter
fd_thrust, rv_thrust, up_thrust, dn_thrust, lf_thrust, rt_thrust = 24000, 6000, 8000, 4000, 4000, 4000
--mass in kg
shp_mass = 5000
--cross-sections for drag area computation, area in square meters
--to figure these out, export the ship to max and maintain scale!. choose an orthagonal view
--for the plane you wish to work on first. top is xz, front is xy, and side is yz. flatten the
--ship to a plane using scale. if youre working on the xz plane you want to flatten by setting
--y to 0%. in other words scale the axis not in plane. then use the poly select tool (with ignore
--backfacing enabled) and select all visible polies and hit del. this leaves a flat cross
--section on the other side that you can measure. open the utilities panel and select measure.
--grab the number from the surface area field. hit undo a few times to restore your model.
--repeat for the other 2 planes.
xy_area = 27.28
xz_area = 104.77
yz_area = 55.09
--drag coefficient
drag_ce = 0.020 --about that of a cessna, more = less streamlined, a brick had a dce of about 2
--lift coefficient
--be careful with lift values, too much will throw you out of the level
lift_ce = 0.06 --a fighter jet uses about 0.3, but this is as high as i dare go more = more lift
--wing area
--sorta guesstimate this, its gonna be a number between 0 and xz_area. more = more lift
wing_area = 95 --the whole ship is a wing

--enviroment specs
--gravitational force per kg
--im using planer gravity right now, but may implement spherical gravity later on
grav_force = 9.78033 --earth grav
--atmospheric pressure kg/m^3
--eventually il throw in barametrics to simulate diferent density at diverent altitudes
atmo_pres = 1.293 --earth atmo at ground level at 0c
--no more physics vars to tweek, maybe more next time

wvel = ba.createVector(0,0,0)

]
$simulation:
[

player = mn.Ships["Alpha 1"]

--first lets do thrust, its longer due to tweaked input code
if player:isValid() then
tvec = ba.createVector(0,0,0)
--tvec.x = player.Physics.SideThrust
--tvec.y = player.Physics.VerticalThrust
tvec.x, tvec.y = mousejoy() --more usefull cause you can set lift to an arbitrary amount
tvec.y = -tvec.y
tvec.z = player.Physics.ForwardThrust

if tvec.x > 0 then
tvec.x = tvec.x * lf_thrust
else
tvec.x = tvec.x * rt_thrust
end

if tvec.y > 0 then
tvec.y = tvec.y * up_thrust
else
tvec.y = tvec.y * dn_thrust
end

if tvec.z > 0 then
tvec.z = tvec.z * fd_thrust
else
tvec.z = tvec.z * rv_thrust
end

tvec = player.Orientation:unrotateVector(tvec) --convert local vector to world space

--first compute some important data
local wvel_len = wvel:getMagnitude()
local wvel_sqrd = wvel_len * wvel_len
if wvel_len > 0 then wvel_len_f = 1 / wvel_len else wvel_len_f = 1 end --avoid div by zero error
local wvel_norm = wvel * wvel_len_f
local wvel_norm_rot = player.Orientation:rotateVector(wvel_norm)

--lets do drag, figure out how much area is hitting the wind
--scale cross sections by components of the normalized, rotated velocity vector
local area = xy_area * math.abs(wvel_norm_rot.z) +
xz_area * math.abs(wvel_norm_rot.y) +
yz_area * math.abs(wvel_norm_rot.x)
--lets plug the drag equasion
local drag = drag_ce * area * 0.5 * atmo_pres * wvel_sqrd
dvec = (wvel_norm * -1) * drag

--now for lift
local lift = lift_ce * wing_area * 0.5 * atmo_pres * wvel_sqrd
lvec = wvel_norm:getCrossProduct(player.Orientation:unrotateVector(ba.createVector(1, 0, 0)))
lvec = lvec * lift

--gravity is really easy
gvec = ba.createVector(0,-grav_force ,0) * shp_mass

--add em up to get our total force vector
fvec = tvec + dvec + lvec + gvec

--factor in mass
local massfactor = 1 / shp_mass
fvec2 = fvec * massfactor

--add to velocity
wvel = wvel + fvec2

--adjust for frametime
local wvel_timescaled = wvel * ba.getFrametime()

--use it
Vx,Vy = (player.Position + wvel):getScreenCoords()
velmag = wvel:getMagnitude()
player.Position = player.Position + wvel_timescaled
player.Physics.Velocity = wvel
end

]
$Hud:
[

if player:isValid() then
gr.setColor(255,0,0,255)
gr.drawString("Thrust:   "..math.ceil(tvec.x).." ' "..math.ceil(tvec.y).." ' "..math.ceil(tvec.z))
gr.setColor(0,255,0,255)
gr.drawString("Drag:     "..math.ceil(dvec.x).." ' "..math.ceil(dvec.y).." ' "..math.ceil(dvec.z))
gr.setColor(0,0,255,255)
gr.drawString("Lift:     "..math.ceil(lvec.x).." ' "..math.ceil(lvec.y).." ' "..math.ceil(lvec.z))
gr.setColor(255,255,0,255)
gr.drawString("Weight:   "..math.ceil(gvec.x).." ' "..math.ceil(gvec.y).." ' "..math.ceil(gvec.z))
gr.setColor(0,255,255,255)
gr.drawString("Total:    "..math.ceil(fvec.x).." ' "..math.ceil(fvec.y).." ' "..math.ceil(fvec.z))
gr.drawCircle(5, io.getMouseX()*wf, io.getMouseY()*hf)
gr.setColor(0,0,0,255)
gr.drawString("Altitude: "..math.ceil(player.Position.y + 50000))
gr.drawString("Airspeed: "..math.ceil(wvel:getMagnitude()))

local X,Y = player.Position:getScreenCoords()
if X then
X,Y=X*wf,Y*hf
local XX,YY = (player.Position + (tvec*0.001)):getScreenCoords()
gr.setColor(255,0,0,255)
if XX then gr.drawLine(X,Y,XX*wf,YY*hf) end
XX,YY = (player.Position + (dvec*0.001)):getScreenCoords()
gr.setColor(0,255,0,255)
if XX then gr.drawLine(X,Y,XX*wf,YY*hf) end
XX,YY = (player.Position + (lvec*0.001)):getScreenCoords()
gr.setColor(0,0,255,255)
if XX then gr.drawLine(X,Y,XX*wf,YY*hf) end
XX,YY = (player.Position + (gvec*0.001)):getScreenCoords()
gr.setColor(255,255,0,255)
if XX then gr.drawLine(X,Y,XX*wf,YY*hf) end
XX,YY = (player.Position + (fvec*0.001)):getScreenCoords()
gr.setColor(255,255,255,255)
if XX then gr.drawLine(X,Y,XX*wf,YY*hf) end
end

if Vx then prograderet( Vx, Vy, round(velmag) ) end
end

]
#End

--- End code ---

WMCoolmon:
It seemed a little weird. I tried using an Orion as a point of reference, and noted collision didn't work. I also had trouble diving - it seemed like I continued getting lift even when I was pointed down.

Also to round a number you should be able to do math.floor(n+0.5)

Very nice though, this could get very interesting. :D

Wanderer:
If you want to keep collision detection working then for heavens sake do not use position data.

Its the exact same reason why i had to implement velocity based barriers to the corridor mode.

Hmmm...
Also is the lift (as a force pointing upwards) 'attenuated' with the ships orientation?
And hmm.. have you given any thoughts about using or setting up terminal velocity (though that would also need to be attenuated with ships orientation...)?

Nuke:
one of the reaons i tweak position data direactl is cause the gamev
--- Quote from: WMCoolmon on December 15, 2007, 03:36:59 am ---It seemed a little weird. I tried using an Orion as a point of reference, and noted collision didn't work. I also had trouble diving - it seemed like I continued getting lift even when I was pointed down.

Also to round a number you should be able to do math.floor(n+0.5)

Very nice though, this could get very interesting. :D

--- End quote ---

that round func is old, most of the timei just use ceil. its probly lrft over from my old newtonian script. i expected colisions to be borked, as im still hacking position data. wvel is a valid replacement velocity though. i just need a way to tell freespace not to screw with my velocity. i tried using the on frame state hook and it worked about the same way. i eventually said **** it, im uncommenting the hack.


--- Quote from: Wanderer on December 15, 2007, 04:10:38 am ---If you want to keep collision detection working then for heavens sake do not use position data.

Its the exact same reason why i had to implement velocity based barriers to the corridor mode.

Hmmm...
Also is the lift (as a force pointing upwards) 'attenuated' with the ships orientation?
And hmm.. have you given any thoughts about using or setting up terminal velocity (though that would also need to be attenuated with ships orientation...)?

--- End quote ---

terminal velocity seems to work as a product of the drag function. the drag force is fairly accurate. it will be even more accurate when i account for barometrics and lift induced drag.

part of the drag equation needs to know how much surface area is exposed to flow. i calculate that by rotating a normalized velocity vector to model space. i use that vector's individual components as scalers. the z axis scales the frontal area, the y axis the top down area, and x scales side area. i sum the result to get a rough approximation of how much surface area the airflow must interact with. drag_ce is the co-efficient, a  magic number which covers all the stuff tht needs t be determined experimentally. but in practice a blunt object has a higher value, small numbers are more streamlined. so a cessna is about 0.028, and a borg cube would be > 1 or more around 2.

this is only a subsonic equation however. for supersonic flight, you need to account for shock forces. should allow an adama manuver at least :D

lift still dont work right. the force is applied in the wrong direction first of all. lift force is apllied along the cross product of velocity and a world space side vector. lift seems to be all over the place. i tried simply multiplying lift by normalized velocity, and flipping z and y. but that didnt work either. im also seeing excessive horizontal component. aoa needs to be accounted for. if you try to fly straight up, instead of stalling, you just sorta hover there and climb slowly, which shouldnt be possible considering how little thrus im using. fighter jets produce thrust in terms oof hundreds of thousands of newtons. a mere 32000 newtons shouldnt be capable of that.  im probibly gonna use a world space velocity normal as a scaler again, seemed to work well for drag.

Wanderer:

--- Quote from: Nuke on December 15, 2007, 05:34:29 am ---one of the reaons i tweak position data direactl is cause the gamev
--- End quote ---
Yes, but still it breaks stuff and there is no way of avoiding it.

Navigation

[0] Message Index

[#] Next page

Go to full version