## Physics question

Game development specific discussions.
BasicCoder2
Posts: 3566
Joined: Jan 01, 2009 7:03
Location: Australia

### Re: Physics question

@dodicat,
My attempts just result in the coffin spinning out of control! Can you get it on target?
So I cheated!!
changed line 258 to make finer adjustments to the direction,

Code: Select all

`        Dim As pt x2=Getline(mx,my,wheel/90,length)`

And inserted these guidelines in the display code,

Code: Select all

`        circle (200,400),5,rgb(255,0,0),,,,f        circle (700,300),5,rgb(0,0,255),,,,f        line (200,400)-(700,300),rgb(255,255,0)       Screenunlock`

I then rotated the red line until it aligned with the yellow line and with one click sent it onto the target.
dodicat
Posts: 6559
Joined: Jan 10, 2006 20:30
Location: Scotland

### Re: Physics question

Thanks for testing, basiccoder2 & badidea.
basiccoder2.
You can make a slightly bigger grave, line 221--Dim As Long roomforerror=10
You could make 15 or something.
But your tweak has been noted, and it would make sense in the real universe for a nice send off.
Thank you.
Posts: 2080
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Physics question

BasicCoder2 wrote:...
Spacecraft can pass through the asteroid belt with virtually no chance of a collision.
...

How about a belt of neutron stars (or at least one):

Code: Select all

`#include "fbgfx.bi"const as single PI = 4 * atn(1)dim shared as single PPM = 2 'pixels per meterconst SW = 800, SH = 600const K_ESC = chr(27)const K_MIN = chr(45)const K_UND = chr(95)const K_PLU = chr(61)const K_EQU = chr(43)screenres SW, SH, 32width SW \ 8, SH \ 16'-------------------------------------------------------------------------------type sgl2d   dim as single x, y   declare constructor   declare constructor(x as single, y as single)   declare operator cast() as stringend typeconstructor sgl2dend constructorconstructor sgl2d(x as single, y as single)   this.x = x : this.y = yend constructoroperator sgl2d.cast () as string   return str(x) & "," & str(y)end operatoroperator +(a as sgl2d, b as sgl2d) as sgl2d   return sgl2d(a.x + b.x, a.y + b.y)end operatoroperator -(a as sgl2d, b as sgl2d) as sgl2d   return sgl2d(a.x - b.x, a.y - b.y)end operatoroperator /(a as sgl2d, div as single) as sgl2d   return sgl2d(a.x / div, a.y / div)end operatoroperator *(a as sgl2d, mul as single) as sgl2d   return sgl2d(a.x * mul, a.y * mul)end operatorfunction cross(a as sgl2d, b as sgl2d) as single   return a.x * b.y - a.y * b.xend functionfunction length(a as sgl2d) as single   return sqr((a.x * a.x) + (a.y * a.y)) end functionfunction lengthSqrd(a as sgl2d) as single   return (a.x * a.x) + (a.y * a.y) end functionfunction dist(a as sgl2d, b as sgl2d) as single   dim as single dx = a.x - b.x   dim as single dy = a.y - b.y   return sqr((dx * dx) + (dy * dy)) end functionfunction distSqrd(a as sgl2d, b as sgl2d) as single   dim as single dx = a.x - b.x   dim as single dy = a.y - b.y   return (dx * dx) + (dy * dy) end function'-------------------------------------------------------------------------------type polar   dim as single angle   dim as single magnitudeend typefunction polarToCartesian(angle as single, radius as single) as sgl2d   return sgl2d(cos(angle) * radius, sin(angle) * radius)end functionfunction degToRad(degrees as single) as single   return (degrees / 180) * PIend functionfunction rotatedVector(v as sgl2d, rotAngle as single) as sgl2d   dim as sgl2d tmp   tmp.x = cos(rotAngle) * v.x - sin(rotAngle) * v.y   tmp.y = sin(rotAngle) * v.x + cos(rotAngle) * v.y   return tmpend functionsub clearScreen(c as ulong)   line(0, 0)-(SW - 1, SH - 1), c, bfend sub'scaled circle using PPM, y-axis pointing up, center = 0, 0sub drawCircle(p as sgl2d, r as single, c as ulong)   circle(SW \ 2 + p.x * PPM, SH \ 2 - p.y * PPM), r * PPM, cend sub'scaled line using PPM, y-axis pointing up, center = 0, 0sub drawLine(p1 as sgl2d, p2 as sgl2d, c as ulong)   line(SW \ 2 + p1.x * PPM, SH \ 2 - p1.y * PPM)-_      (SW \ 2 + p2.x * PPM, SH \ 2 - p2.y * PPM), cend subsub drawArrow(p1 as sgl2d, p2 as sgl2d, c as ulong)   drawLine(p1, p2, c)   dim as sgl2d posVector = p2 - p1   posVector /= 3 '1/3 length   drawLine(p1, p1 + rotatedVector(posVector, degToRad(+30)), c)   drawLine(p1, p1 + rotatedVector(posVector, degToRad(-30)), c)end sub'-------------------------------------------------------------------------------type disc_object   dim as single radius '[m]   dim as single height '[m]   dim as single density '[kg/m^3]   dim as ulong colour '[m]   'linear motion properties   dim as sgl2d position 'position [m]   dim as single lin_m 'mass [kg]   dim as sgl2d lin_F 'force [N] [kg*m/s^2]   dim as sgl2d lin_a 'acceleration [m/s^2]   dim as sgl2d lin_v 'velocity [m/s]   'dim as sgl2d lin_p 'momentum [kg*m/s]   'dim as single lin_E 'Kinetic energy [J] [kg*m^2/s^2]   'Rotational motion properties   dim as single angle 'angular position (theta) [rad]   dim as single ang_m 'angular mass, moment of inertia (I) [kg*m^2]   dim as single ang_F 'torque (tau) [N*m] [kg*m^2/s^2]   dim as single ang_a 'angular velocity (alpha) [rad/s^2]   dim as single ang_v 'angular velocity (omega) [rad/s]   'dim as single ang_p 'angular momentum (L) [kg*m^2/s]   'dim as single ang_E 'Kinetic energy [J] [kg*m^2/s^2]   '   declare sub init(r as single, h as single, d as single, p as sgl2d, c as ulong)   declare sub update(dt as double)   declare function getKineticEnergy() as singleend type'Set radius, height, density, position'Calculate mass and rotational inertiasub disc_object.init(r as single, h as single, d as single, p as sgl2d, c as ulong)   radius = r   height = h   density = d   position = p   colour = c   lin_m = PI * r ^ 2 * d   ang_m = 0.5 * lin_m * r ^ 2end sub'update position and anglesub disc_object.update(dt as double)   lin_a = lin_F / lin_m   lin_v += lin_a * dt   position += lin_v * dt   ang_a = ang_F / ang_m   ang_v += ang_a * dt   angle += ang_v * dtend subfunction disc_object.getKineticEnergy() as single   dim as single lin_E = 0.5 * lin_m * lengthSqrd(lin_v)   dim as single ang_E = 0.5 * ang_m * ang_v * ang_v   return lin_E + ang_Eend function'-------------------------------------------------------------------------------type thruster_type   '''init paramaters   dim as polar polarForce '(rad, N)   dim as polar polarPos '(rad, m)   '''variable paramaters   dim as sgl2d forceVector '(N, N)   dim as sgl2d relPos, absPos '(m, m)   dim as integer active   declare sub init(forceMagnitude as single, forceDirection as single, posAngle as single, posRadius as single)   declare sub updatePosition(bodyPos as sgl2d, bodyAngle as single)end typesub thruster_type.init(forceDirection as single, forceMagnitude as single, posAngle as single, posRadius as single)   polarForce = type(forceDirection, forceMagnitude) 'thruster action   polarPos = type(posAngle, posRadius) 'position of thruster on shipend subsub thruster_type.updatePosition(bodyPos as sgl2d, bodyAngle as single)   relPos = polarToCartesian(bodyAngle + polarPos.angle, polarPos.magnitude)   absPos = bodyPos + relPosend sub'-------------------------------------------------------------------------------const as single GRAV_CONST = 6.67e-11 '[m3/(kg*s^2)type astro_body   dim as single radius '[m]   dim as single density '[kg/m^3]   dim as ulong colour '[m]   dim as sgl2d position 'position [m]   dim as single mass '[kg]   declare sub init(r as single, d as single, p as sgl2d, c as ulong)end type'Set radius, density, position'Calculate mass and rotational inertiasub astro_body.init(r as single, d as single, p as sgl2d, c as ulong)   radius = r   density = d   position = p   colour = c   mass = PI * r ^ 2 * dend subfunction gravForce(m1 as single, m2 as single, r as single) as single   return GRAV_CONST * (m1 * m2) / (r * r)end functionfunction gravForceVector(m1 as single, pos1 as sgl2d, m2 as single, pos2 as sgl2d) as sgl2d   'https://en.wikipedia.org/wiki/Newton%27s_law_of_universal_gravitation#Vector_form   dim as single distSquared = distSqrd(pos2, pos1)   dim as sgl2d unitVector12 = (pos1 - pos2) / sqr(distSquared)   return unitVector12 * (-GRAV_CONST * (m1 * m2) / distSquared)end function'-------------------------------------------------------------------------------const as single MOON_RADIUS = 1737e+6 '[m]const as single MOON_DENSITY = 3344 '[kg/m^3]const NUM_THRUSTERS = 6const L_FW_THR = 0 'left forward thrusterconst R_FW_THR = 1 'right forward thrusterconst L_LO_THR = 2const R_LO_THR = 3const L_HI_THR = 4const R_HI_THR = 5dim as string keydim as integer quit = 0dim as disc_object discdim as thruster_type thruster(NUM_THRUSTERS - 1)dim as astro_body moon, neutronstar'moon.init(MOON_RADIUS, MOON_DENSITY, sgl2d(+40, +20), rgb(255, 127, 0))neutronstar.init(MOON_RADIUS * 1e-8, MOON_DENSITY * 1e8, sgl2d(+40, +20), rgb(255, 127, 0))disc.init(10, 1, 5, sgl2d(0, -50), rgb(127, 255, 0))'force angle, force magnitude, polar thruster position thruster(L_FW_THR).init(0.5 * pi, 1e4, -0.75 * pi, disc.radius)thruster(R_FW_THR).init(0.5 * pi, 1e4, -0.25 * pi, disc.radius)thruster(L_LO_THR).init(0.0 * pi, 5e3, -0.75 * pi, disc.radius)thruster(R_LO_THR).init(1.0 * pi, 5e3, -0.25 * pi, disc.radius)thruster(L_HI_THR).init(0.0 * pi, 5e3, +0.75 * pi, disc.radius)thruster(R_HI_THR).init(1.0 * pi, 5e3, +0.25 * pi, disc.radius)dim as double tNow = timer, tPrev = tNow, dt = 0while quit = 0   'reset stuff   disc.lin_F = sgl2d(0, 0)   disc.ang_F = 0   for i as integer = 0 to NUM_THRUSTERS - 1      thruster(i).active = 0   next   'do always for display   for i as integer = 0 to NUM_THRUSTERS - 1      thruster(i).updatePosition(disc.position, disc.angle)   next   if multikey(FB.SC_UP) then      thruster(L_FW_THR).active = 1      thruster(R_FW_THR).active = 1   end if   if multikey(FB.SC_LEFT) then      thruster(L_LO_THR).active = 1      thruster(R_HI_THR).active = 1   end if   if multikey(FB.SC_RIGHT) then      thruster(R_LO_THR).active = 1      thruster(L_HI_THR).active = 1   end if   if key = K_MIN or key = K_UND then ppm /= 1.1 'zoom out   if key = K_PLU or key = K_EQU then ppm *= 1.1 'zoom in   if key = K_ESC then quit = 1   for i as integer = 0 to NUM_THRUSTERS - 1      'forces on body by active thrusters      if thruster(i).active = 1 then         thruster(i).forceVector = polarToCartesian(disc.angle + thruster(i).polarForce.angle, thruster(i).polarForce.magnitude)         disc.lin_F += thruster(i).forceVector         disc.ang_F += cross(thruster(i).relPos, thruster(i).forceVector)      end if   next   disc.lin_F += gravForceVector(disc.lin_m, disc.position, neutronstar.mass, neutronstar.position)   if dist(disc.position, neutronstar.position) < (disc.radius + neutronstar.radius) then quit = 2 'crashed      disc.update(dt)      'display   screenlock   clearScreen(0)   locate 2, 2 : print "<UP>, <LEFT>, <RIGHT> for thrusters";   locate 3, 2 : print "<+>, <-> for zoom in/out";   locate 4, 2 : print "<ESC> to exit";   locate 5, 2 : print "Kinetic engergy [J]: "; disc.getKineticEnergy();   'locate 6, 2 : print str(cint(length(disc.position)))   drawCircle(disc.position, disc.radius, disc.colour) 'flying saucer   drawArrow(disc.position + disc.lin_v / 1, disc.position, rgb(255, 0, 127)) 'lin. speed ind.   drawArrow(disc.position + disc.lin_F / 1e3, disc.position, rgb(0, 127, 255)) 'lin. speed ind.   for i as integer = 0 to NUM_THRUSTERS - 1      dim as ulong c = iif(i < 4, rgb(255, 255, 0), rgb(255, 255, 255))      drawLine(disc.position, thruster(i).absPos, c) 'rotation indicator      if thruster(i).active = 1 then         drawArrow(thruster(i).absPos, thruster(i).absPos - thruster(i).forceVector / 1e3, rgb(255, 127, 0)) 'thruster force indicator      end if   next   drawCircle(neutronstar.position, neutronstar.radius, neutronstar.colour) 'flying saucer   screenunlock   'time update   key = inkey()   sleep 1   tPrev = tNow   tNow = timer   dt = tNow - tPrevwendlocate 8, 2: print iif(quit = 2, "You crashed into the neutron star", "User quit request") + " (wait 3 sec)"sleep 3000, 1screen 0print "End"`
h4tt3n
Posts: 694
Joined: Oct 22, 2005 21:12
Location: Denmark

### Re: Physics question

Oh man, this is just my kind of thread :-) Awesome to come back to the forums after a long break to see you guys hard at work making cool stuff!

I have made loads of space physics doodle stuff just like this in the past few years, just gimme a bit of time and I'll dig out some stuff that is definitely useful...
Posts: 2080
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Physics question

This starts to look like a ship between asteroids:

Code: Select all

`#Include "fbgfx.bi"Type int2d   As Integer x, y   Declare Constructor   Declare Constructor(x As Integer, y As Integer)   Declare Operator Cast () As StringEnd TypeConstructor int2dEnd ConstructorConstructor int2d(x As Integer, y As Integer)   This.x = x : This.y = yEnd ConstructorOperator = (a As int2d, b As int2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd OperatorOperator <> (a As int2d, b As int2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' "x, y"Operator int2d.cast () As String  Return Str(x) & "," & Str(y)End Operator' a + b Operator + (a As int2d, b As int2d) As int2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As int2d, b As int2d) As int2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As int2d) As int2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As int2d, b As int2d) As int2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As int2d, mul As Integer) As int2d   Return Type(a.x * mul, a.y * mul)End Operator' a \ bOperator \ (a As int2d, b As int2d) As int2d   Return Type(a.x \ b.x, a.y \ b.y)End Operator' a \ divOperator \ (a As int2d, div As Integer) As int2d   Return Type(a.x \ div, a.y \ div)End Operator'===============================================================================Type sgl2d   As Single x, y   Declare Constructor   Declare Constructor(x As Single, y As Single)   Declare Operator Cast () As StringEnd TypeConstructor sgl2dEnd ConstructorConstructor sgl2d(x As Single, y As Single)   This.x = x : This.y = yEnd Constructor' "x, y"Operator sgl2d.cast () As String   Return Str(x) & "," & Str(y)End Operator'---- operators ---' distance / lenthOperator Len (a As sgl2d) As Single   Return Sqr(a.x * a.x + a.y * a.y)End Operator' a = b ?Operator = (a As sgl2d, b As sgl2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd Operator' a != b ?Operator <> (a As sgl2d, b As sgl2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' a + b Operator + (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As sgl2d) As sgl2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As sgl2d, mul As Single) As sgl2d   Return Type(a.x * mul, a.y * mul)End Operator' a / divOperator / (a As sgl2d, div As Single) As sgl2d   Return Type(a.x / div, a.y / div)End Operator'---- extra functions ---Function cross(a As sgl2d, b As sgl2d) As Single   Return a.x * b.y - a.y * b.xEnd FunctionFunction length(a As sgl2d) As Single   Return Sqr((a.x * a.x) + (a.y * a.y)) End FunctionFunction lengthSqrd(a As sgl2d) As Single   Return (a.x * a.x) + (a.y * a.y) End FunctionFunction dist(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return Sqr((dx * dx) + (dy * dy)) End FunctionFunction distSqrd(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return (dx * dx) + (dy * dy) End Function'==============================================================================='Note: y+ = up, x+ = right, (0,0) = centerType scaled_graphics_type   Dim As Single scale = 1 ' = 1 / pixel_size 'pixels / meter   'dim as int2d offset' = (scrn_w \ 2, h \ 2) 'offset in pixels   Dim As sgl2d offset   Dim As Integer w = -1, h = -1   Dim As Integer wc = -1, hc = -1 'center x,y   Declare Sub setScreen(w As Integer, h As Integer)   Declare Sub setScaling(scale As Single, offset As sgl2d)   Declare Sub clearScreen(c As ULong)   Declare Function pos2screen(p As sgl2d) As int2d   Declare Sub drawPixel(p As sgl2d, c As Integer)   Declare Sub drawCircle(p As sgl2d, r As Single, c As Integer)   Declare Sub drawLine(p1 As sgl2d, p2 As sgl2d, c As Integer)End TypeSub scaled_graphics_type.setScreen(w As Integer, h As Integer)   This.w = w 'width   This.h = h 'height   wc = w \ 2   hc = h \ 2   ScreenRes w, h, 32   Width w \ 8, h \ 16 'bigger fontEnd SubSub scaled_graphics_type.setScaling(scale As Single, offset As sgl2d)   This.scale = scale   This.offset = offsetEnd SubSub scaled_graphics_type.clearScreen(c As ULong)   Line(0, 0)-(w - 1, h - 1), c, bfEnd SubFunction scaled_graphics_type.pos2screen(p As sgl2d) As int2d   Return int2d(Int(wc + (p.x - offset.x) * scale), h - Int(hc + (p.y - offset.y) * scale))End FunctionSub scaled_graphics_type.drawPixel(p As sgl2d, c As Integer)   Dim As int2d posScrn = pos2screen(p)   PSet(posScrn.x, posScrn.y), cEnd SubSub scaled_graphics_type.drawCircle(p As sgl2d, r As Single, c As Integer)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, cEnd SubSub scaled_graphics_type.drawLine(p1 As sgl2d, p2 As sgl2d, c As Integer)   Dim As int2d posScrn1 = pos2screen(p1)   Dim As int2d posScrn2 = pos2screen(p2)   Line(posScrn1.x, posScrn1.y)-(posScrn2.x, posScrn2.y), cEnd Sub'===============================================================================Const As Single PI = 4 * Atn(1)Const As Single sinA = Sin((10 / 180) * PI)Const As Single cosA = Cos((10 / 180) * PI)Const K_ESC = Chr(27)Const K_MIN = Chr(45)Const K_UND = Chr(95)Const K_PLU = Chr(61)Const K_EQU = Chr(43)Const SCRN_W = 800, SCRN_H = 600Dim Shared As scaled_graphics_type sgsg.setScaling(2.0, sgl2d(0, 0))sg.setScreen(SCRN_W, SCRN_H)'-------------------------------------------------------------------------------Type polar   Dim As Single angle   Dim As Single magnitudeEnd TypeFunction polarToCartesian(angle As Single, radius As Single) As sgl2d   Return sgl2d(Cos(angle) * radius, Sin(angle) * radius)End FunctionFunction degToRad(degrees As Single) As Single   Return (degrees / 180) * PIEnd FunctionFunction rotatedVector(v As sgl2d, rotAngle As Single) As sgl2d   Dim As sgl2d tmp   tmp.x = Cos(rotAngle) * v.x - Sin(rotAngle) * v.y   tmp.y = Sin(rotAngle) * v.x + Cos(rotAngle) * v.y   Return tmpEnd Function'-------------------------------------------------------------------------------Sub drawArrow(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.95 'reduce length   'sg.drawLine(p1, p1 + rotatedVector(dp, degToRad(+30)), c)   'sg.drawLine(p1, p1 + rotatedVector(dp, degToRad(-30)), c)   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x - sinA * dp.y, sinA * dp.x + cosA * dp.y), c)   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x + sinA * dp.y, cosA * dp.y - sinA * dp.x), c)End Sub'-------------------------------------------------------------------------------Type disc_object   Dim As Single radius '[m]   Dim As Single height '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   'linear motion properties   Dim As sgl2d position 'position [m]   Dim As Single lin_m 'mass [kg]   Dim As sgl2d lin_F 'force [N] [kg*m/s^2]   Dim As sgl2d lin_a 'acceleration [m/s^2]   Dim As sgl2d lin_v 'velocity [m/s]   'dim as sgl2d lin_p 'momentum [kg*m/s]   'dim as single lin_E 'Kinetic energy [J] [kg*m^2/s^2]   'Rotational motion properties   Dim As Single angle 'angular position (theta) [rad]   Dim As Single ang_m 'angular mass, moment of inertia (I) [kg*m^2]   Dim As Single ang_F 'torque (tau) [N*m] [kg*m^2/s^2]   Dim As Single ang_a 'angular velocity (alpha) [rad/s^2]   Dim As Single ang_v 'angular velocity (omega) [rad/s]   'dim as single ang_p 'angular momentum (L) [kg*m^2/s]   'dim as single ang_E 'Kinetic energy [J] [kg*m^2/s^2]   '   Declare Sub init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   Declare Sub update(dt As Double)   Declare Function getKineticEnergy() As SingleEnd Type'Set radius, height, density, position'Calculate mass and rotational inertiaSub disc_object.init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   radius = r   height = h   density = d   position = p   colour = c   lin_m = PI * r ^ 2 * d   ang_m = 0.5 * lin_m * r ^ 2End Sub'update position and angleSub disc_object.update(dt As Double)   lin_a = lin_F / lin_m   lin_v += lin_a * dt   position += lin_v * dt   ang_a = ang_F / ang_m   ang_v += ang_a * dt   angle += ang_v * dtEnd SubFunction disc_object.getKineticEnergy() As Single   Dim As Single lin_E = 0.5 * lin_m * lengthSqrd(lin_v)   Dim As Single ang_E = 0.5 * ang_m * ang_v * ang_v   Return lin_E + ang_EEnd Function'-------------------------------------------------------------------------------Type thruster_type   '''init paramaters   Dim As polar polarForce '(rad, N)   Dim As polar polarPos '(rad, m)   '''variable paramaters   Dim As sgl2d forceVector '(N, N)   Dim As sgl2d relPos, absPos '(m, m)   Dim As Integer active   Declare Sub init(forceMagnitude As Single, forceDirection As Single, posAngle As Single, posRadius As Single)   Declare Sub updatePosition(bodyPos As sgl2d, bodyAngle As Single)End TypeSub thruster_type.init(forceDirection As Single, forceMagnitude As Single, posAngle As Single, posRadius As Single)   polarForce = Type(forceDirection, forceMagnitude) 'thruster action   polarPos = Type(posAngle, posRadius) 'position of thruster on shipEnd SubSub thruster_type.updatePosition(bodyPos As sgl2d, bodyAngle As Single)   relPos = polarToCartesian(bodyAngle + polarPos.angle, polarPos.magnitude)   absPos = bodyPos + relPosEnd Sub'-------------------------------------------------------------------------------Const As Single GRAV_CONST = 6.67e-11 '[m3/(kg*s^2)Type astro_body   Dim As Single radius '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   Dim As sgl2d position 'position [m]   Dim As Single mass '[kg]   Declare Sub init(r As Single, d As Single, p As sgl2d, c As ULong)End Type'Set radius, density, position'Calculate mass and rotational inertiaSub astro_body.init(r As Single, d As Single, p As sgl2d, c As ULong)   radius = r   density = d   position = p   colour = c   mass = PI * r ^ 2 * dEnd SubFunction gravForce(m1 As Single, m2 As Single, r As Single) As Single   Return GRAV_CONST * (m1 * m2) / (r * r)End FunctionFunction gravForceVector(m1 As Single, Pos1 As sgl2d, m2 As Single, pos2 As sgl2d) As sgl2d   'https://en.wikipedia.org/wiki/Newton%27s_law_of_universal_gravitation#Vector_form   Dim As Single distSquared = distSqrd(pos2, Pos1)   Dim As sgl2d unitVector12 = (Pos1 - pos2) / Sqr(distSquared)   Return unitVector12 * (-GRAV_CONST * (m1 * m2) / distSquared)End Function'-------------------------------------------------------------------------------Const As Single MOON_RADIUS = 1737e+6 '[m]Const As Single MOON_DENSITY = 3344 '[kg/m^3]Const NUM_THRUSTERS = 6Const L_FW_THR = 0 'left forward thrusterConst R_FW_THR = 1 'right forward thrusterConst L_LO_THR = 2Const R_LO_THR = 3Const L_HI_THR = 4Const R_HI_THR = 5Dim As String keyDim As Integer quit = 0Dim As disc_object discDim As thruster_type thruster(NUM_THRUSTERS - 1)'dim as astro_body moon, neutronstarConst NUM_ASTROID = 100Dim As astro_body astroid(NUM_ASTROID-1)'moon.init(MOON_RADIUS, MOON_DENSITY, sgl2d(+40, +20), rgb(255, 127, 0))'neutronstar.init(MOON_RADIUS * 1e-8, MOON_DENSITY * 1e8, sgl2d(+40, +20), rgb(255, 127, 0))disc.init(10, 1, 5, sgl2d(0, -50), RGB(127, 255, 0))For i As Integer = 0 To UBound(astroid)   astroid(i).init(10, 1000, sgl2d((Rnd - 0.5) * 2000, (Rnd - 0.5) * 2000), RGB(255, 127, 0))Next'force angle, force magnitude, polar thruster position thruster(L_FW_THR).init(0.5 * pi, 1.2e4, -0.75 * pi, disc.radius)thruster(R_FW_THR).init(0.5 * pi, 1.2e4, -0.25 * pi, disc.radius)thruster(L_LO_THR).init(0.0 * pi, 8e3, -0.75 * pi, disc.radius)thruster(R_LO_THR).init(1.0 * pi, 8e3, -0.25 * pi, disc.radius)thruster(L_HI_THR).init(0.0 * pi, 8e3, +0.75 * pi, disc.radius)thruster(R_HI_THR).init(1.0 * pi, 8e3, +0.25 * pi, disc.radius)Dim As Double tNow = Timer, tPrev = tNow, dt = 0While quit = 0   'reset stuff   disc.lin_F = sgl2d(0, 0)   disc.ang_F = 0   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).active = 0   Next   'do always for display   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).updatePosition(disc.position, disc.angle)   Next   If MultiKey(FB.SC_UP) Then      thruster(L_FW_THR).active = 1      thruster(R_FW_THR).active = 1   End If   If MultiKey(FB.SC_LEFT) Then      thruster(L_LO_THR).active = 1      thruster(R_HI_THR).active = 1   End If   If MultiKey(FB.SC_RIGHT) Then      thruster(R_LO_THR).active = 1      thruster(L_HI_THR).active = 1   End If   'If key = K_MIN Or key = K_UND Then sg.scale /= 1.1 'zoom out   'If key = K_PLU Or key = K_EQU Then sg.scale *= 1.1 'zoom in   If key = K_ESC Then quit = 1   For i As Integer = 0 To NUM_THRUSTERS - 1      'forces on body by active thrusters      If thruster(i).active = 1 Then         thruster(i).forceVector = polarToCartesian(disc.angle + thruster(i).polarForce.angle, thruster(i).polarForce.magnitude)         disc.lin_F += thruster(i).forceVector         disc.ang_F += cross(thruster(i).relPos, thruster(i).forceVector)      End If   Next   'disc.lin_F += gravForceVector(disc.lin_m, disc.position, neutronstar.mass, neutronstar.position)   'if dist(disc.position, neutronstar.position) < (disc.radius + neutronstar.radius) then quit = 2 'crashed      disc.update(dt)   'X_C = -disc.position.x   'Y_C = disc.position.y   'sg.offset = int2d(cint(disc.position.x), cint(disc.position.y))   sg.offset = disc.position   Dim As Single ppm = 100 / Len(disc.lin_v)   If ppm < 0.5 Then ppm = 0.5   If ppm > 2.0 Then ppm = 2.0   sg.scale = ppm   'calculate ship direction pointer / triangle   Dim As Single forwardAngle = disc.angle - PI/2   Dim As Single leftBackAngle = forwardAngle + degToRad(135)   Dim As Single rightBackAngle = forwardAngle - degToRad(135)   Dim As sgl2d forwardPos = sgl2d(Cos(forwardAngle), Sin(forwardAngle)) * (disc.radius * 2.2)   Dim As sgl2d leftBackPos = sgl2d(Cos(leftBackAngle), Sin(leftBackAngle)) * (disc.radius * 1.1)   Dim As sgl2d rightBackPos = sgl2d(Cos(rightBackAngle), Sin(rightBackAngle)) * (disc.radius * 1.1)       'display   ScreenLock   sg.clearScreen(0)   Locate 2, 2 : Print "<UP>, <LEFT>, <RIGHT> for thrusters";   'Locate 3, 2 : Print "<+>, <-> for zoom in/out";   Locate 4, 2 : Print "<ESC> to exit";   Locate 5, 2 : Print "Kinetic engergy [J]: "; disc.getKineticEnergy();   Locate 6, 2 : Print "ppm: "; ppm   'draw ship      sg.drawCircle(disc.position, disc.radius, disc.colour) 'flying saucer   sg.drawLine(disc.position - forwardPos, disc.position - leftBackPos, disc.colour)   sg.drawLine(disc.position - forwardPos, disc.position - rightBackPos, disc.colour)   sg.drawLine(disc.position - leftBackPos, disc.position - rightBackPos, disc.colour)   'drawArrow(disc.position + disc.lin_v / 1, disc.position, rgb(255, 0, 127)) 'lin. speed ind.   'drawArrow(disc.position + disc.lin_F / 1e3, disc.position, rgb(0, 127, 255)) 'lin. speed ind.   For i As Integer = 0 To NUM_THRUSTERS - 1      Dim As ULong c = IIf(i < 4, RGB(255, 255, 0), RGB(255, 255, 255))      'sg.drawLine(disc.position, thruster(i).absPos, c) 'rotation indicator      If thruster(i).active = 1 Then         drawArrow(thruster(i).absPos, thruster(i).absPos - thruster(i).forceVector / 1e3, RGB(255, 127, 0)) 'thruster force indicator      End If   Next   'drawCircle(neutronstar.position, neutronstar.radius, neutronstar.colour) 'flying saucer   For i As Integer = 0 To UBound(astroid)      sg.drawCircle(astroid(i).position, astroid(i).radius, astroid(i).colour)   Next   ScreenUnLock   'time update   key = InKey()   Sleep 1   tPrev = tNow   tNow = Timer   dt = tNow - tPrevWend'locate 8, 2: print iif(quit = 2, "You crashed into the neutron star", "User quit request") + " (wait 3 sec)"'sleep 300, 1Screen 0Print "End"'TODO:'center of universe indicator?'nearest object indicator + distance'better looking ship'drawElipse`

Ship centered view, and view scaling with speed.
No collisions, space battles or death stars yet.
Posts: 2080
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Physics question

'Improved' ship design with a nearest asteroid indicator:

Code: Select all

`#Include "fbgfx.bi"Type int2d   As Integer x, y   Declare Constructor   Declare Constructor(x As Integer, y As Integer)   Declare Operator Cast () As StringEnd TypeConstructor int2dEnd ConstructorConstructor int2d(x As Integer, y As Integer)   This.x = x : This.y = yEnd ConstructorOperator = (a As int2d, b As int2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd OperatorOperator <> (a As int2d, b As int2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' "x, y"Operator int2d.cast () As String  Return Str(x) & "," & Str(y)End Operator' a + b Operator + (a As int2d, b As int2d) As int2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As int2d, b As int2d) As int2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As int2d) As int2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As int2d, b As int2d) As int2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As int2d, mul As Integer) As int2d   Return Type(a.x * mul, a.y * mul)End Operator' a \ bOperator \ (a As int2d, b As int2d) As int2d   Return Type(a.x \ b.x, a.y \ b.y)End Operator' a \ divOperator \ (a As int2d, div As Integer) As int2d   Return Type(a.x \ div, a.y \ div)End Operator'===============================================================================Type sgl2d   As Single x, y   Declare Constructor   Declare Constructor(x As Single, y As Single)   Declare Operator Cast () As StringEnd TypeConstructor sgl2dEnd ConstructorConstructor sgl2d(x As Single, y As Single)   This.x = x : This.y = yEnd Constructor' "x, y"Operator sgl2d.cast () As String   Return Str(x) & "," & Str(y)End Operator'---- operators ---' distance / lenthOperator Len (a As sgl2d) As Single   Return Sqr(a.x * a.x + a.y * a.y)End Operator' a = b ?Operator = (a As sgl2d, b As sgl2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd Operator' a != b ?Operator <> (a As sgl2d, b As sgl2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' a + b Operator + (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As sgl2d) As sgl2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As sgl2d, mul As Single) As sgl2d   Return Type(a.x * mul, a.y * mul)End Operator' a / divOperator / (a As sgl2d, div As Single) As sgl2d   Return Type(a.x / div, a.y / div)End Operator'---- extra functions ---Function cross(a As sgl2d, b As sgl2d) As Single   Return a.x * b.y - a.y * b.xEnd FunctionFunction lengthSqrd(a As sgl2d) As Single   Return (a.x * a.x) + (a.y * a.y) End FunctionFunction dist(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return Sqr((dx * dx) + (dy * dy)) End FunctionFunction distSqrd(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return (dx * dx) + (dy * dy) End FunctionFunction normalise(a As sgl2d) As sgl2d   Dim As sgl2d temp   Dim As Single length = Len(a)   Return sgl2d(a.x / length, a.y / length)End Function'==============================================================================='Note: y+ = up, x+ = right, (0,0) = centerType scaled_graphics_type   Dim As Single scale = 1 ' = 1 / pixel_size 'pixels / meter   'dim as int2d offset' = (scrn_w \ 2, h \ 2) 'offset in pixels   Dim As sgl2d offset   Dim As Integer w = -1, h = -1   Dim As Integer wc = -1, hc = -1 'center x,y   Declare Sub setScreen(w As Integer, h As Integer)   Declare Sub setScaling(scale As Single, offset As sgl2d)   Declare Sub clearScreen(c As ULong)   Declare Function pos2screen(p As sgl2d) As int2d   Declare Sub drawPixel(p As sgl2d, c As Integer)   Declare Sub drawCircle(p As sgl2d, r As Single, c As Integer)   Declare Sub drawLine(p1 As sgl2d, p2 As sgl2d, c As Integer)End TypeSub scaled_graphics_type.setScreen(w As Integer, h As Integer)   This.w = w 'width   This.h = h 'height   wc = w \ 2   hc = h \ 2   ScreenRes w, h, 32   Width w \ 8, h \ 16 'bigger fontEnd SubSub scaled_graphics_type.setScaling(scale As Single, offset As sgl2d)   This.scale = scale   This.offset = offsetEnd SubSub scaled_graphics_type.clearScreen(c As ULong)   Line(0, 0)-(w - 1, h - 1), c, bfEnd SubFunction scaled_graphics_type.pos2screen(p As sgl2d) As int2d   Return int2d(Int(wc + (p.x - offset.x) * scale), h - Int(hc + (p.y - offset.y) * scale))End FunctionSub scaled_graphics_type.drawPixel(p As sgl2d, c As Integer)   Dim As int2d posScrn = pos2screen(p)   PSet(posScrn.x, posScrn.y), cEnd SubSub scaled_graphics_type.drawCircle(p As sgl2d, r As Single, c As Integer)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, cEnd SubSub scaled_graphics_type.drawLine(p1 As sgl2d, p2 As sgl2d, c As Integer)   Dim As int2d posScrn1 = pos2screen(p1)   Dim As int2d posScrn2 = pos2screen(p2)   Line(posScrn1.x, posScrn1.y)-(posScrn2.x, posScrn2.y), cEnd Sub'===============================================================================Const As Single PI = 4 * Atn(1)Const As Single RAD_PER_DEG = (PI / 180)Const As Single DEG_PER_RAD = 180 / PIConst As Single sinA = Sin((10 / 180) * PI)Const As Single cosA = Cos((10 / 180) * PI)Const As Single sinB = Sin((20 / 180) * PI)Const As Single cosB = Cos((20 / 180) * PI)Const K_ESC = Chr(27)Const K_MIN = Chr(45)Const K_UND = Chr(95)Const K_PLU = Chr(61)Const K_EQU = Chr(43)Const SCRN_W = 800, SCRN_H = 600Dim Shared As scaled_graphics_type sgsg.setScaling(2.0, sgl2d(0, 0))sg.setScreen(SCRN_W, SCRN_H)'-------------------------------------------------------------------------------Function limit(value As Single, min As Single, max As Single) As Single   If value < min Then Return min   If value > max Then Return max   Return valueEnd FunctionType polar   Dim As Single angle   Dim As Single magnitudeEnd TypeFunction polarToCartesian(angle As Single, radius As Single) As sgl2d   Return sgl2d(Cos(angle) * radius, Sin(angle) * radius)End FunctionFunction rotatedVector(v As sgl2d, rotAngle As Single) As sgl2d   Dim As sgl2d tmp   tmp.x = Cos(rotAngle) * v.x - Sin(rotAngle) * v.y   tmp.y = Sin(rotAngle) * v.x + Cos(rotAngle) * v.y   Return tmpEnd Function'-------------------------------------------------------------------------------Sub drawArrow(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.30 'reduce length   sg.drawLine(p2, p2 - sgl2d(cosB * dp.x - sinB * dp.y, sinB * dp.x + cosB * dp.y), c)   sg.drawLine(p2, p2 - sgl2d(cosB * dp.x + sinB * dp.y, cosB * dp.y - sinB * dp.x), c)End SubSub drawThruster(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.95 'reduce length   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x - sinA * dp.y, sinA * dp.x + cosA * dp.y), c)   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x + sinA * dp.y, cosA * dp.y - sinA * dp.x), c)End Sub'-------------------------------------------------------------------------------Type disc_object   Dim As Single radius '[m]   Dim As Single height '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   'linear motion properties   Dim As sgl2d position 'position [m]   Dim As Single lin_m 'mass [kg]   Dim As sgl2d lin_F 'force [N] [kg*m/s^2]   Dim As sgl2d lin_a 'acceleration [m/s^2]   Dim As sgl2d lin_v 'velocity [m/s]   'dim as sgl2d lin_p 'momentum [kg*m/s]   'dim as single lin_E 'Kinetic energy [J] [kg*m^2/s^2]   'Rotational motion properties   Dim As Single angle 'angular position (theta) [rad]   Dim As Single ang_m 'angular mass, moment of inertia (I) [kg*m^2]   Dim As Single ang_F 'torque (tau) [N*m] [kg*m^2/s^2]   Dim As Single ang_a 'angular velocity (alpha) [rad/s^2]   Dim As Single ang_v 'angular velocity (omega) [rad/s]   'dim as single ang_p 'angular momentum (L) [kg*m^2/s]   'dim as single ang_E 'Kinetic energy [J] [kg*m^2/s^2]   Declare Sub init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   Declare Sub update(dt As Double)   Declare Function getKineticEnergy() As SingleEnd Type'Set radius, height, density, position'Calculate mass and rotational inertiaSub disc_object.init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   radius = r   height = h   density = d   position = p   colour = c   lin_m = PI * r ^ 2 * d   ang_m = 0.5 * lin_m * r ^ 2End Sub'update position and angleSub disc_object.update(dt As Double)   lin_a = lin_F / lin_m   lin_v += lin_a * dt   position += lin_v * dt   ang_a = ang_F / ang_m   ang_v += ang_a * dt   angle += ang_v * dtEnd SubFunction disc_object.getKineticEnergy() As Single   Dim As Single lin_E = 0.5 * lin_m * lengthSqrd(lin_v)   Dim As Single ang_E = 0.5 * ang_m * ang_v * ang_v   Return lin_E + ang_EEnd Function'-------------------------------------------------------------------------------Type thruster_type   '''init paramaters   Dim As polar polarForce '(rad, N)   Dim As polar polarPos '(rad, m)   '''variable paramaters   Dim As sgl2d forceVector '(N, N)   Dim As sgl2d relPos, absPos '(m, m)   Dim As Integer active   Declare Sub init(forceMagnitude As Single, forceDirection As Single, posAngle As Single, posRadius As Single)   Declare Sub updatePosition(bodyPos As sgl2d, bodyAngle As Single)End TypeSub thruster_type.init(forceDirection As Single, forceMagnitude As Single, posAngle As Single, posRadius As Single)   polarForce = Type(forceDirection, forceMagnitude) 'thruster action   polarPos = Type(posAngle, posRadius) 'position of thruster on shipEnd SubSub thruster_type.updatePosition(bodyPos As sgl2d, bodyAngle As Single)   relPos = polarToCartesian(bodyAngle + polarPos.angle, polarPos.magnitude)   absPos = bodyPos + relPosEnd Sub'-------------------------------------------------------------------------------Const As Single GRAV_CONST = 6.67e-11 '[m3/(kg*s^2)Type astro_body   Dim As Single radius '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   Dim As sgl2d position 'position [m]   Dim As Single mass '[kg]   Declare Sub init(r As Single, d As Single, p As sgl2d, c As ULong)End Type'Set radius, density, position'Calculate mass and rotational inertiaSub astro_body.init(r As Single, d As Single, p As sgl2d, c As ULong)   radius = r   density = d   position = p   colour = c   mass = PI * r ^ 2 * dEnd SubFunction gravForce(m1 As Single, m2 As Single, r As Single) As Single   Return GRAV_CONST * (m1 * m2) / (r * r)End FunctionFunction gravForceVector(m1 As Single, Pos1 As sgl2d, m2 As Single, pos2 As sgl2d) As sgl2d   Dim As Single distSquared = distSqrd(pos2, Pos1)   Dim As sgl2d unitVector12 = (Pos1 - pos2) / Sqr(distSquared)   Return unitVector12 * (-GRAV_CONST * (m1 * m2) / distSquared)End Function'-------------------------------------------------------------------------------Const As Single MOON_RADIUS = 1737e+6 '[m]Const As Single MOON_DENSITY = 3344 '[kg/m^3]Const NUM_THRUSTERS = 6Const L_FW_THR = 0 'left forward thrusterConst R_FW_THR = 1 'right forward thrusterConst L_LO_THR = 2Const R_LO_THR = 3Const L_HI_THR = 4Const R_HI_THR = 5Dim As String keyDim As Integer quit = 0Dim As disc_object shipDim As thruster_type thruster(NUM_THRUSTERS - 1)Const NUM_asteroid = 100Dim As astro_body asteroid(NUM_ASTEROID-1)ship.init(10, 1, 5, sgl2d(0, -50), RGB(127, 223, 0))For i As Integer = 0 To UBound(asteroid)   asteroid(i).init(5 + 4 / (Rnd + 0.2), 1000, sgl2d((Rnd - 0.5) * 2000, (Rnd - 0.5) * 2000), RGB(255, 191, 0))Next'force angle, force magnitude, polar thruster position thruster(L_FW_THR).init(0.5 * pi, 1.2e4, -0.75 * pi, ship.radius)thruster(R_FW_THR).init(0.5 * pi, 1.2e4, -0.25 * pi, ship.radius)thruster(L_LO_THR).init(0.0 * pi, 8e3, -0.75 * pi, ship.radius)thruster(R_LO_THR).init(1.0 * pi, 8e3, -0.25 * pi, ship.radius)thruster(L_HI_THR).init(0.0 * pi, 8e3, +0.75 * pi, ship.radius)thruster(R_HI_THR).init(1.0 * pi, 8e3, +0.25 * pi, ship.radius)Dim As Double tNow = Timer, tPrev = tNow, dt = 0While quit = 0   'reset stuff   ship.lin_F = sgl2d(0, 0)   ship.ang_F = 0   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).active = 0   Next   If MultiKey(FB.SC_UP) Then      thruster(L_FW_THR).active = 1      thruster(R_FW_THR).active = 1   End If   '~ if multikey(FB.SC_SPACE) then      '~ thruster(L_FW_THR).active = 2 'hyper-drive      '~ thruster(R_FW_THR).active = 2 'hyper-drive   '~ end if   If MultiKey(FB.SC_LEFT) Then      thruster(L_LO_THR).active = 1      thruster(R_HI_THR).active = 1   End If   If MultiKey(FB.SC_RIGHT) Then      thruster(R_LO_THR).active = 1      thruster(L_HI_THR).active = 1   End If   If key = K_ESC Then quit = 1   For i As Integer = 0 To NUM_THRUSTERS - 1      'forces on body by active thrusters      If thruster(i).active > 0 Then         Dim As Single thrust = thruster(i).polarForce.magnitude         'if thruster(i).active = 2 then thrust *= 10 'hyper-drive         thruster(i).forceVector = polarToCartesian(ship.angle + thruster(i).polarForce.angle, thrust)         ship.lin_F += thruster(i).forceVector         ship.ang_F += cross(thruster(i).relPos, thruster(i).forceVector)      End If   Next   ship.update(dt) 'position and angle   sg.offset = ship.position   sg.scale = limit(100 / Len(ship.lin_v), 0.5, 2.0)   'calculate ship direction pointer / triangle   Dim As sgl2d forwardPos = polarToCartesian(ship.angle - 90 * RAD_PER_DEG, ship.radius * 2.2)   Dim As sgl2d leftBackPos = polarToCartesian(ship.angle - 135 * RAD_PER_DEG, ship.radius * 1.0) '(90 + 45)   Dim As sgl2d rightBackPos = polarToCartesian(ship.angle - 45 * RAD_PER_DEG, ship.radius * 1.0) '(90 - 45)   'do always for display   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).updatePosition(ship.position, ship.angle)   Next   'find nearest asteroid   Dim As Integer nearestAsteroidId = 0   Dim As Single nearestAsteroidDistSqrd = distSqrd(ship.position, asteroid(0).position)   Dim As Single currenAsteroidDistSqrd   For i As Integer = 1 To UBound(asteroid)      currenAsteroidDistSqrd = distSqrd(ship.position, asteroid(i).position)      If currenAsteroidDistSqrd < nearestAsteroidDistSqrd Then         nearestAsteroidDistSqrd = currenAsteroidDistSqrd         nearestAsteroidId = i      End If   Next      'display   ScreenLock   sg.clearScreen(0)   Locate 2, 2 : Print "<UP>, <LEFT>, <RIGHT> for thrusters, <ESC> to exit";   Locate 3, 2 : Print "Nearest asteroid distance [m]: "; CInt(Sqr(nearestAsteroidDistSqrd));   Locate 4, 2 : Print "Kinetic engergy [kJ]: "; CInt(ship.getKineticEnergy() * 1e-3);   'draw ship   sg.drawCircle(ship.position, ship.radius, ship.colour) 'flying saucer   sg.drawLine(ship.position + forwardPos, ship.position + leftBackPos, ship.colour)   sg.drawLine(ship.position + forwardPos, ship.position + rightBackPos, ship.colour)   'draw active thrusters   For i As Integer = 0 To NUM_THRUSTERS - 1      'Dim As ULong c = IIf(i < 4, RGB(255, 255, 0), RGB(255, 255, 255))      If thruster(i).active > 0 Then         drawThruster(thruster(i).absPos, thruster(i).absPos - thruster(i).forceVector / 1e3, RGB(255, 63, 0)) 'thruster force indicator      End If   Next   'draw astroids   For i As Integer = 0 To UBound(asteroid)      sg.drawCircle(asteroid(i).position, asteroid(i).radius, IIf(nearestAsteroidId = i, RGB(191, 191, 255), asteroid(i).colour))   Next   Dim As sgl2d asteroidPointer = normalise(ship.position - asteroid(nearestAsteroidId).position)   drawArrow(ship.position, ship.position - asteroidPointer * ship.radius * 2, RGB(191, 191, 255))   ScreenUnLock   'time update   key = InKey()   Sleep 1   tPrev = tNow   tNow = Timer   dt = tNow - tPrevWendScreen 0Print "End"'TODO:'center of universe indicator'drawElipse'fuel`
Posts: 2080
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Physics question

While patiently waiting for h4tt3n's space physics doodle stuff, I slowly convert my code to a small game:

Code: Select all

`#Include "fbgfx.bi"Type int2d   As Integer x, y   Declare Constructor   Declare Constructor(x As Integer, y As Integer)   Declare Operator Cast () As StringEnd TypeConstructor int2dEnd ConstructorConstructor int2d(x As Integer, y As Integer)   This.x = x : This.y = yEnd ConstructorOperator = (a As int2d, b As int2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd OperatorOperator <> (a As int2d, b As int2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' "x, y"Operator int2d.cast () As String  Return Str(x) & "," & Str(y)End Operator' a + b Operator + (a As int2d, b As int2d) As int2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As int2d, b As int2d) As int2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As int2d) As int2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As int2d, b As int2d) As int2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As int2d, mul As Integer) As int2d   Return Type(a.x * mul, a.y * mul)End Operator' a \ bOperator \ (a As int2d, b As int2d) As int2d   Return Type(a.x \ b.x, a.y \ b.y)End Operator' a \ divOperator \ (a As int2d, div As Integer) As int2d   Return Type(a.x \ div, a.y \ div)End Operator'===============================================================================Type sgl2d   As Single x, y   Declare Constructor   Declare Constructor(x As Single, y As Single)   Declare Operator Cast () As StringEnd TypeConstructor sgl2dEnd ConstructorConstructor sgl2d(x As Single, y As Single)   This.x = x : This.y = yEnd Constructor' "x, y"Operator sgl2d.cast () As String   Return Str(x) & "," & Str(y)End Operator'---- operators ---' distance / lenthOperator Len (a As sgl2d) As Single   Return Sqr(a.x * a.x + a.y * a.y)End Operator' a = b ?Operator = (a As sgl2d, b As sgl2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd Operator' a != b ?Operator <> (a As sgl2d, b As sgl2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' a + b Operator + (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As sgl2d) As sgl2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As sgl2d, mul As Single) As sgl2d   Return Type(a.x * mul, a.y * mul)End Operator' a / divOperator / (a As sgl2d, div As Single) As sgl2d   Return Type(a.x / div, a.y / div)End Operator'---- extra functions ---Function cross(a As sgl2d, b As sgl2d) As Single   Return a.x * b.y - a.y * b.xEnd Function'~ function length(a as sgl2d) as single   '~ return sqr((a.x * a.x) + (a.y * a.y)) '~ end functionFunction lengthSqrd(a As sgl2d) As Single   Return (a.x * a.x) + (a.y * a.y) End FunctionFunction dist(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return Sqr((dx * dx) + (dy * dy)) End FunctionFunction distSqrd(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return (dx * dx) + (dy * dy) End FunctionFunction normalise(a As sgl2d) As sgl2d   Dim As sgl2d temp   Dim As Single length = Len(a)   Return sgl2d(a.x / length, a.y / length)End Function'==============================================================================='Note: y+ = up, x+ = right, (0,0) = centerType scaled_graphics_type   Dim As Single scale = 1 ' = 1 / pixel_size 'pixels / meter   'dim as int2d offset' = (scrn_w \ 2, h \ 2) 'offset in pixels   Dim As sgl2d offset   Dim As Integer w = -1, h = -1   Dim As Integer wc = -1, hc = -1 'center x,y   Declare Sub setScreen(w As Integer, h As Integer)   Declare Sub setScaling(scale As Single, offset As sgl2d)   Declare Sub clearScreen(c As ULong)   Declare Function pos2screen(p As sgl2d) As int2d   Declare Sub drawPixel(p As sgl2d, c As Integer)   Declare Sub drawCircle(p As sgl2d, r As Single, c As Integer)   Declare Sub drawElipse(p As sgl2d, r As Single, aspect As Single, c As Integer)   Declare Sub drawLine(p1 As sgl2d, p2 As sgl2d, c As Integer)End TypeSub scaled_graphics_type.setScreen(w As Integer, h As Integer)   This.w = w 'width   This.h = h 'height   wc = w \ 2   hc = h \ 2   ScreenRes w, h, 32   Width w \ 8, h \ 16 'bigger fontEnd SubSub scaled_graphics_type.setScaling(scale As Single, offset As sgl2d)   This.scale = scale   This.offset = offsetEnd SubSub scaled_graphics_type.clearScreen(c As ULong)   Line(0, 0)-(w - 1, h - 1), c, bfEnd SubFunction scaled_graphics_type.pos2screen(p As sgl2d) As int2d   Return int2d(Int(wc + (p.x - offset.x) * scale), h - Int(hc + (p.y - offset.y) * scale))End FunctionSub scaled_graphics_type.drawPixel(p As sgl2d, c As Integer)   Dim As int2d posScrn = pos2screen(p)   PSet(posScrn.x, posScrn.y), cEnd SubSub scaled_graphics_type.drawCircle(p As sgl2d, r As Single, c As Integer)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, cEnd SubSub scaled_graphics_type.drawElipse(p As sgl2d, r As Single, aspect As Single, c As Integer)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, c, , , aspectEnd SubSub scaled_graphics_type.drawLine(p1 As sgl2d, p2 As sgl2d, c As Integer)   Dim As int2d posScrn1 = pos2screen(p1)   Dim As int2d posScrn2 = pos2screen(p2)   Line(posScrn1.x, posScrn1.y)-(posScrn2.x, posScrn2.y), cEnd Sub'===============================================================================Const As Single PI = 4 * Atn(1)Const As Single RAD_PER_DEG = (PI / 180)Const As Single DEG_PER_RAD = 180 / PIConst As Single sinA = Sin((10 / 180) * PI)Const As Single cosA = Cos((10 / 180) * PI)Const As Single sinB = Sin((20 / 180) * PI)Const As Single cosB = Cos((20 / 180) * PI)Const K_ESC = Chr(27)Const K_MIN = Chr(45)Const K_UND = Chr(95)Const K_PLU = Chr(61)Const K_EQU = Chr(43)Const SCRN_W = 800, SCRN_H = 600Dim Shared As scaled_graphics_type sgsg.setScaling(2.0, sgl2d(0, 0))sg.setScreen(SCRN_W, SCRN_H)'-------------------------------------------------------------------------------Function limit(value As Single, min As Single, max As Single) As Single   If value < min Then Return min   If value > max Then Return max   Return valueEnd FunctionType polar   Dim As Single angle   Dim As Single magnitudeEnd TypeFunction polarToCartesian(angle As Single, radius As Single) As sgl2d   Return sgl2d(Cos(angle) * radius, Sin(angle) * radius)End FunctionFunction rotatedVector(v As sgl2d, rotAngle As Single) As sgl2d   Dim As sgl2d tmp   tmp.x = Cos(rotAngle) * v.x - Sin(rotAngle) * v.y   tmp.y = Sin(rotAngle) * v.x + Cos(rotAngle) * v.y   Return tmpEnd Function'-------------------------------------------------------------------------------Sub drawArrow(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.30 'reduce length   sg.drawLine(p2, p2 - sgl2d(cosB * dp.x - sinB * dp.y, sinB * dp.x + cosB * dp.y), c)   sg.drawLine(p2, p2 - sgl2d(cosB * dp.x + sinB * dp.y, cosB * dp.y - sinB * dp.x), c)End SubSub drawThruster(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.95 'reduce length   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x - sinA * dp.y, sinA * dp.x + cosA * dp.y), c)   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x + sinA * dp.y, cosA * dp.y - sinA * dp.x), c)End SubSub drawHelium3(p As sgl2d, r As Single, c As ULong)   For i As Integer = 0 To 2      sg.drawCircle(p + polarToCartesian((i / 3) * 2 * PI, 0.15 * r), 0.15 * r, c)   Next   sg.drawElipse(p, r, 2.0, c)   sg.drawElipse(p, r, 0.5, c)End Sub'-------------------------------------------------------------------------------Type disc_object   Dim As Single radius '[m]   Dim As Single height '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   'linear motion properties   Dim As sgl2d position 'position [m]   Dim As Single lin_m 'mass [kg]   Dim As sgl2d lin_F 'force [N] [kg*m/s^2]   Dim As sgl2d lin_a 'acceleration [m/s^2]   Dim As sgl2d lin_v 'velocity [m/s]   'dim as sgl2d lin_p 'momentum [kg*m/s]   'dim as single lin_E 'Kinetic energy [J] [kg*m^2/s^2]   'Rotational motion properties   Dim As Single angle 'angular position (theta) [rad]   Dim As Single ang_m 'angular mass, moment of inertia (I) [kg*m^2]   Dim As Single ang_F 'torque (tau) [N*m] [kg*m^2/s^2]   Dim As Single ang_a 'angular velocity (alpha) [rad/s^2]   Dim As Single ang_v 'angular velocity (omega) [rad/s]   'dim as single ang_p 'angular momentum (L) [kg*m^2/s]   'dim as single ang_E 'Kinetic energy [J] [kg*m^2/s^2]   Declare Sub init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   Declare Sub update(dt As Double)   Declare Function getKineticEnergy() As SingleEnd Type'Set radius, height, density, position'Calculate mass and rotational inertiaSub disc_object.init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   radius = r   height = h   density = d   position = p   colour = c   lin_m = PI * r ^ 2 * d   ang_m = 0.5 * lin_m * r ^ 2End Sub'update position and angleSub disc_object.update(dt As Double)   lin_a = lin_F / lin_m   lin_v += lin_a * dt   position += lin_v * dt   ang_a = ang_F / ang_m   ang_v += ang_a * dt   angle += ang_v * dtEnd SubFunction disc_object.getKineticEnergy() As Single   Dim As Single lin_E = 0.5 * lin_m * lengthSqrd(lin_v)   Dim As Single ang_E = 0.5 * ang_m * ang_v * ang_v   Return lin_E + ang_EEnd FunctionSub drawShip(ship As disc_object)   'calculate ships tail pointer / triangle   Dim As sgl2d forwardPos = polarToCartesian(ship.angle - 90 * RAD_PER_DEG, ship.radius * 2.2)   Dim As sgl2d leftBackPos = polarToCartesian(ship.angle - 135 * RAD_PER_DEG, ship.radius * 1.0) '(90 + 45)   Dim As sgl2d rightBackPos = polarToCartesian(ship.angle - 45 * RAD_PER_DEG, ship.radius * 1.0) '(90 - 45)   sg.drawCircle(ship.position, ship.radius, ship.colour) 'flying saucer   sg.drawLine(ship.position + forwardPos, ship.position + leftBackPos, ship.colour)   sg.drawLine(ship.position + forwardPos, ship.position + rightBackPos, ship.colour)End Sub'-------------------------------------------------------------------------------Type thruster_type   '''init paramaters   Dim As polar polarForce '(rad, N)   Dim As polar polarPos '(rad, m)   '''variable paramaters   Dim As sgl2d forceVector '(N, N)   Dim As sgl2d relPos, absPos '(m, m)   Dim As Integer active   Declare Sub init(forceMagnitude As Single, forceDirection As Single, posAngle As Single, posRadius As Single)   Declare Sub updatePosition(bodyPos As sgl2d, bodyAngle As Single)End TypeSub thruster_type.init(forceDirection As Single, forceMagnitude As Single, posAngle As Single, posRadius As Single)   polarForce = Type(forceDirection, forceMagnitude) 'thruster action   polarPos = Type(posAngle, posRadius) 'position of thruster on shipEnd SubSub thruster_type.updatePosition(bodyPos As sgl2d, bodyAngle As Single)   relPos = polarToCartesian(bodyAngle + polarPos.angle, polarPos.magnitude)   absPos = bodyPos + relPosEnd Sub'-------------------------------------------------------------------------------Const As Single GRAV_CONST = 6.67e-11 '[m3/(kg*s^2)Type astro_body   Dim As Single radius '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   Dim As sgl2d position 'position [m]   Dim As Single mass '[kg]   Declare Sub init(r As Single, d As Single, p As sgl2d, c As ULong)End Type'Set radius, density, position'Calculate mass and rotational inertiaSub astro_body.init(r As Single, d As Single, p As sgl2d, c As ULong)   radius = r   density = d   position = p   colour = c   mass = PI * r ^ 2 * dEnd SubFunction gravForce(m1 As Single, m2 As Single, r As Single) As Single   Return GRAV_CONST * (m1 * m2) / (r * r)End FunctionFunction gravForceVector(m1 As Single, Pos1 As sgl2d, m2 As Single, pos2 As sgl2d) As sgl2d   Dim As Single distSquared = distSqrd(pos2, Pos1)   Dim As sgl2d unitVector12 = (Pos1 - pos2) / Sqr(distSquared)   Return unitVector12 * (-GRAV_CONST * (m1 * m2) / distSquared)End FunctionFunction findNearestBody(refPos As sgl2d, body() As astro_body) As Integer   Dim As Integer nearestBodyId = 0   Dim As Single nearestBodyDistSqrd = distSqrd(refPos, body(0).position)   Dim As Single currentBodyDistSqrd   For i As Integer = 1 To UBound(body)      currentBodyDistSqrd = distSqrd(refPos, body(i).position)      If currentBodyDistSqrd < nearestBodyDistSqrd Then         nearestBodyDistSqrd = currentBodyDistSqrd         nearestBodyId = i      End If   Next   Return nearestBodyId End Function'-------------------------------------------------------------------------------Const As Single MOON_RADIUS = 1737e+6 '[m]Const As Single MOON_DENSITY = 3344 '[kg/m^3]Const NUM_THRUSTERS = 6Const L_FW_THR = 0 'left forward thrusterConst R_FW_THR = 1 'right forward thrusterConst L_LO_THR = 2Const R_LO_THR = 3Const L_HI_THR = 4Const R_HI_THR = 5Dim As String keyDim As Integer quit = 0Dim As disc_object shipDim As thruster_type thruster(NUM_THRUSTERS - 1)Const NUM_ASTEROID = 50Dim As astro_body asteroid(NUM_ASTEROID-1)Const NUM_HELIUM = 20Dim As astro_body helium(NUM_HELIUM-1)Const As Single maxFuel = 1e6 'N*sDim As Single fuel = maxFuelship.init(10, 1, 5, sgl2d(0, -50), RGB(127, 223, 0))For i As Integer = 0 To UBound(asteroid)   asteroid(i).init(5 + 4 / (Rnd + 0.2), 1000, sgl2d((Rnd - 0.5) * 2000, (Rnd - 0.5) * 2000), RGB(255, 191, 0))NextFor i As Integer = 0 To UBound(helium)   helium(i).init(5 + 4 / (Rnd + 0.2), 1000, sgl2d((Rnd - 0.5) * 2000, (Rnd - 0.5) * 2000), RGB(255, 191, 0))Next'force angle, force magnitude, polar thruster position thruster(L_FW_THR).init(0.5 * pi, 1.2e4, -0.75 * pi, ship.radius)thruster(R_FW_THR).init(0.5 * pi, 1.2e4, -0.25 * pi, ship.radius)thruster(L_LO_THR).init(0.0 * pi, 8e3, -0.75 * pi, ship.radius)thruster(R_LO_THR).init(1.0 * pi, 8e3, -0.25 * pi, ship.radius)thruster(L_HI_THR).init(0.0 * pi, 8e3, +0.75 * pi, ship.radius)thruster(R_HI_THR).init(1.0 * pi, 8e3, +0.25 * pi, ship.radius)Dim As Double tNow = Timer, tPrev = tNow, dt = 0While quit = 0   'reset stuff   ship.lin_F = sgl2d(0, 0)   ship.ang_F = 0   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).active = 0   Next   If MultiKey(FB.SC_UP) Then      thruster(L_FW_THR).active = 1      thruster(R_FW_THR).active = 1      fuel -= thruster(L_FW_THR).polarForce.magnitude * dt      fuel -= thruster(R_FW_THR).polarForce.magnitude * dt   End If   If MultiKey(FB.SC_LEFT) Then      thruster(L_LO_THR).active = 1      thruster(R_HI_THR).active = 1      fuel -= thruster(L_LO_THR).polarForce.magnitude * dt      fuel -= thruster(R_HI_THR).polarForce.magnitude * dt   End If   If MultiKey(FB.SC_RIGHT) Then      thruster(R_LO_THR).active = 1      thruster(L_HI_THR).active = 1      fuel -= thruster(R_LO_THR).polarForce.magnitude * dt      fuel -= thruster(L_HI_THR).polarForce.magnitude * dt   End If   If key = K_ESC Then quit = 1   For i As Integer = 0 To NUM_THRUSTERS - 1      'forces on body by active thrusters      If thruster(i).active > 0 Then         Dim As Single thrust = thruster(i).polarForce.magnitude         thruster(i).forceVector = polarToCartesian(ship.angle + thruster(i).polarForce.angle, thrust)         ship.lin_F += thruster(i).forceVector         ship.ang_F += cross(thruster(i).relPos, thruster(i).forceVector)      End If   Next   ship.update(dt) 'position and angle   sg.offset = ship.position   sg.scale = limit(100 / Len(ship.lin_v), 0.5, 2.0)   'do always for display   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).updatePosition(ship.position, ship.angle)   Next   Dim As Integer nearestHeliumId = findNearestBody(ship.position, helium())   Dim As Integer nearestAsteroidId = findNearestBody(ship.position, asteroid())   Dim As astro_body Ptr pAsteroid = @asteroid(nearestAsteroidId)   If dist(ship.position, pAsteroid->position) < ship.radius + pAsteroid->radius Then      quit = 2 'crash   End If   If fuel <= 0 Then quit = 3      'display   ScreenLock   sg.clearScreen(0)   Locate 2, 2 : Print "<UP>, <LEFT>, <RIGHT> for thrusters, <ESC> to exit";   Locate 3, 2 : Print "Nearest helium distance [m]: "; CInt(dist(ship.position, helium(nearestHeliumId).position));   Locate 4, 2 : Print "Kinetic engergy [kJ]: "; CInt(ship.getKineticEnergy() * 1e-3);   Locate 5, 2 : Print "Fuel remaining [%]: "; CInt((fuel / maxFuel) * 100);   drawShip(ship)   'draw active thrusters   For i As Integer = 0 To NUM_THRUSTERS - 1      Dim As ULong c = IIf(i < 4, RGB(255, 255, 0), RGB(255, 255, 255))      If thruster(i).active > 0 Then         drawThruster(thruster(i).absPos, thruster(i).absPos - thruster(i).forceVector / 1e3, RGB(255, 63, 0)) 'thruster force indicator      End If   Next   'draw asteroids   For i As Integer = 0 To UBound(asteroid)      sg.drawCircle(asteroid(i).position, asteroid(i).radius, asteroid(i).colour)   Next   'draw helium 'clouds'   For i As Integer = 0 To UBound(helium)      drawHelium3(helium(i).position, helium(i).radius, IIf(nearestHeliumId = i, RGB(191, 191, 255), helium(i).colour))   Next   Dim As sgl2d heliumPointer = normalise(ship.position - helium(nearestHeliumId).position)   drawArrow(ship.position, ship.position - heliumPointer * ship.radius * 2, RGB(191, 191, 255))   ScreenUnLock   'time update   key = InKey()   Sleep 1   tPrev = tNow   tNow = Timer   dt = tNow - tPrevWendIf quit > 1 Then 'Crashed or No fuel   If quit = 2 Then ship.colour = RGB(233, 0, 0)   If quit = 3 Then ship.colour = RGB(233, 191, 191)   drawShip(ship)   While InKey <> Chr(13)      Locate 7, 2       If quit = 2 Then Print "Ship crashed, press <ENTER> to exit."      If quit = 3 Then Print "Ship out of fuel, press <ENTER> to exit."      Sleep 1   WendEnd IfScreen 0Print "End"'TODO:'collect / remove helium3'shoot asteroids`
h4tt3n
Posts: 694
Joined: Oct 22, 2005 21:12
Location: Denmark

### Re: Physics question

I'm still around :-) Here, as promised, are some space physics examples. Some are rather old, but I'll just post them as they are, warts and all.

First, a vector library and a ball shaped space ship, asteroids in orbit around a central planet, also featuring collision with friction.

You control the yellow ball with the arrow keys. Up = thrust, left/right = rotate, down = stop rotating.

Vec2.bi

Code: Select all

`''*******************************************************************************''   ''   FreeBASIC 2D Floating Point Vector Library''   Written in FreeBASIC 1.05''   Version 1.3.0, November 2016, Michael "h4tt3n" Nissen''   ''   Function syntax:''   ''   (Return Type) (Name) (Argument Type (, ...)) (Description)''   ''   Vector  Absolute         ( Vector )          Absolute value''   Vector  AngleToUnit      ( Scalar )          unit vector from angle scalar''   Vector  Component        ( Vector, Vector )  Vector Component''   Scalar  Dot              ( Vector, Vector )  Dot product''   Vector  Dot              ( Vector, Scalar )  Dot product ''   Vector  Dot              ( Scalar, Vector )  Dot product''   Vector  PerpCW           ( Vector )          Right hand perpendicular''   Vector  PerpCCW          ( Vector )          Left hand perpendicular''   Vector  Unit             ( Vector )          Unit Vector''   Scalar  Length           ( Vector )          Length''   Scalar  LengthSquared    ( Vector )          Length squared''   Scalar  PerpDot          ( Vector, Vector )  Perp dot product (2d cross)''   Vector  PerpDot          ( Vector, Scalar )  Perp dot product (2d cross)''   Vector  PerpDot          ( Scalar, Vector )  Perp dot product (2d cross)''   Vector  Project          ( Vector, Vector )  Vector Projection''   Vector  RandomizeSquare  ( Scalar )          Randomize in range +/- value''   Vector  RandomizeCircle  ( Scalar )          Randomize in range +/- value''   Vector  Rotate           ( Vector )          Rotate''   Scalar  UnitToAngle      ( Vector )          angle scalar from unit vector''   ''   Library supports both member and non-member function useage:''   ''   A.function(B) <-> function(A, B)''   ''*******************************************************************************''#Ifndef __VEC2_BI__#Define __VEC2_BI__''  Vec2 Vector classType Vec2      Public:      ''  Vec2 constructor declarations   Declare Constructor ()   Declare Constructor ( ByRef v As Const Vec2 )   Declare Constructor ( ByVal x As Const Single, ByVal y As Const Single )      '' Vec2 destructor   Declare Destructor()      ''  Vec2 assignment operator (=)   Declare Operator Let ( ByRef B As Const Vec2 )      ''   Vec2 compound arithmetic member operator declarations   Declare Operator +=  ( ByRef B As Const Vec2   )   Declare Operator -=  ( ByRef B As Const Vec2   )   Declare Operator *=  ( ByRef B As Const Vec2   )   Declare Operator *=  ( ByVal B As Const Single )   Declare Operator /=  ( ByVal B As Const Single )      ''  Vec2 member function declarations   Declare Const Function Absolute_        () As Vec2      Declare Const Function PerpCW          () As Vec2   Declare Const Function PerpCCW         () As Vec2      Declare Const Function Unit            () As Vec2   Declare Const Function Length          () As Single   Declare Const Function LengthSquared   () As Single      Declare Const Function Dot             ( ByRef B As Const Vec2   ) As Single   Declare Const Function Dot             ( ByVal B As Const Single ) As Vec2      Declare Const Function PerpDot         ( ByRef B As Const Vec2   ) As Single   Declare Const Function PerpDot         ( ByVal B As Const Single ) As Vec2      Declare Const Function Project         ( ByRef B As Const Vec2   ) As Vec2   Declare Const Function Component       ( ByRef B As Const Vec2   ) As Vec2      Declare Const Function RandomizeCircle ( ByVal B As Const Single ) As Vec2   Declare Const Function RandomizeSquare ( ByVal B As Const Single ) As Vec2      Declare Const Function RotateCW        ( ByRef B As Const Vec2   ) As Vec2   Declare Const Function RotateCCW       ( ByRef B As Const Vec2   ) As Vec2      Declare Const Function RotateCW        ( ByRef B As Const Single ) As Vec2   Declare Const Function RotateCCW       ( ByRef B As Const Single ) As Vec2      ''  Vec2 variables   As Single x, y   End Type''  Vec2 unary arithmetic non-member operator declarationsDeclare Operator - ( ByRef B As Const Vec2 ) As Vec2''  Vec2 binary arithmetic non-member operator declarationsDeclare Operator + ( ByRef A As Const Vec2  , ByRef B As Const Vec2   ) As Vec2Declare Operator - ( ByRef A As Const Vec2  , ByRef B As Const Vec2   ) As Vec2Declare Operator * ( ByVal A As Const Single, ByRef B As Const Vec2   ) As Vec2Declare Operator * ( ByRef A As Const Vec2  , ByVal B As Const Single ) As Vec2Declare Operator * ( ByRef A As Const Vec2  , ByRef B As Const Vec2   ) As Vec2Declare Operator / ( ByRef A As Const Vec2  , ByVal B As Const Single ) As Vec2''  Vec2 binary relational non-member operator declarationsDeclare Operator =  ( ByRef A As Const Vec2, ByVal B As Const Vec2 ) As IntegerDeclare Operator <> ( ByRef A As Const Vec2, ByVal B As Const Vec2 ) As IntegerDeclare Operator <  ( ByRef A As Const Vec2, ByVal B As Const Vec2 ) As IntegerDeclare Operator >  ( ByRef A As Const Vec2, ByVal B As Const Vec2 ) As Integer''  Vec2 non-member function declarationsDeclare Function Absolute_ OverLoad ( ByRef A As Const Vec2 ) As Vec2Declare Function Unit              ( ByRef A As Const Vec2 ) As Vec2Declare Function Length            ( ByRef A As Const Vec2 ) As SingleDeclare Function LengthSquared     ( ByRef A As Const Vec2 ) As SingleDeclare Function Dot      Overload ( ByRef A As Const Vec2  , ByRef B As Const Vec2   ) As SingleDeclare Function Dot               ( ByRef A As Const Vec2  , ByVal B As Const Single ) As Vec2Declare Function Dot               ( ByVal A As Const Single, ByRef B As Const Vec2   ) As Vec2Declare Function PerpDot  OverLoad ( ByRef A As Const Vec2  , ByRef B As Const Vec2   ) As SingleDeclare Function PerpDot           ( ByRef A As Const Vec2  , ByVal B As Const Single ) As Vec2Declare Function PerpDot           ( ByVal A As Const Single, ByRef B As Const Vec2   ) As Vec2Declare Function Project           ( ByRef A As Const Vec2  , ByRef B As Const Vec2   ) As Vec2Declare Function Component         ( ByRef A As Const Vec2  , ByRef B As Const Vec2   ) As Vec2Declare Function RandomizeCircle   ( ByRef A As Const Vec2  , ByVal B As Const Single ) As Vec2Declare Function RandomizeSquare   ( ByRef A As Const Vec2  , ByVal B As Const Single ) As Vec2Declare Function RotateCW  OverLoad ( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2Declare Function RotateCCW OverLoad ( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2Declare Function AngleToUnit       ( ByVal A As Const Single ) As Vec2Declare Function UnitToAngle       ( ByRef A As Const Vec2 ) As Single''  Vec2 constructorsConstructor Vec2()  This.x = 0.0 : This.y = 0.0  End ConstructorConstructor Vec2( ByRef v As Const Vec2 )      This = v  End ConstructorConstructor Vec2( ByVal x As Const Single, ByVal y As Const Single )  This.x = x : This.y = y  End Constructor'' DestructorDestructor Vec2()End Destructor''Operator Vec2.Let ( ByRef B As Const Vec2 )      If ( Not @This = @B ) Then            This.x = B.x : This.y = B.y         EndIf   End Operator''  Vec2 compound arithmetic member operatorsOperator Vec2.+= ( ByRef B As Const Vec2 )      This.x += B.x : This.y += B.y   End OperatorOperator Vec2.-= ( ByRef B As Const Vec2 )      This.x -= B.x : This.y -= B.y   End OperatorOperator Vec2.*= ( ByRef B As Const Vec2 )      This.x *= B.x : This.y *= B.y   End OperatorOperator Vec2.*= ( ByVal B As Const Single )      This.x *= B : This.y *= B   End OperatorOperator Vec2./= ( ByVal B As Const Single )         This.x /= B : This.y /= B    End Operator''  Vec2 member functionsFunction Vec2.Absolute_() As Vec2      Return Vec2( Abs( This.x ), Abs( This.y ) )   End FunctionFunction Vec2.PerpCW() As Vec2      Return Vec2( This.y, -This.x )   End FunctionFunction Vec2.PerpCCW() As Vec2      Return Vec2( -This.y, This.x )   End Function Function Vec2.Unit() As Vec2      Return IIf( This <> Vec2( 0.0, 0.0 ) , Vec2( This / This.Length() ) , Vec2( 0.0, 0.0 ) )   End FunctionFunction Vec2.Length() As Single      'Dim As Single length_squared = This.LengthSquared()   'Return Sqr( length_squared )      Return Sqr( This.LengthSquared() )   End FunctionFunction Vec2.LengthSquared() As Single      'Return This.Dot( This )   Return ( This.x * This.x + This.y * This.y )   End FunctionFunction Vec2.Dot( ByVal B As Const Single ) As Vec2      Return Vec2( This.x * B, This.y * B )   End FunctionFunction Vec2.Dot( ByRef B As Const Vec2 ) As Single      Return ( This.x * B.x + This.y * B.y )   End FunctionFunction Vec2.PerpDot( ByVal B As Const Single  ) As Vec2      Return Vec2( -This.y * B, This.x * B )   End FunctionFunction Vec2.PerpDot( ByRef B As Const Vec2 ) As Single      Return ( -This.y * B.x + This.x * B.y  )   'Return ( This.x * B.y - This.y * B.x )   'Return ( This.Dot( B.Perp() ) )   End FunctionFunction Vec2.Project( ByRef B As Const Vec2 ) As Vec2      Return ( B.Dot( This ) / This.Dot( This ) ) * This   End FunctionFunction Vec2.Component( ByRef B As Const Vec2 ) As Vec2      Return ( This.Dot( B ) / B.Dot( B ) ) * B   End FunctionFunction Vec2.RandomizeCircle( ByVal B As Const Single ) As Vec2      Dim As Single a = Rnd() * 8.0 * Atn( 1.0 )   Dim As Single r = Sqr( Rnd() * B * B )      Return Vec2( Cos( a ), Sin( a ) ) * r    End FunctionFunction Vec2.RandomizeSquare( ByVal B As Const Single ) As Vec2      Return Vec2( ( Rnd() - Rnd() ) * B, ( Rnd() - Rnd() ) * B )   End FunctionFunction Vec2.RotateCW( ByRef B As Const Vec2 ) As Vec2      Return Vec2( B.Dot( This ), B.PerpDot( This ) )   End FunctionFunction Vec2.RotateCCW( ByRef B As Const Vec2 ) As Vec2      'Dim As vec2 v = Vec2( B.x, -B.y )      'Return Vec2( v.Dot( This ), v.PerpDot( This ) )      Return Vec2( B.x * This.x - B.y * This.y , B.y * This.x + B.x * This.y )      ''perpccw = -y, x   End FunctionFunction Vec2.RotateCW( ByRef B As Const Single ) As Vec2      Dim As Vec2 v = Vec2( Cos( B ), Sin( B ) )      Return This.RotateCW( v )   End FunctionFunction Vec2.RotateCCW( ByRef B As Const Single ) As Vec2      Dim As Vec2 v = Vec2( Cos( B ), Sin( B ) )      Return This.RotateCCW( v )   End Function''  Vec2 unary arithmetic non-member operatorsOperator - ( ByRef B As Const Vec2 ) As Vec2      Return Vec2( -B.x, -B.y )   End Operator''  Vec2 binary arithmetic non-member operatorsOperator + ( ByRef A As Const Vec2, ByRef B As Const Vec2 ) As Vec2      Return Vec2( A.x + B.x, A.y + B.y )   End OperatorOperator - ( ByRef A As Const Vec2, ByRef B As Const Vec2 ) As Vec2      Return Vec2( A.x - B.x, A.y - B.y )   End OperatorOperator * ( ByVal A As Const Single, ByRef B As Const Vec2 ) As Vec2      Return Vec2( A * B.x, A * B.y)   End OperatorOperator * ( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2      Return Vec2( A.x * B, A.y * B)   End OperatorOperator * ( ByRef A As Const Vec2, ByRef B As Const Vec2 ) As Vec2      Return Vec2( A.x * B.x, A.y * B.y )   End OperatorOperator / ( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2      Return Vec2( A.x / B, A.y / B )   End Operator''  Vec2 binary relational non-member operatorsOperator = ( ByRef A As Const Vec2, ByVal B As Const Vec2 ) As Integer      Return ( A.x = B.x ) And ( A.y = B.y )   End OperatorOperator <> ( ByRef A As Const Vec2, ByVal B As Const Vec2 ) As Integer      Return ( A.x <> B.x ) Or ( A.y <> B.y )   End OperatorOperator < ( ByRef A As Const Vec2, ByVal B As Const Vec2 ) As Integer      Return ( A.x < B.x ) And ( A.y < B.y )   End OperatorOperator > ( ByRef A As Const Vec2, ByVal B As Const Vec2 ) As Integer      Return ( A.x > B.x ) And ( A.y > B.y )   End Operator''  Vec2 non-member functionsFunction Absolute_( ByRef A As Const Vec2 ) As Vec2      Return A.Absolute_()   End FunctionFunction Unit( ByRef A As Const Vec2 ) As Vec2      Return A.Unit()   End FunctionFunction Length( ByRef A As Const Vec2 ) As Single      Return A.Length()   End FunctionFunction LengthSquared( ByRef A As Const Vec2 ) As Single      Return A.LengthSquared()   End FunctionFunction Dot( ByRef A As Const Vec2, ByRef B As Const Vec2 ) As Single      Return A.Dot( B )   End FunctionFunction Dot( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2      Return A.Dot( B )   End FunctionFunction Dot( ByVal A As Const Single, ByRef B As Const Vec2 ) As Vec2      Return B.Dot( -A )   End FunctionFunction PerpDot( ByRef A As Const Vec2, ByRef B As Const Vec2 ) As Single      Return A.PerpDot( B )   End FunctionFunction PerpDot( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2      Return A.PerpDot( B )   End FunctionFunction PerpDot( ByVal A As Const Single, ByRef B As Const Vec2 ) As Vec2      Return B.PerpDot( -A )   End FunctionFunction Project( ByRef A As Const Vec2, ByRef B As Const Vec2 ) As Vec2      Return A.Project( B )   End FunctionFunction Component( ByRef A As Const Vec2, ByRef B As Const Vec2 ) As Vec2      Return A.Component( B )   End FunctionFunction RandomizeCircle( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2      Return A.RandomizeCircle( B )   End FunctionFunction RandomizeSquare( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2      Return A.RandomizeSquare( B )   End FunctionFunction RotateCW( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2      Return A.RotateCW( B )   End FunctionFunction RotateCCW( ByRef A As Const Vec2, ByVal B As Const Single ) As Vec2      Return A.RotateCCW( B )   End FunctionFunction AngleToUnit( ByVal A As Const Single ) As Vec2      Return Vec2( Cos( A ), Sin( A ) )   End FunctionFunction UnitToAngle( ByRef A As Const Vec2 ) As Single      Return ATan2( A.y, A.x )   End Function#EndIf __VEC2_BI__`

And here the physics doodle:

Code: Select all

`'' Ball - Ball collision detection and response with friction.'' Written by Michael "h4tt3n" Schmidt Nissen''''#include "fbgfx.bi"#include "Vec2.bi"''Const pi                       = 4*atn(1)Const G                         = 4const num_balls                = 32const rest_fps                  = 60                  ''  ideal framerate'const inv_rest_fps              = 1.0 / (rest_fps+2)  ''  inverse ideal framerateConst inv_rest_fps              = 1.0 / rest_fps  ''  inverse ideal framerateConst dt                        = inv_rest_fps        ''  timestep, delta timeConst inv_dt                  = 1.0 / dt        ''  timestep, delta timeConst StaticFrictionVelocity    = 1.0randomize timer''type ball_typeAs UInteger colas Vec2 Impulseas Vec2 Velocityas Vec2 Positionas Vec2 AngleVectoras Single angular_impulse, ang_Velocity, sin_ang, cos_ang, ang_Position, mass, InverseMass, dens, radius, _RadiusSquared, I, InverseI, CollisionStiffness, COllisionDamping, dynamicfriction, staticfrictionend typedim shared as Vec2 dst, separation_vector, closest_pointdim shared as ball_type ptr balldim shared as Single dst_sqd, radius, RadiusSquared, distancedim shared as integer a, b, scrn_wid, scrn_hgtdim shared as integer FPS, FPS_Counterdim shared as Single FPS_Timer, t0declare sub InitBall(byref a as ball_type)declare sub BallBallCollisionDetection()Declare Sub Controls()Declare Sub Gravity()declare sub Integrate()declare sub DrawSceneToScreen()declare sub brake()scrn_wid = 1000:   scrn_hgt = 800ScreenRes scrn_wid, scrn_hgt, 32WindowTitle "force based 2d ball-ball collision with friction"Color RGB(0, 0, 0), RGB(192, 192, 244)'color 0, rgb(255, 255, 255)ball = New Ball_Type[Num_Balls]with ball[0]Dim As UByte Clr = ((Num_Balls-a)/num_Balls)*255.col = rgb(Clr, 255, clr).mass = 800000.InverseMass = 1/.mass.dens = 0.2.radius = ((.mass/.dens)/((4/3)*pi))^(1/3).RadiusSquared = .radius*.radius.I = 0.5*.mass*.RadiusSquared         ''   flat disc'.I = (2*.mass*.RadiusSquared)/5      ''   solid sphere.InverseI = 1/.I.Position.x = scrn_wid\2.Position.y = scrn_hgt\2.ang_Velocity = 0.0.ang_Position = rnd*2*pi.cos_ang = cos(.ang_Position).sin_ang = sin(.ang_Position).CollisionStiffness = 0.5.COllisionDamping = 0.1.dynamicfriction = 0.5.staticfriction = 1.0end with''  set startup conditionfor a = 1 to num_balls-1Dim As Single angle = 2*pi*RndDim As Single radius = ball[0].radius + 128 + Rnd*256with ball[a]''   brightest first, darkest lastDim As UByte Clr = ((Num_Balls-a)/num_Balls)*255.col = rgb(Clr, 255, clr).mass = 10+(rnd*80^(1/2))^2.InverseMass = 1/.mass.dens = 0.01.radius = ((.mass/.dens)/((4/3)*pi))^(1/3).RadiusSquared = .radius*.radius'.I = 0.5*.mass*.RadiusSquared         ''   flat disc.I = (2*.mass*.RadiusSquared)/5      ''   solid sphere.InverseI = 1/.I.Position.x = ball[0].Position.x + Cos(angle)*Radius.Position.y = ball[0].Position.y + Sin(angle)*Radius.Velocity.X = Sqr((G*ball[0].mass)/radius)*Sin(-Angle).Velocity.Y = Sqr((G*ball[0].mass)/radius)*Cos(Angle)ball[0].Velocity -= .Velocity*(.mass/ball[0].mass).ang_Position = rnd*2*pi.cos_ang = cos(.ang_Position).sin_ang = sin(.ang_Position).ang_Velocity = 0.0'(Rnd-Rnd) * 0.2.CollisionStiffness = 0.5.COllisionDamping = 0.1.dynamicfriction = 0.5.staticfriction = 1.0end withNextWith ball[1].col = RGB(255, 255, 64).mass = 20.InverseMass = 1/.mass.dens = 0.001.radius = ((.mass/.dens)/((4/3)*pi))^(1/3).RadiusSquared = .radius*.radius.I = 0.5*.mass*.radius*.radius.InverseI = 1/.IEnd With''----------------------------------------------------------------------------''DoBallBallCollisionDetection()Integrate()DrawSceneToScreen()brake()loop until multikey(1)Delete[] Ballend''----------------------------------------------------------------------------''sub BallBallCollisionDetection()      For a As Integer = 0 to num_balls-2            For b As Integer = a+1 to num_balls-1                  Dim As Vec2 DistanceVector = ball[a].Position-ball[b].Position         Dim As Single DistanceSquared = LengthSquared(DistanceVector)         Dim As Single rest_distance = ball[a].radius + ball[b].radius                  If DistanceSquared > ( rest_distance * rest_distance ) Then Continue For                     Dim As Single Distance = sqr(DistanceSquared)         Dim as Vec2 NormalVector = IIf( Not Distance = 0.0 , DistanceVector/Distance , Vec2( 0.0, 0.0 ) )         Dim as Vec2 TangentVector = NormalVector.PerpCW()                  Dim as Single distance_error = distance - rest_distance                  Dim As Vec2 contact_a = ball[a].Position-ball[a].radius*NormalVector         Dim As Vec2 contact_b = ball[b].Position+ball[b].radius*NormalVector                  Dim as Vec2 contact_velocity_a = ball[a].Velocity+ball[a].ang_Velocity*(ball[a].Position-contact_a).PerpCW()         Dim as Vec2 contact_velocity_b = ball[b].Velocity+ball[b].ang_Velocity*(ball[b].Position-contact_b).PerpCW()                  Dim as Vec2 contact_velocity = contact_velocity_a - contact_velocity_b         Dim as Single contact_velocityNormal = Dot(contact_velocity, normalVector)                  If contact_velocityNormal > 0.0 Then Continue For                     Dim As Single K = ( ball[a].CollisionStiffness + ball[b].CollisionStiffness ) * 0.5         Dim As Single D = ( ball[a].CollisionDamping + ball[b].CollisionDamping ) * 0.5                  'dim as Single impulseNormal = -(1+Restitution)*contact_velocityNormal/(ball[a].InverseMass+ball[b].InverseMass)         Dim as Single impulseNormal = -(distance_error*inv_dt*k + contact_velocityNormal*D ) * ( 1.0 / (ball[a].InverseMass+ball[b].InverseMass) )                  Dim As Single contact_velocityTangent = Dot(contact_velocity, tangentvector)                  Dim As Single FrictionCoefficient = IIf( Abs(contact_velocityTangent) < StaticFrictionVelocity, _                                                  ( Ball[a].StaticFriction  + Ball[b].StaticFriction  ) * 0.5, _                                                  ( Ball[a].DynamicFriction + Ball[b].DynamicFriction ) * 0.5 )                  Dim as Single MaxImpulseTangent = -contact_velocityTangent * ( 1.0 / (Ball[a].InverseMass+Ball[b].InverseMass+_         Ball[a].RadiusSquared*Ball[a].InverseI+Ball[b].RadiusSquared*Ball[b].InverseI) )                  Dim As Single ImpulseTangent = IIf( Abs( MaxImpulseTangent ) < ( FrictionCoefficient * ImpulseNormal ), _                                             MaxImpulseTangent, _                                             Sgn( MaxImpulseTangent ) * ( FrictionCoefficient * ImpulseNormal ) )                  'Dim As Single ImpulseTangent = MaxImpulseTangent                  Dim As Vec2 Impulse = ImpulseNormal * NormalVector + ImpulseTangent * TangentVector                  ball[a].Impulse += Impulse*ball[a].InverseMass         ball[a].angular_impulse += PerpDot(Impulse, ball[a].Position-contact_a)*ball[a].InverseI                  ball[b].Impulse -= Impulse*ball[b].InverseMass         ball[b].angular_impulse -= Perpdot(Impulse, ball[b].Position-contact_b)*ball[b].InverseI               Next         Next   End SubSub Controls()      With Ball[1]               If MultiKey(&h48) Then                  .Impulse.X += Cos(.Ang_Position)*100*.InverseMass         .Impulse.Y += Sin(.Ang_Position)*100*.InverseMass               EndIf            'If MultiKey(&h4b) Then .Ang_Position -= 0.05      'If MultiKey(&h4d) Then .Ang_Position += 0.05      If MultiKey(&h4b) Then .ang_Velocity -= 0.1      If MultiKey(&h4d) Then .ang_Velocity += 0.1      If MultiKey(&h50) Then .ang_Velocity = 0      '.ang_Velocity = 0            .cos_ang = cos(.ang_Position)      .sin_ang = sin(.ang_Position)         End With   End SubSub Gravity()For a As Integer = 0 to num_balls-2For b As Integer = a+1 to num_balls-1Dim As Vec2 DistanceVector = ball[a].Position-ball[b].PositionDim As Single DistanceSquared = LengthSquared(DistanceVector)Dim As Single DistanceCubed = DistanceSquared*Sqr(DistanceSquared)Ball[a].Impulse -= Ball[b].mass * G * DT * DistanceVector / DistanceCubedBall[b].Impulse += Ball[a].mass * G * DT * DistanceVector / DistanceCubedNextNextEnd SubSub Integrate()Controls()Gravity()For a As Integer = 0 to num_balls-1With Ball[a].Velocity += .Impulse.Position += .Velocity * dt.Impulse = Vec2( 0.0, 0.0 ).ang_Velocity += .angular_impulse.ang_Position += .ang_Velocity * dt.angular_impulse = 0.0.cos_ang = cos(.ang_Position).sin_ang = sin(.ang_Position)end WithNextEnd Subsub DrawSceneToScreen()ScreenLock()Clslocate  2, (scrn_wid\8)-3: print using "###"; fpsfor a As Integer = 0 to num_balls-1with ball[a]circle (.Position.x, .Position.y), .radius, 0,,,1, fcircle (.Position.x, .Position.y), .radius-2, .col,,,1, fLine(.Position.x, .Position.y)-(.Position.x+.cos_ang*.radius, .Position.y+.sin_ang*.radius), 0end WithNextScreenUnLock()end subsub brake()if timer < fps_timer thenfps_counter += 1Elsefps_timer = timer+1fps = fps_counterfps_counter = 0end ifDo while ( Timer - t0 ) < ( inv_rest_fps )Sleep 1, 1Loopt0 = timerend Sub`
Posts: 2080
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Physics question

h4tt3n wrote:I'm still around :-) Here, as promised, are some space physics examples. Some are rather old, but I'll just post them as they are, warts and all.

First, a vector library and a ball shaped space ship, asteroids in orbit around a central planet, also featuring collision with friction.

You control the yellow ball with the arrow keys. Up = thrust, left/right = rotate, down = stop rotating.

....

Cool, I see that you have a 'slightly' modified the gravitational constant, else thing would be very slow.
For linux systems: Dim shared as Single Double FPS_Timer, t0
h4tt3n
Posts: 694
Joined: Oct 22, 2005 21:12
Location: Denmark

### Re: Physics question

badidea wrote:Cool, I see that you have a 'slightly' modified the gravitational constant, else thing would be very slow.
For linux systems: Dim shared as Single Double FPS_Timer, t0

It's just a constant, you can give it any value you want. The real G is just as arbitrary, it depends on the random units we use. If you prefer to use G = 6.67e-11 then just crank up mass or delta time.
Posts: 2080
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Physics question

h4tt3n wrote:
badidea wrote:Cool, I see that you have a 'slightly' modified the gravitational constant, else thing would be very slow.
For linux systems: Dim shared as Single Double FPS_Timer, t0

It's just a constant, you can give it any value you want. The real G is just as arbitrary, it depends on the random units we use. If you prefer to use G = 6.67e-11 then just crank up mass or delta time.

I know, that is why I had in my previous code a heavy 'neutron star':

Code: Select all

`neutronstar.init(MOON_RADIUS * 1e-8, MOON_DENSITY * 1e8, sgl2d(+40, +20), rgb(255, 127, 0))`

Not sure if density and radius are realistic for a neutron star, but that were the numbers needed for a real-time gravity effect.
Never mind, I had the moon radius wrong by a factor of 1000.
Posts: 2080
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Physics question

Possibly the most frustrating game ever:

Code: Select all

`#Include "fbgfx.bi"Type int2d   As Integer x, y   Declare Constructor   Declare Constructor(x As Integer, y As Integer)   Declare Operator Cast () As StringEnd TypeConstructor int2dEnd ConstructorConstructor int2d(x As Integer, y As Integer)   This.x = x : This.y = yEnd ConstructorOperator = (a As int2d, b As int2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd OperatorOperator <> (a As int2d, b As int2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' "x, y"Operator int2d.cast () As String  Return Str(x) & "," & Str(y)End Operator' a + b Operator + (a As int2d, b As int2d) As int2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As int2d, b As int2d) As int2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As int2d) As int2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As int2d, b As int2d) As int2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As int2d, mul As Integer) As int2d   Return Type(a.x * mul, a.y * mul)End Operator' a \ bOperator \ (a As int2d, b As int2d) As int2d   Return Type(a.x \ b.x, a.y \ b.y)End Operator' a \ divOperator \ (a As int2d, div As Integer) As int2d   Return Type(a.x \ div, a.y \ div)End Operator'===============================================================================Type sgl2d   As Single x, y   Declare Constructor   Declare Constructor(x As Single, y As Single)   Declare Operator Cast () As StringEnd TypeConstructor sgl2dEnd ConstructorConstructor sgl2d(x As Single, y As Single)   This.x = x : This.y = yEnd Constructor' "x, y"Operator sgl2d.cast () As String   Return Str(x) & "," & Str(y)End Operator'---- operators ---' distance / lenthOperator Len (a As sgl2d) As Single   Return Sqr(a.x * a.x + a.y * a.y)End Operator' a = b ?Operator = (a As sgl2d, b As sgl2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd Operator' a != b ?Operator <> (a As sgl2d, b As sgl2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' a + b Operator + (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As sgl2d) As sgl2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As sgl2d, mul As Single) As sgl2d   Return Type(a.x * mul, a.y * mul)End Operator' a / divOperator / (a As sgl2d, div As Single) As sgl2d   Return Type(a.x / div, a.y / div)End Operator'---- extra functions ---Function cross(a As sgl2d, b As sgl2d) As Single   Return a.x * b.y - a.y * b.xEnd FunctionFunction lengthSqrd(a As sgl2d) As Single   Return (a.x * a.x) + (a.y * a.y) End FunctionFunction dist(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return Sqr((dx * dx) + (dy * dy)) End FunctionFunction distSqrd(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return (dx * dx) + (dy * dy) End FunctionFunction normalise(a As sgl2d) As sgl2d   Dim As sgl2d temp   Dim As Single length = Len(a)   Return sgl2d(a.x / length, a.y / length)End Function'==============================================================================='Note: y+ = up, x+ = right, (0,0) = centerType scaled_graphics_type   Dim As Single scale = 1 ' = 1 / pixel_size 'pixels / meter   'dim as int2d offset' = (scrn_w \ 2, h \ 2) 'offset in pixels   Dim As sgl2d offset   Dim As Integer w = -1, h = -1   Dim As Integer wc = -1, hc = -1 'center x,y   Declare Sub setScreen(w As Integer, h As Integer)   Declare Sub setScaling(scale As Single, offset As sgl2d)   Declare Sub clearScreen(c As ULong)   Declare Function pos2screen(p As sgl2d) As int2d   Declare Sub drawPixel(p As sgl2d, c As ULong)   Declare Sub drawCircle(p As sgl2d, r As Single, c As ULong)   Declare Sub drawCircleFilled(p As sgl2d, r As Single, c As ULong, cFill As ULong)   Declare Sub drawElipse(p As sgl2d, r As Single, aspect As Single, c As ULong)   Declare Sub drawLine(p1 As sgl2d, p2 As sgl2d, c As ULong)End TypeSub scaled_graphics_type.setScreen(w As Integer, h As Integer)   This.w = w 'width   This.h = h 'height   wc = w \ 2   hc = h \ 2   ScreenRes w, h, 32   Width w \ 8, h \ 16 'bigger fontEnd SubSub scaled_graphics_type.setScaling(scale As Single, offset As sgl2d)   This.scale = scale   This.offset = offsetEnd SubSub scaled_graphics_type.clearScreen(c As ULong)   Line(0, 0)-(w - 1, h - 1), c, bfEnd SubFunction scaled_graphics_type.pos2screen(p As sgl2d) As int2d   Return int2d(Int(wc + (p.x - offset.x) * scale), h - Int(hc + (p.y - offset.y) * scale))End FunctionSub scaled_graphics_type.drawPixel(p As sgl2d, c As ULong)   Dim As int2d posScrn = pos2screen(p)   PSet(posScrn.x, posScrn.y), cEnd SubSub scaled_graphics_type.drawCircle(p As sgl2d, r As Single, c As ULong)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, cEnd SubSub scaled_graphics_type.drawCircleFilled(p As sgl2d, r As Single, c As ULong, cFill As ULong)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, 0,,,,f   Circle(posScrn.x, posScrn.y), r * scale, cEnd SubSub scaled_graphics_type.drawElipse(p As sgl2d, r As Single, aspect As Single, c As ULong)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, c, , , aspectEnd SubSub scaled_graphics_type.drawLine(p1 As sgl2d, p2 As sgl2d, c As ULong)   Dim As int2d posScrn1 = pos2screen(p1)   Dim As int2d posScrn2 = pos2screen(p2)   Line(posScrn1.x, posScrn1.y)-(posScrn2.x, posScrn2.y), cEnd Sub'===============================================================================Const As Single PI = 4 * Atn(1)Const As Single RAD_PER_DEG = (PI / 180)Const As Single DEG_PER_RAD = 180 / PIConst As Single sinA = Sin((10 / 180) * PI)Const As Single cosA = Cos((10 / 180) * PI)Const As Single sinB = Sin((20 / 180) * PI)Const As Single cosB = Cos((20 / 180) * PI)Const K_ESC = Chr(27)Const K_MIN = Chr(45)Const K_UND = Chr(95)Const K_PLU = Chr(61)Const K_EQU = Chr(43)Const SCRN_W = 800, SCRN_H = 600Dim Shared As scaled_graphics_type sgsg.setScaling(2.0, sgl2d(0, 0))sg.setScreen(SCRN_W, SCRN_H)'-------------------------------------------------------------------------------Function limit(value As Single, min As Single, max As Single) As Single   If value < min Then Return min   If value > max Then Return max   Return valueEnd FunctionType polar   Dim As Single angle   Dim As Single magnitudeEnd TypeFunction polarToCartesian(angle As Single, radius As Single) As sgl2d   Return sgl2d(Cos(angle) * radius, Sin(angle) * radius)End FunctionFunction rotatedVector(v As sgl2d, rotAngle As Single) As sgl2d   Dim As sgl2d tmp   tmp.x = Cos(rotAngle) * v.x - Sin(rotAngle) * v.y   tmp.y = Sin(rotAngle) * v.x + Cos(rotAngle) * v.y   Return tmpEnd Function'-------------------------------------------------------------------------------Sub drawArrow(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.30 'reduce length   sg.drawLine(p2, p2 - sgl2d(cosB * dp.x - sinB * dp.y, sinB * dp.x + cosB * dp.y), c)   sg.drawLine(p2, p2 - sgl2d(cosB * dp.x + sinB * dp.y, cosB * dp.y - sinB * dp.x), c)End SubSub drawThruster(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.95 'reduce length   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x - sinA * dp.y, sinA * dp.x + cosA * dp.y), c)   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x + sinA * dp.y, cosA * dp.y - sinA * dp.x), c)End SubSub drawHelium3(p As sgl2d, r As Single, c As ULong)   For i As Integer = 0 To 2      sg.drawCircle(p + polarToCartesian((i / 3) * 2 * PI, 0.15 * r), 0.15 * r, c)   Next   sg.drawElipse(p, r, 2.0, c)   sg.drawElipse(p, r, 0.5, c)End SubSub drawStar(p As sgl2d, size As Single, c As ULong)   sg.drawLine(p - sgl2d(size / 2, 0) , p + sgl2d(size / 2, 0), c)   sg.drawLine(p - sgl2d(0, size / 2) , p + sgl2d(0, size / 2), c)End Sub'-------------------------------------------------------------------------------Type disc_object   Dim As Single radius '[m]   Dim As Single height '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   'linear motion properties   Dim As sgl2d position 'position [m]   Dim As Single lin_m 'mass [kg]   Dim As sgl2d lin_F 'force [N] [kg*m/s^2]   Dim As sgl2d lin_a 'acceleration [m/s^2]   Dim As sgl2d lin_v 'velocity [m/s]   'dim as sgl2d lin_p 'momentum [kg*m/s]   'dim as single lin_E 'Kinetic energy [J] [kg*m^2/s^2]   'Rotational motion properties   Dim As Single angle 'angular position (theta) [rad]   Dim As Single ang_m 'angular mass, moment of inertia (I) [kg*m^2]   Dim As Single ang_F 'torque (tau) [N*m] [kg*m^2/s^2]   Dim As Single ang_a 'angular velocity (alpha) [rad/s^2]   Dim As Single ang_v 'angular velocity (omega) [rad/s]   'dim as single ang_p 'angular momentum (L) [kg*m^2/s]   'dim as single ang_E 'Kinetic energy [J] [kg*m^2/s^2]   Declare Sub init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   Declare Sub update(dt As Double)   Declare Function getKineticEnergy() As SingleEnd Type'Set radius, height, density, position'Calculate mass and rotational inertiaSub disc_object.init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   radius = r   height = h   density = d   position = p   colour = c   lin_m = PI * r ^ 2 * d   ang_m = 0.5 * lin_m * r ^ 2End Sub'update position and angleSub disc_object.update(dt As Double)   lin_a = lin_F / lin_m   lin_v += lin_a * dt   position += lin_v * dt   ang_a = ang_F / ang_m   ang_v += ang_a * dt   angle += ang_v * dtEnd SubFunction disc_object.getKineticEnergy() As Single   Dim As Single lin_E = 0.5 * lin_m * lengthSqrd(lin_v)   Dim As Single ang_E = 0.5 * ang_m * ang_v * ang_v   Return lin_E + ang_EEnd FunctionSub drawShip(ship As disc_object)   'calculate ships tail pointer / triangle   Dim As sgl2d forwardPos = polarToCartesian(ship.angle - 90 * RAD_PER_DEG, ship.radius * 2.2)   Dim As sgl2d leftBackPos = polarToCartesian(ship.angle - 135 * RAD_PER_DEG, ship.radius * 1.0) '(90 + 45)   Dim As sgl2d rightBackPos = polarToCartesian(ship.angle - 45 * RAD_PER_DEG, ship.radius * 1.0) '(90 - 45)   sg.drawCircle(ship.position, ship.radius, ship.colour) 'flying saucer   sg.drawLine(ship.position + forwardPos, ship.position + leftBackPos, ship.colour)   sg.drawLine(ship.position + forwardPos, ship.position + rightBackPos, ship.colour)End Sub'-------------------------------------------------------------------------------Type thruster_type   '''init paramaters   Dim As polar polarForce '(rad, N)   Dim As polar polarPos '(rad, m)   '''variable paramaters   Dim As sgl2d forceVector '(N, N)   Dim As sgl2d relPos, absPos '(m, m)   Dim As Integer active   Declare Sub init(forceMagnitude As Single, forceDirection As Single, posAngle As Single, posRadius As Single)   Declare Sub updatePosition(bodyPos As sgl2d, bodyAngle As Single)End TypeSub thruster_type.init(forceDirection As Single, forceMagnitude As Single, posAngle As Single, posRadius As Single)   polarForce = Type(forceDirection, forceMagnitude) 'thruster action   polarPos = Type(posAngle, posRadius) 'position of thruster on shipEnd SubSub thruster_type.updatePosition(bodyPos As sgl2d, bodyAngle As Single)   relPos = polarToCartesian(bodyAngle + polarPos.angle, polarPos.magnitude)   absPos = bodyPos + relPosEnd Sub'-------------------------------------------------------------------------------Const As Single GRAV_CONST = 6.67e-11 '[m3/(kg*s^2)Type astro_body   Dim As Single radius '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   Dim As sgl2d position 'position [m]   Dim As Single mass '[kg]   Declare Sub init(r As Single, d As Single, p As sgl2d, c As ULong)End Type'Set radius, density, position'Calculate mass and rotational inertiaSub astro_body.init(r As Single, d As Single, p As sgl2d, c As ULong)   radius = r   density = d   position = p   colour = c   mass = PI * r ^ 2 * dEnd SubFunction gravForce(m1 As Single, m2 As Single, r As Single) As Single   Return GRAV_CONST * (m1 * m2) / (r * r)End FunctionFunction gravForceVector(m1 As Single, Pos1 As sgl2d, m2 As Single, pos2 As sgl2d) As sgl2d   Dim As Single distSquared = distSqrd(pos2, Pos1)   Dim As sgl2d unitVector12 = (Pos1 - pos2) / Sqr(distSquared)   Return unitVector12 * (-GRAV_CONST * (m1 * m2) / distSquared)End FunctionFunction findNearestBody(refPos As sgl2d, body() As astro_body) As Integer   Dim As Integer nearestBodyId = 0   Dim As Single nearestBodyDistSqrd = distSqrd(refPos, body(0).position)   Dim As Single currentBodyDistSqrd   For i As Integer = 1 To UBound(body)      currentBodyDistSqrd = distSqrd(refPos, body(i).position)      If currentBodyDistSqrd < nearestBodyDistSqrd Then         nearestBodyDistSqrd = currentBodyDistSqrd         nearestBodyId = i      End If   Next   Return nearestBodyId End FunctionType star_type   Dim As sgl2d position '[m]   Dim As Single size   Dim As ULong colour   Declare Sub init(p As sgl2d, s As Single, c As ULong)End TypeSub star_type.init(p As sgl2d, s As Single, c As ULong)   position = p   size = s   colour = cEnd Sub'-------------------------------------------------------------------------------Const As Single MOON_RADIUS = 1737e+6 '[m]Const As Single MOON_DENSITY = 3344 '[kg/m^3]Const NUM_THRUSTERS = 6Const L_FW_THR = 0 'left forward thrusterConst R_FW_THR = 1 'right forward thrusterConst L_LO_THR = 2Const R_LO_THR = 3Const L_HI_THR = 4Const R_HI_THR = 5Dim As String keyDim As Integer quit = 0Dim As disc_object shipDim As thruster_type thruster(NUM_THRUSTERS - 1)Const NUM_ASTEROID = 80Dim As astro_body asteroid(NUM_ASTEROID-1)Const NUM_HELIUM = 10ReDim As astro_body helium(NUM_HELIUM-1)Const As Single maxFuel = 1e6 'N*sDim As Single fuel = maxFuelConst NUM_STARS = 150Dim As star_type star(NUM_STARS-1)ship.init(10, 1, 5, sgl2d(0, -50), RGB(127, 223, 0))For i As Integer = 0 To UBound(asteroid)   asteroid(i).init(5 + 4 / (Rnd + 0.2), 1000, sgl2d((Rnd - 0.5) * 2000, (Rnd - 0.5) * 2000), RGB(Rnd * 64 + 127, Rnd * 64 + 95, 127))NextFor i As Integer = 0 To UBound(helium)   helium(i).init(5 + 4 / (Rnd + 0.2), 1000, sgl2d((Rnd - 0.5) * 2000, (Rnd - 0.5) * 2000), RGB(255, 191, 0))NextFor i As Integer = 0 To UBound(star)   star(i).init(sgl2d((Rnd - 0.5) * 4000, (Rnd - 0.5) * 4000), Rnd * 5 + 2, RGB(Rnd * 64 + 191, Rnd * 64 + 191, Rnd * 64 + 191))Next'force angle, force magnitude, polar thruster position thruster(L_FW_THR).init(0.5 * pi, 1.2e4, -0.75 * pi, ship.radius)thruster(R_FW_THR).init(0.5 * pi, 1.2e4, -0.25 * pi, ship.radius)thruster(L_LO_THR).init(0.0 * pi, 8e3, -0.75 * pi, ship.radius)thruster(R_LO_THR).init(1.0 * pi, 8e3, -0.25 * pi, ship.radius)thruster(L_HI_THR).init(0.0 * pi, 8e3, +0.75 * pi, ship.radius)thruster(R_HI_THR).init(1.0 * pi, 8e3, +0.25 * pi, ship.radius)'intro textLocate 10, 20: Print "HELIUM-3 SPACE RACE"Locate 12, 20: Print "Scoop up all the helium-3 clouds as fast as possible."Locate 13, 20: Print "Your ship needs helium-3 for its fusion powered trhusters."Locate 14, 20: Print "Do not run out of it and do not collide with the asteroids."Locate 15, 20: Print "Post your best time on the forum."Locate 17, 20: Print "Press <ENTER> to start";While InKey <> Chr(13)   Sleep 1WendDim As Double tStart = Timer, tNow = tStart, tPrev = tNow, dt = 0While quit = 0   'reset stuff   ship.lin_F = sgl2d(0, 0)   ship.ang_F = 0   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).active = 0   Next   If MultiKey(FB.SC_UP) Then      thruster(L_FW_THR).active = 1      thruster(R_FW_THR).active = 1      fuel -= thruster(L_FW_THR).polarForce.magnitude * dt      fuel -= thruster(R_FW_THR).polarForce.magnitude * dt   End If   If MultiKey(FB.SC_LEFT) Then      thruster(L_LO_THR).active = 1      thruster(R_HI_THR).active = 1      fuel -= thruster(L_LO_THR).polarForce.magnitude * dt      fuel -= thruster(R_HI_THR).polarForce.magnitude * dt   End If   If MultiKey(FB.SC_RIGHT) Then      thruster(R_LO_THR).active = 1      thruster(L_HI_THR).active = 1      fuel -= thruster(R_LO_THR).polarForce.magnitude * dt      fuel -= thruster(L_HI_THR).polarForce.magnitude * dt   End If   If key = K_ESC Then quit = 1   For i As Integer = 0 To NUM_THRUSTERS - 1      'forces on body by active thrusters      If thruster(i).active > 0 Then         Dim As Single thrust = thruster(i).polarForce.magnitude         thruster(i).forceVector = polarToCartesian(ship.angle + thruster(i).polarForce.angle, thrust)         ship.lin_F += thruster(i).forceVector         ship.ang_F += cross(thruster(i).relPos, thruster(i).forceVector)      End If   Next   ship.update(dt) 'position and angle   sg.offset = ship.position   sg.scale = limit(100 / Len(ship.lin_v), 0.5, 2.0)   'do always for display   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).updatePosition(ship.position, ship.angle)   Next   Dim As Integer nearestAsteroidId = findNearestBody(ship.position, asteroid())   Dim As astro_body Ptr pAsteroid = @asteroid(nearestAsteroidId)   If dist(ship.position, pAsteroid->position) < (ship.radius + pAsteroid->radius) Then      quit = 2 'crash   End If   Dim As Integer nearestHeliumId = findNearestBody(ship.position, helium())      If fuel <= 0 Then quit = 3      'display   ScreenLock   sg.clearScreen(0)   Locate 2, 2 : Print "<UP>, <LEFT>, <RIGHT> for thrusters, <ESC> to exit";   Locate 3, 2 : Print "Nearest helium distance [m]: "; CInt(dist(ship.position, helium(nearestHeliumId).position));   Locate 4, 2 : Print "Kinetic engergy [kJ]: "; CInt(ship.getKineticEnergy() * 1e-3);   Locate 5, 2 : Print "Fuel remaining [%]: "; CInt((fuel / maxFuel) * 100);   Locate 6, 2 : Print "Remaining helium3 clouds: "; UBound(helium) + 1;   'draw stars background   For i As Integer = 0 To UBound(star)      drawStar(star(i).position * 0.75 + ship.position * 0.25, star(i).size, star(i).colour)   Next   drawShip(ship)   'draw active thrusters   For i As Integer = 0 To NUM_THRUSTERS - 1      Dim As ULong c = IIf(i < 4, RGB(255, 255, 0), RGB(255, 255, 255))      If thruster(i).active > 0 Then         drawThruster(thruster(i).absPos, thruster(i).absPos - thruster(i).forceVector / 1e3, RGB(255, 63, 0)) 'thruster force indicator      End If   Next   'draw asteroids   For i As Integer = 0 To UBound(asteroid)      sg.drawCircleFilled(asteroid(i).position, asteroid(i).radius, asteroid(i).colour, 0)   Next   'draw helium 'clouds'   For i As Integer = 0 To UBound(helium)      drawHelium3(helium(i).position, helium(i).radius, IIf(nearestHeliumId = i, RGB(191, 191, 255), helium(i).colour))   Next   Dim As sgl2d heliumPointer = normalise(ship.position - helium(nearestHeliumId).position)   drawArrow(ship.position, ship.position - heliumPointer * ship.radius * 2, RGB(191, 191, 255))   ScreenUnLock   'clean up after displaying   Dim As astro_body Ptr pHelium = @helium(nearestHeliumId)   If dist(ship.position, pHelium->position) < (ship.radius + pHelium->radius * 0.5) Then      If UBound(helium) > 0 Then         'remove form list         helium(nearestHeliumId) = helium(UBound(helium))         ReDim Preserve helium(UBound(helium) - 1)         fuel = maxFuel      Else         'last item         quit = 4      End If   End If   'time update   key = InKey()   Sleep 1   tPrev = tNow   tNow = Timer   dt = tNow - tPrevWendIf quit > 1 Then 'Crashed or No fuel   If quit = 2 Then ship.colour = RGB(233, 0, 0)   If quit = 3 Then ship.colour = RGB(233, 191, 191)   drawShip(ship)   Locate 8, 2   If quit = 2 Then Print "Ship crashed";   If quit = 3 Then Print "Ship out of fuel";   If quit = 4 Then Print "Well done all helium3 collected. Your time: " + Str(CInt(tNow - tStart)) + " seconds";   Locate 9, 2: Print "press <ENTER> to exit";   While InKey <> Chr(13)      Sleep 1   WendEnd IfScreen 0Print "End"'TODO:'rotating helium3'shoot asteroids'background stars : optimize performance`

Update 2019-09-04: Backgound stars added. New personal record: 244 seconds.
Gunslinger
Posts: 39
Joined: Mar 08, 2016 19:10
Location: The Netherlands

### Re: Physics question

Just got 189 seconds on second run full hd :-)
I'm a drone drone pilot and that is 3 axels, gravity and momentum to fight with.
Posts: 2080
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Physics question

Small update:
* One can shoot at a asteroid to remove it, costs 10% fuel
* Helium-3 atom clouds with rotating core animation
* Additional control of side thrusters <A>, <D> (does not make control easier)

Code: Select all

`#Include "fbgfx.bi"Type int2d   As Integer x, y   Declare Constructor   Declare Constructor(x As Integer, y As Integer)   Declare Operator Cast () As StringEnd TypeConstructor int2dEnd ConstructorConstructor int2d(x As Integer, y As Integer)   This.x = x : This.y = yEnd ConstructorOperator = (a As int2d, b As int2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd OperatorOperator <> (a As int2d, b As int2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' "x, y"Operator int2d.cast () As String  Return Str(x) & "," & Str(y)End Operator' a + b Operator + (a As int2d, b As int2d) As int2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As int2d, b As int2d) As int2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As int2d) As int2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As int2d, b As int2d) As int2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As int2d, mul As Integer) As int2d   Return Type(a.x * mul, a.y * mul)End Operator' a \ bOperator \ (a As int2d, b As int2d) As int2d   Return Type(a.x \ b.x, a.y \ b.y)End Operator' a \ divOperator \ (a As int2d, div As Integer) As int2d   Return Type(a.x \ div, a.y \ div)End Operator'===============================================================================Type sgl2d   As Single x, y   Declare Constructor   Declare Constructor(x As Single, y As Single)   Declare Operator Cast () As StringEnd TypeConstructor sgl2dEnd ConstructorConstructor sgl2d(x As Single, y As Single)   This.x = x : This.y = yEnd Constructor' "x, y"Operator sgl2d.cast () As String   Return Str(x) & "," & Str(y)End Operator'---- operators ---' distance / lenthOperator Len (a As sgl2d) As Single   Return Sqr(a.x * a.x + a.y * a.y)End Operator' a = b ?Operator = (a As sgl2d, b As sgl2d) As boolean   If a.x <> b.x Then Return false   If a.y <> b.y Then Return false   Return trueEnd Operator' a != b ?Operator <> (a As sgl2d, b As sgl2d) As boolean   If a.x = b.x And a.y = b.y Then Return false   Return trueEnd Operator' a + b Operator + (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x + b.x, a.y + b.y)End Operator' a - bOperator - (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x - b.x, a.y - b.y)End Operator' -aOperator - (a As sgl2d) As sgl2d   Return Type(-a.x, -a.y)End Operator' a * bOperator * (a As sgl2d, b As sgl2d) As sgl2d   Return Type(a.x * b.x, a.y * b.y)End Operator' a * mulOperator * (a As sgl2d, mul As Single) As sgl2d   Return Type(a.x * mul, a.y * mul)End Operator' a / divOperator / (a As sgl2d, div As Single) As sgl2d   Return Type(a.x / div, a.y / div)End Operator'---- extra functions ---Function cross(a As sgl2d, b As sgl2d) As Single   Return a.x * b.y - a.y * b.xEnd FunctionFunction lengthSqrd(a As sgl2d) As Single   Return (a.x * a.x) + (a.y * a.y) End FunctionFunction dist(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return Sqr((dx * dx) + (dy * dy)) End FunctionFunction distSqrd(a As sgl2d, b As sgl2d) As Single   Dim As Single dx = a.x - b.x   Dim As Single dy = a.y - b.y   Return (dx * dx) + (dy * dy) End FunctionFunction normalise(a As sgl2d) As sgl2d   Dim As sgl2d temp   Dim As Single length = Len(a)   Return sgl2d(a.x / length, a.y / length)End Function'==============================================================================='Note: y+ = up, x+ = right, (0,0) = centerType scaled_graphics_type   Dim As Single scale = 1 ' = 1 / pixel_size 'pixels / meter   'dim as int2d offset' = (scrn_w \ 2, h \ 2) 'offset in pixels   Dim As sgl2d offset   Dim As Integer w = -1, h = -1   Dim As Integer wc = -1, hc = -1 'center x,y   Declare Sub setScreen(w As Integer, h As Integer)   Declare Sub setScaling(scale As Single, offset As sgl2d)   Declare Sub clearScreen(c As ULong)   Declare Function pos2screen(p As sgl2d) As int2d   Declare Sub drawPixel(p As sgl2d, c As ULong)   Declare Sub drawCircle(p As sgl2d, r As Single, c As ULong)   Declare Sub drawCircleFilled(p As sgl2d, r As Single, c As ULong, cFill As ULong)   Declare Sub drawElipse(p As sgl2d, r As Single, aspect As Single, c As ULong)   Declare Sub drawLine(p1 As sgl2d, p2 As sgl2d, c As ULong)End TypeSub scaled_graphics_type.setScreen(w As Integer, h As Integer)   This.w = w 'width   This.h = h 'height   wc = w \ 2   hc = h \ 2   ScreenRes w, h, 32   Width w \ 8, h \ 16 'bigger fontEnd SubSub scaled_graphics_type.setScaling(scale As Single, offset As sgl2d)   This.scale = scale   This.offset = offsetEnd SubSub scaled_graphics_type.clearScreen(c As ULong)   Line(0, 0)-(w - 1, h - 1), c, bfEnd SubFunction scaled_graphics_type.pos2screen(p As sgl2d) As int2d   Return int2d(Int(wc + (p.x - offset.x) * scale), h - Int(hc + (p.y - offset.y) * scale))End FunctionSub scaled_graphics_type.drawPixel(p As sgl2d, c As ULong)   Dim As int2d posScrn = pos2screen(p)   PSet(posScrn.x, posScrn.y), cEnd SubSub scaled_graphics_type.drawCircle(p As sgl2d, r As Single, c As ULong)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, cEnd SubSub scaled_graphics_type.drawCircleFilled(p As sgl2d, r As Single, c As ULong, cFill As ULong)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, 0,,,,f   Circle(posScrn.x, posScrn.y), r * scale, cEnd SubSub scaled_graphics_type.drawElipse(p As sgl2d, r As Single, aspect As Single, c As ULong)   Dim As int2d posScrn = pos2screen(p)   Circle(posScrn.x, posScrn.y), r * scale, c, , , aspectEnd SubSub scaled_graphics_type.drawLine(p1 As sgl2d, p2 As sgl2d, c As ULong)   Dim As int2d posScrn1 = pos2screen(p1)   Dim As int2d posScrn2 = pos2screen(p2)   Line(posScrn1.x, posScrn1.y)-(posScrn2.x, posScrn2.y), cEnd Sub'===============================================================================Const As Single PI = 4 * Atn(1)Const As Single RAD_PER_DEG = (PI / 180)Const As Single DEG_PER_RAD = 180 / PIConst As Single sinA = Sin((10 / 180) * PI)Const As Single cosA = Cos((10 / 180) * PI)Const As Single sinB = Sin((20 / 180) * PI)Const As Single cosB = Cos((20 / 180) * PI)Const K_ENTER = Chr(13)Const K_ESC = Chr(27)Const K_MIN = Chr(45)Const K_UND = Chr(95)Const K_PLU = Chr(61)Const K_EQU = Chr(43)Const SCRN_W = 800, SCRN_H = 600Dim Shared As scaled_graphics_type sgsg.setScaling(2.0, sgl2d(0, 0))sg.setScreen(SCRN_W, SCRN_H)'-------------------------------------------------------------------------------Sub waitForKey(key As String)   While InKey <> key      Sleep 1   WendEnd SubFunction limit(value As Single, min As Single, max As Single) As Single   If value < min Then Return min   If value > max Then Return max   Return valueEnd FunctionType polar   Dim As Single angle   Dim As Single magnitudeEnd TypeFunction polarToCartesian(angle As Single, radius As Single) As sgl2d   Return sgl2d(Cos(angle) * radius, Sin(angle) * radius)End FunctionFunction rotatedVector(v As sgl2d, rotAngle As Single) As sgl2d   Dim As sgl2d tmp   tmp.x = Cos(rotAngle) * v.x - Sin(rotAngle) * v.y   tmp.y = Sin(rotAngle) * v.x + Cos(rotAngle) * v.y   Return tmpEnd Function'-------------------------------------------------------------------------------Sub drawArrow(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.30 'reduce length   sg.drawLine(p2, p2 - sgl2d(cosB * dp.x - sinB * dp.y, sinB * dp.x + cosB * dp.y), c)   sg.drawLine(p2, p2 - sgl2d(cosB * dp.x + sinB * dp.y, cosB * dp.y - sinB * dp.x), c)End SubSub drawThruster(p1 As sgl2d, p2 As sgl2d, c As ULong)   sg.drawLine(p1, p2, c)   Dim As sgl2d dp = (p2 - p1) * 0.95 'reduce length   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x - sinA * dp.y, sinA * dp.x + cosA * dp.y), c)   sg.drawLine(p1, p1 + sgl2d(cosA * dp.x + sinA * dp.y, cosA * dp.y - sinA * dp.x), c)End SubSub drawHelium3(p As sgl2d, r As Single, rot As Single, c As ULong)   For i As Integer = 0 To 2      sg.drawCircle(p + polarToCartesian((i / 3) * 2 * PI + rot, 0.15 * r), 0.15 * r, c)   Next   sg.drawElipse(p, r, 2.0, c)   sg.drawElipse(p, r, 0.5, c)End SubSub drawStar(p As sgl2d, size As Single, c As ULong)   sg.drawLine(p - sgl2d(size / 2, 0) , p + sgl2d(size / 2, 0), c)   sg.drawLine(p - sgl2d(0, size / 2) , p + sgl2d(0, size / 2), c)End Sub'-------------------------------------------------------------------------------Type disc_object   Dim As Single radius '[m]   Dim As Single height '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   'linear motion properties   Dim As sgl2d position 'position [m]   Dim As Single lin_m 'mass [kg]   Dim As sgl2d lin_F 'force [N] [kg*m/s^2]   Dim As sgl2d lin_a 'acceleration [m/s^2]   Dim As sgl2d lin_v 'velocity [m/s]   'dim as sgl2d lin_p 'momentum [kg*m/s]   'dim as single lin_E 'Kinetic energy [J] [kg*m^2/s^2]   'Rotational motion properties   Dim As Single angle 'angular position (theta) [rad]   Dim As Single ang_m 'angular mass, moment of inertia (I) [kg*m^2]   Dim As Single ang_F 'torque (tau) [N*m] [kg*m^2/s^2]   Dim As Single ang_a 'angular velocity (alpha) [rad/s^2]   Dim As Single ang_v 'angular velocity (omega) [rad/s]   'dim as single ang_p 'angular momentum (L) [kg*m^2/s]   'dim as single ang_E 'Kinetic energy [J] [kg*m^2/s^2]   Declare Sub init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   Declare Sub update(dt As Double)   Declare Function getKineticEnergy() As SingleEnd Type'Set radius, height, density, position'Calculate mass and rotational inertiaSub disc_object.init(r As Single, h As Single, d As Single, p As sgl2d, c As ULong)   radius = r   height = h   density = d   position = p   colour = c   lin_m = PI * r ^ 2 * d   ang_m = 0.5 * lin_m * r ^ 2End Sub'update position and angleSub disc_object.update(dt As Double)   lin_a = lin_F / lin_m   lin_v += lin_a * dt   position += lin_v * dt   ang_a = ang_F / ang_m   ang_v += ang_a * dt   angle += ang_v * dtEnd SubFunction disc_object.getKineticEnergy() As Single   Dim As Single lin_E = 0.5 * lin_m * lengthSqrd(lin_v)   Dim As Single ang_E = 0.5 * ang_m * ang_v * ang_v   Return lin_E + ang_EEnd FunctionSub drawShip(ship As disc_object)   'calculate ships tail pointer / triangle   Dim As sgl2d forwardPos = polarToCartesian(ship.angle - 90 * RAD_PER_DEG, ship.radius * 2.2)   Dim As sgl2d leftBackPos = polarToCartesian(ship.angle - 135 * RAD_PER_DEG, ship.radius * 1.0) '(90 + 45)   Dim As sgl2d rightBackPos = polarToCartesian(ship.angle - 45 * RAD_PER_DEG, ship.radius * 1.0) '(90 - 45)   sg.drawCircle(ship.position, ship.radius, ship.colour) 'flying saucer   sg.drawLine(ship.position + forwardPos, ship.position + leftBackPos, ship.colour)   sg.drawLine(ship.position + forwardPos, ship.position + rightBackPos, ship.colour)End Sub'-------------------------------------------------------------------------------Type thruster_type   '''init paramaters   Dim As polar polarForce '(rad, N)   Dim As polar polarPos '(rad, m)   '''variable paramaters   Dim As sgl2d forceVector '(N, N)   Dim As sgl2d relPos, absPos '(m, m)   Dim As Integer active   Declare Sub init(forceMagnitude As Single, forceDirection As Single, posAngle As Single, posRadius As Single)   Declare Sub updatePosition(bodyPos As sgl2d, bodyAngle As Single)End TypeSub thruster_type.init(forceDirection As Single, forceMagnitude As Single, posAngle As Single, posRadius As Single)   polarForce = Type(forceDirection, forceMagnitude) 'thruster action   polarPos = Type(posAngle, posRadius) 'position of thruster on shipEnd SubSub thruster_type.updatePosition(bodyPos As sgl2d, bodyAngle As Single)   relPos = polarToCartesian(bodyAngle + polarPos.angle, polarPos.magnitude)   absPos = bodyPos + relPosEnd Sub'-------------------------------------------------------------------------------Const As Single GRAV_CONST = 6.67e-11 '[m3/(kg*s^2)Type astro_body   Dim As Single radius '[m]   Dim As Single density '[kg/m^3]   Dim As ULong colour '[m]   Dim As sgl2d position 'position [m]   Dim As Single mass '[kg]   Dim As Single rotation '[rad]   Declare Sub init(r As Single, d As Single, p As sgl2d, c As ULong)End Type'Set radius, density, position'Calculate mass and rotational inertiaSub astro_body.init(r As Single, d As Single, p As sgl2d, c As ULong)   radius = r   density = d   position = p   colour = c   mass = PI * r ^ 2 * dEnd SubFunction gravForce(m1 As Single, m2 As Single, r As Single) As Single   Return GRAV_CONST * (m1 * m2) / (r * r)End FunctionFunction gravForceVector(m1 As Single, Pos1 As sgl2d, m2 As Single, pos2 As sgl2d) As sgl2d   Dim As Single distSquared = distSqrd(pos2, Pos1)   Dim As sgl2d unitVector12 = (Pos1 - pos2) / Sqr(distSquared)   Return unitVector12 * (-GRAV_CONST * (m1 * m2) / distSquared)End FunctionFunction findNearestBody(refPos As sgl2d, body() As astro_body) As Integer   Dim As Integer nearestBodyId = 0   Dim As Single nearestBodyDistSqrd = distSqrd(refPos, body(0).position)   Dim As Single currentBodyDistSqrd   For i As Integer = 1 To UBound(body)      currentBodyDistSqrd = distSqrd(refPos, body(i).position)      If currentBodyDistSqrd < nearestBodyDistSqrd Then         nearestBodyDistSqrd = currentBodyDistSqrd         nearestBodyId = i      End If   Next   Return nearestBodyId End FunctionType star_type   Dim As sgl2d position '[m]   Dim As Single size   Dim As ULong colour   Declare Sub init(p As sgl2d, s As Single, c As ULong)End TypeSub star_type.init(p As sgl2d, s As Single, c As ULong)   position = p   size = s   colour = cEnd SubType bullet_type   Dim As sgl2d position   Dim As sgl2d velocity   Dim As Single radius = 3.0   Dim As Integer active   Dim As Double endTime   Dim As ULong colour   Declare Sub init(p As sgl2d, v As sgl2d, lifeTime As Double, c As ULong)End TypeSub bullet_type.init(p As sgl2d, v As sgl2d, lifeTime As Double, c As ULong)   position = p   velocity = v   endTime = Timer + lifeTime   active = 1   colour = cEnd Sub'-------------------------------------------------------------------------------Const As Single MOON_RADIUS = 1737e+6 '[m]Const As Single MOON_DENSITY = 3344 '[kg/m^3]Const NUM_THRUSTERS = 6Const L_FW_THR = 0 'left forward thrusterConst R_FW_THR = 1 'right forward thrusterConst L_LO_THR = 2Const R_LO_THR = 3Const L_HI_THR = 4Const R_HI_THR = 5Const QUIT_NO = 0Const QUIT_USER = 1Const QUIT_CRASH = 2Const QUIT_FUEL = 3Const QUIT_WINNER = 4Dim As Integer quit = 0Dim As disc_object shipDim As thruster_type thruster(NUM_THRUSTERS - 1)'const NUM_ASTEROID = 80ReDim As astro_body asteroid(80 - 1)'const NUM_HELIUM = 10ReDim As astro_body helium(10 - 1)Const As Single maxFuel = 1e6 'N*sDim As Single fuel = maxFuelConst NUM_STARS = 150Dim As star_type star(NUM_STARS-1)Dim As bullet_type bulletDim As astro_body Ptr pAsteroid, pHeliumDim As Integer nearestAsteroidToBulletId = -1Dim As Integer nearestHeliumIdDim As Integer nearestAsteroidIdDim As Integer asteroidRemove = 0ship.init(10, 1, 5, sgl2d(0, -50), RGB(127, 223, 0))For i As Integer = 0 To UBound(asteroid)   asteroid(i).init(5 + 4 / (Rnd + 0.2), 1000, sgl2d((Rnd - 0.5) * 2000, (Rnd - 0.5) * 2000), RGB(Rnd * 64 + 127, Rnd * 64 + 95, 127))NextFor i As Integer = 0 To UBound(helium)   helium(i).init(5 + 4 / (Rnd + 0.2), 1000, sgl2d((Rnd - 0.5) * 2000, (Rnd - 0.5) * 2000), RGB(255, 191, 0))NextFor i As Integer = 0 To UBound(star)   star(i).init(sgl2d((Rnd - 0.5) * 4000, (Rnd - 0.5) * 4000), Rnd * 5 + 2, RGB(Rnd * 64 + 191, Rnd * 64 + 191, Rnd * 64 + 191))Next'force angle, force magnitude, polar thruster position thruster(L_FW_THR).init(0.5 * pi, 1.2e4, -0.75 * pi, ship.radius)thruster(R_FW_THR).init(0.5 * pi, 1.2e4, -0.25 * pi, ship.radius)thruster(L_LO_THR).init(0.0 * pi, 8e3, -0.75 * pi, ship.radius)thruster(R_LO_THR).init(1.0 * pi, 8e3, -0.25 * pi, ship.radius)thruster(L_HI_THR).init(0.0 * pi, 8e3, +0.75 * pi, ship.radius)thruster(R_HI_THR).init(1.0 * pi, 8e3, +0.25 * pi, ship.radius)'intro textLocate 10, 20: Print "HELIUM-3 SPACE RACE"Locate 12, 20: Print "Scoop up all the helium-3 clouds as fast as possible."Locate 13, 20: Print "Your ship needs helium-3 for its fusion powered trhusters."Locate 14, 20: Print "Do not run out of it and do not collide with the asteroids."Locate 15, 20: Print "Post your best time on the forum."Locate 17, 20: Print "Press <ENTER> to start";Locate 24, 20: Print "Controls:";Locate 26, 20: Print " Fire: <SPACE>";Locate 27, 20: Print " Forward thrusters: <UP>";Locate 28, 20: Print " Rotation thrusters: <LEFT>, <RIGHT>";Locate 29, 20: Print " Side thrusters: <A>, <D>";Locate 30, 20: Print " Abort game: <ESC>";waitForKey(K_ENTER)Dim As Double tStart = Timer, tNow = tStart, tPrev = tNow, dt = 0While quit = 0   'reset stuff   ship.lin_F = sgl2d(0, 0)   ship.ang_F = 0   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).active = 0   Next   If MultiKey(FB.SC_UP) Then      thruster(L_FW_THR).active = 1      thruster(R_FW_THR).active = 1      fuel -= thruster(L_FW_THR).polarForce.magnitude * dt      fuel -= thruster(R_FW_THR).polarForce.magnitude * dt   End If   If MultiKey(FB.SC_LEFT) Then      thruster(L_LO_THR).active = 1      thruster(R_HI_THR).active = 1      fuel -= thruster(L_LO_THR).polarForce.magnitude * dt      fuel -= thruster(R_HI_THR).polarForce.magnitude * dt   End If   If MultiKey(FB.SC_RIGHT) Then      thruster(R_LO_THR).active = 1      thruster(L_HI_THR).active = 1      fuel -= thruster(R_LO_THR).polarForce.magnitude * dt      fuel -= thruster(L_HI_THR).polarForce.magnitude * dt   End If   If MultiKey(FB.SC_A) Then      thruster(R_LO_THR).active = 1      thruster(R_HI_THR).active = 1      fuel -= thruster(R_LO_THR).polarForce.magnitude * dt      fuel -= thruster(R_HI_THR).polarForce.magnitude * dt   End If   If MultiKey(FB.SC_D) Then      thruster(L_LO_THR).active = 1      thruster(L_HI_THR).active = 1      fuel -= thruster(L_LO_THR).polarForce.magnitude * dt      fuel -= thruster(L_HI_THR).polarForce.magnitude * dt   End If   '~ if multikey(FB.SC_P) then      '~ sleep 5000,1 'for taking a screenshot   '~ end if   If MultiKey(FB.SC_SPACE) Then      If bullet.active = 0 Then         Dim As sgl2d vBullet = ship.lin_v + polarToCartesian(ship.angle + pi/2, 50)         bullet.init(ship.position, vBullet, 3.0, RGB(255, 0, 0))         fuel -= maxFuel * 0.05 'takes 5% of fuel       End If   End If   If MultiKey(FB.SC_ESCAPE) Then quit = QUIT_USER   For i As Integer = 0 To NUM_THRUSTERS - 1      'forces on body by active thrusters      If thruster(i).active > 0 Then         Dim As Single thrust = thruster(i).polarForce.magnitude         thruster(i).forceVector = polarToCartesian(ship.angle + thruster(i).polarForce.angle, thrust)         ship.lin_F += thruster(i).forceVector         ship.ang_F += cross(thruster(i).relPos, thruster(i).forceVector)      End If   Next   ship.update(dt) 'position and angle   sg.offset = ship.position   sg.scale = limit(100 / Len(ship.lin_v), 0.5, 2.0)   'do always for display   For i As Integer = 0 To NUM_THRUSTERS - 1      thruster(i).updatePosition(ship.position, ship.angle)   Next   For i As Integer = 0 To UBound(helium)      helium(i).rotation += 300 * RAD_PER_DEG * dt 'N * degrees / second   Next   nearestAsteroidId = findNearestBody(ship.position, asteroid())   pAsteroid = @asteroid(nearestAsteroidId)   If dist(ship.position, pAsteroid->position) < (ship.radius + pAsteroid->radius) Then      quit = QUIT_CRASH   End If   nearestHeliumId = findNearestBody(ship.position, helium())      If fuel <= 0 Then quit = QUIT_FUEL      If bullet.active = 1 Then      If tNow > bullet.EndTime Then         bullet.active = 0      Else         bullet.position += bullet.velocity * dt         nearestAsteroidToBulletId = findNearestBody(bullet.position, asteroid())         asteroidRemove = 1      End If   End If      'display   ScreenLock   sg.clearScreen(0)   'draw stars background   For i As Integer = 0 To UBound(star)      drawStar(star(i).position * 0.75 + ship.position * 0.25, star(i).size, star(i).colour)   Next   drawShip(ship)   'draw active thrusters   For i As Integer = 0 To NUM_THRUSTERS - 1      Dim As ULong c = IIf(i < 4, RGB(255, 255, 0), RGB(255, 255, 255))      If thruster(i).active > 0 Then         drawThruster(thruster(i).absPos, thruster(i).absPos - thruster(i).forceVector / 1e3, RGB(255, 63, 0)) 'thruster force indicator      End If   Next   'draw asteroids   For i As Integer = 0 To UBound(asteroid)      sg.drawCircleFilled(asteroid(i).position, asteroid(i).radius, asteroid(i).colour, 0)   Next   'draw helium 'clouds'   For i As Integer = 0 To UBound(helium)      drawHelium3(helium(i).position, helium(i).radius, helium(i).rotation, IIf(nearestHeliumId = i, RGB(191, 191, 255), helium(i).colour))   Next   Dim As sgl2d heliumPointer = normalise(ship.position - helium(nearestHeliumId).position)   drawArrow(ship.position, ship.position - heliumPointer * ship.radius * 2, RGB(191, 191, 255))   If bullet.active = 1 Then      sg.drawCircle(bullet.position, bullet.radius, bullet.colour)   End If   Draw String (8, 8 + 0 * 16), "Nearest helium distance [m]: " + Str(CInt(dist(ship.position, helium(nearestHeliumId).position)))   Draw String (8, 8 + 1 * 16), "Kinetic engergy [kJ]: " + Str(CInt(ship.getKineticEnergy() * 1e-3))   Draw String (8, 8 + 2 * 16), "Fuel remaining [%]: " + Str(CInt((fuel / maxFuel) * 100))   Draw String (8, 8 + 3 * 16), "Remaining helium3 clouds: " + Str(UBound(helium) + 1)   ScreenUnLock   'clean up after displaying   pHelium = @helium(nearestHeliumId)   If dist(ship.position, pHelium->position) < (ship.radius + pHelium->radius * 0.5) Then      If UBound(helium) > 0 Then         'remove form list         helium(nearestHeliumId) = helium(UBound(helium))         ReDim Preserve helium(UBound(helium) - 1)         fuel = maxFuel      Else         'last item         Erase helium         quit = QUIT_WINNER      End If   End If   'asteroid hit by bullet?   If nearestAsteroidToBulletId <> -1 Then      pAsteroid = @asteroid(nearestAsteroidToBulletId)      If dist(bullet.position, pAsteroid->position) < (bullet.radius + pAsteroid->radius) Then         'remove asteroid from list         If UBound(asteroid) > 0 Then            'remove form list            asteroid(nearestAsteroidToBulletId) = asteroid(UBound(asteroid))            ReDim Preserve asteroid(UBound(asteroid) - 1)         Else            'last item            Erase asteroid         End If         bullet.endTime = tNow + 0.1         'bullet.active = 0      End If      nearestAsteroidToBulletId = -1   End If   'time update   Sleep 1   tPrev = tNow   tNow = Timer   dt = tNow - tPrevWendSelect Case quitCase QUIT_USER   Draw String (8, 8 + 6 * 16), "Abort by user"Case QUIT_CRASH   ship.colour = RGB(233, 0, 0)   drawShip(ship)   Draw String (8, 8 + 6 * 16), "Ship crashed"Case QUIT_FUEL   ship.colour = RGB(233, 191, 191)   drawShip(ship)   Draw String (8, 8 + 6 * 16), "Ship out of fuel"Case QUIT_WINNER   Draw String (8, 8 + 6 * 16), "Well done all helium3 collected. Your time: " + Str(CInt(tNow - tStart)) + " seconds"Case ElseEnd SelectDraw String (8, 8 + 7 * 16), "press <ENTER> to exit"waitForKey(K_ENTER)Screen 0Print "End"`

Todo:
* Code clean-up, move stuff into classes
dodicat
Posts: 6559
Joined: Jan 10, 2006 20:30
Location: Scotland

### Re: Physics question

Windows for fun with some sound.
(Some help from angros47's post regarding playing .mp3 files on win 10)
https://www.mediafire.com/file/euzi8vn0upn6bsr/RIP.zip/file