Controlled Deceleration

Blitz3D Forums/Blitz3D Programming/Controlled Deceleration

-Rick-(Posted 2014) [#1]
Working on a program and have run into a snag. In a nutshell I want a ship to Run from Star A to Star B with smooth acceleration and deceleration. I use 3 values.

Speed# which is the Maximum Speed
Acceleration# which is how much speed is increased.
Thrust# which is how much Acceleration increases or decreases.

Take off works fine. With Acceleration starting at 0 I just increase its value with Thrust until it reaches Speed. My ship takes off smoothly then cruises along until it reaches the Destination. But of course then its going from max speed to 0 ... don't want that.

I tried setting up a halfway point where acceleration increases until half the distance and then acceleration starts to decrease. This works fine if the distance between stars is less than how long it takes for the ship to reach maximum acceleration. Longer journeys leaves me with a ship that slows down too soon and reaches 0 acceleration before reaching the star.

I could go the easy route and just pick some arbitrary distance and then decrease the speed by %, but this would sometimes mean the ship's deceleration is higher than its acceleration. Thinking realistically, ship captains would just fly their ships backward so they would start out faster.

So I guess I'm wondering if anyone would know a way that I could figure out the point in which I would start slowing the ship down so that it arrived at the destination coordinates with 0 speed?


-Rick-(Posted 2014) [#2]
I did solve this in a round about way, however I would still be interested if anyone had any kind of formula that would work.

My solution was to add another Field to my ship Type called MaxAccelDist#. When a ship's acceleration matched the maximum speed the ship could go it would check to see if MaxAccelDist = 0. If it does then it would store the distance the ship had gone into it. If it doesn't = 0 then we would know it was already set and not update it. Then it would only begin slowing the ship down if its distance to the target was equal to or less than the MaxAccelDist. Since it is decelerating at the same rate it accelerated it end up at the destination coordinates by the time its acceleration reaches 0. Once it arrived at the destination it would reset the value of MaxAccelDist to 0 for the next leg of its journey.


Midimaster(Posted 2014) [#3]
There was the same question some weeks ago on the german forum and I answered with this sample code:



It bases on the fact, that a spaceship can only fire thrust or not. It has two rocket nozzles and uses one to slow down, if the distance is ok and both if the ship is too fast for the target. It stops the nozzles if the spaceship is to far away.

Now after every nozzle thrust the "only one nozzle distance" is calculated and compared with the real distance to the star. This causes ON/OFF for the nozzles next thrust.


Kryzon(Posted 2014) [#4]
I think you should remove the 'thrust' (or "jerk") element from your original concept.
You only need the (fixed) 'acceleration' and the (dynamic) 'velocity,' as they can still provide you with a smooth movement.

You need to use the kinematic equations for this, which are studied under physics.
I think the best one for your situation is this, the "Time Independent Equation:"

vf² = vo² + 2 * a * d

The equation above calculates the final velocity 'vf' of a body based on the velocity 'vo' that it has at the moment that you calculate the equation, its acceleration 'a' which is always the same and the displacement that the body will travel 'd'.
You can see other equations here.

We want the final velocity to be zero (the ship comes to a halt), we know our original velocity (the current one that the ship has), we know the acceleration (it's always the same), and we want to know the displacement that the ship will have (the distance between the target and source positions) so that it can slow down to zero under these conditions.
This "want to know" term means that we have to isolate the variable that represents the value that we want to know.

Isolating 'd,' with a desired final velocity 'vf' of zero.

vf² = vo² + 2*a*d

0 = vo² + 2*a*d

-2*a*d = vo²

d = vo² / -2*a

Replacing the variables with the appropriate names:

minimumDistance = currentSpeed² / -2*acceleration

Therefore,
the point in which I would start slowing the ship down so that it arrived at the destination coordinates with 0 speed?

When the ship is close to the target such that the distance between them is less than or equal to 'minimumDistance,' start decelerating the ship: Flip the sign of the acceleration.

Note that it's easier to do all this if you're keeping separate the direction and magnitude of the vectors involved. This means, you have the direction represented by an angle and the magnitudes represented by floating point variables that you later decompose into 'x' and 'y' components based on the sine and cosine of the angle.
If you are doing this, then you can probably insert the magnitudes already in the equation and it should work.

If you are keeping the vectors decomposed as 'x' and 'y' components, then you would need to retrieve their magnitudes by using the pythagorean theorem:
magnitude = Sqr( x² + y² )


-Rick-(Posted 2014) [#5]
Thanks for the response Kryzon! This will most likely still come in handy for me and I'm still digesting it for understanding. I ran your example code and followed it through and I understood what it was doing quite easily.

The reason I have the thrust variable is to be able to alter it with technology advances. It is a % of the max Speed. I will most likely do away with it later when I clean up the code and just use acc = acc + speed * % because I don't anticipate the thrust value not being tied into the percentage of the max speed.

I had actually looked into the kinematic equation for velocity (although I wasn't aware it was called that) but the conversion into blitz language was causing me problems. So it is well appreciated that I can now see how that was done.

Thank you very much!


Kryzon(Posted 2014) [#6]
Hello. I forgot to add this point.
Since you have a positive original speed and you are going to get a null final speed, the acceleration value that you input in that formula has to be negative.


-Rick-(Posted 2014) [#7]
Ack. I made a particularly bad assumption that I am just now realizing. I owe an apology to MidiMaster as I overlooked his contribution and for some reason (lack of sleep? degenerating mind from age?) and read the code he presented as if it was from Kryzon.

I am very sorry for doing that MidiMaster.


-Rick-(Posted 2014) [#8]
Originally I stuck in a sloppy movement code in my own program so that I could just get things working and allow me to continue coding other portions. It suffered in accuracy and often left ships stopping early and then slowly finishing the final distance. Upon revising how I handed Star/Planet coordiantes (to cut down on rounding errors) I was forced to revisit how I handled movement and MidiMaster's example proved invaluable.

I had to adapt it for 2d coordinate moving. Did some other modifications to allow changing the ShipMaxSpeed on the fly, and it now loops to continually go toward new target points once it reaches a target.

Thanks again to MidiMaster and Kryzon for helping me figure this out!

There is one small quirk in this in that the value of the ShipThrust *MUST* be smaller than whatever distance you are using to determine if the ship is close enough to the target to consider it arrived. Otherwise the ship moves farther than the level of detection and gets stuck endlessly trying to get there.

I set the measurement value to be the same as the ShipThrust value - as such, there can still be a small "hiccup" where it actually passes the target, turns around, and then arrives. That can be completely cured by just increasing the distance detection value to the ShipThrust Value + half the shipthrust value.

EDIT : Added in that the ShipThrust value is a percentile of the ShipMaxThrust Value. The Faster the ship can go the faster it accelerates and decelerates.

Graphics 800,600,16,2
SetBuffer BackBuffer()
FPS=CreateTimer(60)
SeedRnd MilliSecs()
Global ShipX#,ShipY#, TargetX#,TargetY#,ShipSpeed#,ShipThrust#
Global ShipHeading#,ShipTurnSpeed#,ShipMaxSpeed#
Global done

done = False

	ShipX=Rnd(10,GraphicsWidth()-10)
	ShipY=Rnd(10,GraphicsHeight()-100)
	TargetX=Rnd(10,GraphicsWidth()-10);Rnd(750,790)
	TargetY=Rnd(10,GraphicsHeight()-100);Rnd(20,500)
	ShipSpeed= 0
	ShipMaxSpeed = 5
	;WARNING : If the value of ShipThrust is higher than the value to determine
	;if the ship is close enough to the target then ship may never "reach" target.
	;As such, Just set the detection distance to the value of ShipThrust.
	ShipThrust= ShipMaxSpeed / 100
	ShipHeading = Rnd(0,360)
	ShipTurnSpeed = 5
	
	t$="Braking Distance = " + BrakingDistance(ShipSpeed,ShipThrust)
 
	Repeat
		If KeyHit(1) Then done = True
		Cls
		Text 100,500,t
		Text 100,520,"Speed :"+ShipSpeed
		Text 100,560,"Thrust : "+ShipThrust
		
		Text 400,500,"Left/Right Arrows Increase/Decrease MaxSpeed"
		If KeyHit(205) Then ShipMaxSpeed = ShipMaxSpeed + 1
		If KeyHit(203) Then ShipMaxSpeed = ShipMaxSpeed - 1
		Text 400,520,"Max Speed : "+ShipMaxSpeed
		
		If ShipMaxSpeed < 1 Then ShipMaxSpeed = 1
		;Draw Target
		Rect TargetX-3,TargetY-3,6,6
		;Draw Ship
		Oval ShipX-2,ShipY-2,5,5
		Line ShipX,ShipY,Cos(ShipHeading) * 10 + ShipX,(Sin(ShipHeading) * 10) * -1 + ShipY
		;If ship not pointed at Target
		TargetAngle = DistAng(ShipX,ShipY,TargetX,TargetY,"ang")
		ShipHeading = TurnToTarget(ShipX,ShipY,TargetX,TargetY,ShipHeading,ShipTurnSpeed)
		Text 100,540,"Left to Turn :"+Abs(ShipHeading - targetangle)
		If Abs(ShipHeading - TargetAngle) < 1 Then
		;If ship pointed at target
			ShipX = Cos(ShipHeading) * ShipSpeed + ShipX
			ShipY = (Sin(ShipHeading) * ShipSpeed) * -1 + ShipY
			ShipSpeed = Automatik (ShipX,ShipY,TargetX,TargetY, ShipSpeed, ShipThrust)
		EndIf
		;Once Ship arrives set new Target coordinates
		If DistAng(ShipX,ShipY,TargetX,TargetY) < ShipThrust + ShipThrust/2 Then
			TargetX=Rnd(10,GraphicsWidth()-10)
			TargetY=Rnd(10,GraphicsHeight()-100)
			DebugLog "Resetting Target and ShipSpeed"
			ShipSpeed = 0
			ShipThrust= ShipMaxSpeed / 100
		EndIf
		Flip 0
		WaitTimer FPS	
	Until done = True
End

Function Automatik# (X#,Y#,TargX#,TargY#,Speed#,Thrust#)
    ;StopDistance - Distance Required to end at full stop
	;Distance - Distance between Ship and Target
	Local StopDistance#,Distance#
    StopDistance = BrakingDistance(Speed,Thrust)
	Distance = DistAng(X,Y,TargX,TargY)
    If StopDistance > Distance*1.01 Then
		DebugLog "much to close"
		Speed=Speed - 2*Thrust
    ElseIf StopDistance > Distance Then
		DebugLog "to close"
        Speed = Speed - Thrust
	Else
		dl$ = "Thrust"
		Speed = Speed + Thrust
		If Speed > ShipMaxSpeed Then 
			Speed = ShipMaxSpeed
			dl$ = "Coasting at MaxSpeed"
		EndIf
		DebugLog dl$
	EndIf
	If Speed < 0.01 And StopDistance >= Distance Then
		If Speed <> -0.01 Then 
			DebugLog "Stopped when speed was "+Speed
			Speed = 0
		EndIf
	EndIf
	Return Speed
End Function 


Function BrakingDistance#(TestSpeed#,Thrust#)
     Local Way#=0
     Repeat
         TestSpeed=TestSpeed - Thrust
         Way=Way+TestSpeed
     Until TestSpeed<0
     Return Way
End Function


Function DistAng#(x1#,y1#,x2#,y2#,job$="")
	dx# = Abs(x1 - x2)
	dy# = Abs(y1 - y2)
	Dist# = Sqr ((dx * dx)+(dy * dy))
	If job = "ang" Then
		ang# = ACos(dx/dist)
		If (x2 < x1) And (y2 <= y1) Then		;91-180 degrees
			ang = 180 - ang
		ElseIf (x2 < x1) And (y2 > y1) Then		;181-269 degrees
			ang = 180 + ang
		ElseIf (x2 >= x1 And (y2 > y1)) Then	;270-360 degrees
			ang = 360 - ang
		EndIf
		Return ang#
	Else
		Return Dist#
	EndIf
End Function


Function TurnToTarget#(ShipX#,ShipY#,TargetX#,TargetY#,Heading#,TurnSpeed#)
	Local Ang#,Turn#
	Ang# =  DistAng(ShipX,ShipY,TargetX,TargetY,"ang")
;If the turnspeed turns us farther than the remaining angle then just point at target
	If Abs(Heading - Ang) < TurnSpeed Then
		Return Ang
	EndIf
;Determine how far to turn
	If Heading > Ang Then
		Turn# = Abs(Heading - Ang)
	Else
		Turn# = Abs(Ang - Heading)
	EndIf
	If Turn <> 0 Then 
		If Turn <= 180 Then
			If Heading <= Ang Then Heading = Heading + TurnSpeed
			If Heading >  Ang Then Heading = Heading - TurnSpeed
		Else
			If Heading <= Ang Then Heading = Heading - TurnSpeed
			If Heading >  Ang Then Heading = Heading + TurnSpeed
		EndIf
	EndIf
	While Heading > 360
		Heading = Heading - 360
	Wend
	While Heading < 0 
		Heading = Heading + 360
	Wend
	Return Heading#	
End Function



-Rick-(Posted 2014) [#9]
I think the BreakdingDistance function is turning out to be a bit of a resource hog. I'm still trying to successfully implement this movement method into my program but am having some difficulties. I think that's more of an issue of how I've implemented showing various zoom views than the above code itself, but even with working with only 1 ship I notice a significant drop in FPS once the ship begins its move order.

My computer is a bit older and slower, but my fps rating drops from the set 60 fps range down to the 40 to 50 range (the further the distance the worse it seems to be). I'm thinking it will get much worse once I implement it for all of the various ships that will be in the game.

Going to have to focus on finding a single formula to determine breaking distance rather then counting down every update call.


Midimaster(Posted 2014) [#10]
As a fisrt step I would test, how much time the Function BrakingDistance() needs!

Function BrakingDistance#(TestSpeed#,Thrust#)
     Local Time%=Millisecs() 
     Local Way#=0
     Repeat
         TestSpeed=TestSpeed - Thrust
         Way=Way+TestSpeed
     Until TestSpeed<0
     Print "Time=" + (Millisecs() -Time)
     Return Way
End Function


Please report the results here!

If it is below 2, it is not responsible for your problems.

If it is more than 5 you have to do something. Some solutions:

- You could replace it by a complex function instead of a iteration.

- You could stop calling the function as long as the target is far away. As you use a "maximum speed", you know its maximum braking distance and as long as this is smaller than the distance to the target, there is no need of testing anything.

- You could use a "table of speeds<->distances" for estimate, whether a testing is necessary anyway.


- You could use a 10 times faster approximation if speed is high

Function EstimateBrakingDistance#(TestSpeed#,Thrust#)
     ShipMaxBrakeDistance=123456
     If TestSpeed>=ShipMaxSpeed Then Return ShipMaxBrakeDistance
     Local Way#=0
     Repeat
         If TestSpeed>MaxSpeed*0.2
              TestSpeed=TestSpeed - 10*Thrust
              Way=Way+10*TestSpeed
         Else
             TestSpeed=TestSpeed - Thrust
              Way=Way+TestSpeed
         Endif
     Until TestSpeed<0
     Return Way
End Function



-Rick-(Posted 2014) [#11]
Good point and thanks for the response. Should have checked that beforehand.

Put in a millisec() counter and the outcome on every single pass was 0. Here's the exact code I used (this is from my main program, not the demo used above)
test3 = MilliSecs()
	StopDistance = 0
	BrakeSpeed = Speed
	Thrust = ShipMaxSpeed / 1000
	Repeat
		BrakeSpeed = BrakeSpeed - Thrust
		StopDistance = StopDistance + BrakeSpeed
	Until BrakeSpeed < 0
DebugLog MilliSecs() - test3

I find it odd that the millisecs doesn't increment between assigning Test3 the millisec() value and then doing the subtraction later, but I've run into that before, like when using millisec() to generate unique ID's for various type objects I've created. If I don't put in a delay(10) immediately after a read then the next created type in the loop will have the same exact millisecs() value for the UID.

For example, when I generate my initial Planets without a Delay (10) all the planets come out with the same UID. I use the Unique ID to parse through the planet types at various times to find specific planets. Here's that chunk of code :

	While Not complete
		count = Rand(1,10)
		If Rnd(100) < 45 And st\World[count]\ID = 0 Then
		;Identify Planet with Orbit and Parent Star
			st\World[count]\ID = st\ID
		;Generate Unique ID for Planet
			st\World[count]\UID = MilliSecs()
			Delay(10)
			st\World[count]\Orbit = count
		;Position Planet on orbit line in distances of 100
			ang = Rand(-180,180)
			st\World[count]\X = (Cos(ang) * (count * 10) * .0001)
			st\World[count]\Y = (Sin(ang) * (count * 10) * .0001)
			tempx# = st\World[count]\X
			tempy# = st\World[count]\Y 
		;Determine Size and Class
			st\World[count]\Size = Rand(1,10)
			st\World[count]\Class= Rand(1,10)
		;Name Planet
			name$ = st\Name
			Select count
				Case 1 n$ = "I"
				Case 2 n$ = "II"
				Case 3 n$ = "III"
				Case 4 n$ = "IV"
				Case 5 n$ = "V"
				Case 6 n$ = "VI"
				Case 7 n$ = "VII"
				Case 8 n$ = "VIII"
				Case 9 n$ = "IX"
				Case 10 n$ = "X"
			End Select
			st\World[count]\Name = st\Name + " " + n$
		;Assign Resourse Value to Planets and system
			st\World[count]\resources = Rand (1,3)
			rich = False
		;Rare Chance it is a richer planet
			While Not rich
				If Rand(100) < 10 Then 
					st\World[count]\resources = st\World[count]\resources + Rand(3,10)
				Else
					rich = True
				EndIf
			Wend
			st\Resources = st\Resources + st\World[count]\resources
		;Check to see if enough planets were made
			planetcount = planetcount + 1
			If planetcount = numplanets Then
				st\NumPlanets = numplanets
				complete = True
			EndIf
		EndIf
	Wend


So, again, it surprised me that the millisec() value remained the same for each planet in the loop.

I'm thinking I had a false read on the FPS drop because its not doing it now. Most likely I had something else taking resources in memory and it slowed down the program during the compile and run. If I leave firefox open too long in the background I get that sometimes when running a program.

So in short, it doesn't look like that BreakDistance check is my problem. It most likely has to do with how I'm presenting magnification. I have a "Galaxy" level view where you see all the stars on a map, then a "Zoom View" for when you click on a star and see the planets/ships in that system. I'm getting movement where my ships are jumping pretty large distances (5 pixels or so) between updates. I think thats because in Zoom view I've ended up making each pixel space the relative size of 20 or 20 pixels from the magnification level so will have to figure out a better way of doing that.


Midimaster(Posted 2014) [#12]
That's what i expected: The algo is too fast to think about optimisation.


But we did still not think about the sum of calculations. How many different ship-planet distances do you calculate at the same moment in a typical game situation?

But what is the reason for the lags?... Next performance test now would be to test the time between REPEAT and FLIP. Please send results.... If time is always <15 there is no need for optimisation.


You cannot use Millisecs() to generate unique IDs, because the app is too fast. Normally you can do thousands of things during one millisec step. So better use ID=Rand(100000). Or use a simple incremending counter for first ID=1, second ID=2, ...


-Rick-(Posted 2014) [#13]
Between the number of players set for the game (2 to 8) and the number of stars in the game (50 to 150) the ship count will run between 210 to 310 ships total, plus or minus depending on how many a player can afford to build. Ships get more expensive for each consecutive ship built. There are ships that a player directly controls and gives orders to (the ones they actually build) and ships that are generated automatically and run in the background beyond the players control (ships that gather resources, move colonists around)

In my own testing I set all the stars as owned by Player 1 in a 150 star game. It automatically generated 149 resource ships (a ship to gather resources at each 'owned' but un-colonized system' and then return them to the closest base) and while I suffered a drastic FPS loss during the creation of all the ships (which was expected), once they were made they all began running their routes with no real noticeable FPS loss.

I should point out that when I preformed this 'proof of concept' test it was early on with the ships just going to the resources system, visiting each planet, returning to their home base and then repeating the cycle. There was no acceleration/deceleration code in place at that time. And since then I've rewritten my coordinate system because I was experiencing some rather bad rounding errors when the ships began moving around at a solar system scale vs the galaxy wide scale.

This is why I revisited the acceleration/deceleration part of this. I haven't completed retrofitting the code that handles ships being able to run their patterns yet because I'm still stuck on getting the acceleration/deceleration working and am still experiencing some accuracy problems on the smaller scale of planets. I'm currently just focused on getting a ship to run from its base to its parent star smoothly. I haven't even begun to add in the portion where a ship runs from star to star again. I'm assuming (hoping like crazy!) that once I solve the small movement problems the big ones will work out when I plug in the larger coordinates.

I misspoke my concerns of the FPS lag problem. It was more of a projected concern based on what appears now to be my own fault in leaving too many programs open while I was coding that effected the FPS rate.

Also thank you for the heads-up on millisecs(). I was not aware of that and will most definitely keep that in mind in the future.


Midimaster(Posted 2014) [#14]
So if you plan to control the distances of 300 ships, you should simulate this with a simple loop in our test code. (Of course remove the loop after testing it):

Global TEST_MAX%=10 ; test also 30, 100, 300 

Function BrakingDistance#(TestSpeed#,Thrust#)
     Local Time%=Millisecs()
     Local TestTestSpeed#=TestSpeed
     For Local i%= 0 To TESTMAX 
          Local Way#=0
          TestSpeed#=TestTestSpeed
          Repeat
              TestSpeed=TestSpeed - Thrust
              Way=Way+TestSpeed
          Until TestSpeed<0
     Next
     Print "Time=" + (Millisecs() -Time)
     Return Way
End Function


Test this first with a value of 10, then 30, then 100 then 300 and report the results....


-Rick-(Posted 2014) [#15]
At 400 ships my FPS drops from 60 to 30, the Timer fluctuates between an 8 and a 9.

At 300 ship FPS drops from 60 to 55, Timer fluctuates between 5 and 6

At 200 FPS stayed mostly around 57/58 with it occasionally going up to 59 or dropping to 56 for a flicker. Timer fluctuated between 3 and 4

At 100 ship FPS stayed pretty solid on either 58 or 59 with the timer showing a solid 2 with the occasional blip into 1

At 30 Ships FPS stayed a solid 59 with the Timer fluctuating between 1 and 0

At 10 Ships FPS was a solid 59 with the Timer reading mostly 0 with occasional 1's popping up.

Just for a stress test I put in 2000 ships. FPS dropped to 18-20 and the Timer fluctuated between 37 and 40.

Here is the loop I used

test1 = MilliSecs()
	For count = 1 To 2000
		StopDistance = 0
		BrakeSpeed = Speed
		Repeat
			If BrakeSpeed > 1 Then
				BrakeSpeed = BrakeSpeed - ShipMaxSpeed / 100
			Else
				BrakeSpeed = BrakeSpeed - ShipMaxSpeed / 10000
			EndIf
			StopDistance = StopDistance + BrakeSpeed
		Until BrakeSpeed < 0
	Next
	test1 = MilliSecs() - test1


You'll note that I use too instances of ShipMaxSpeed. I found that using a single value didn't work between the star scale and planet scale. If I set things up to move correctly while flying from star to star then they moved far too fast on the planetary scale, and if set things so that ships moved correctly on that scale they would move way slower on the bigger scale. Often a ship wouldn't even reach its max speed even on long journies.

Just for a little explanation - Star coordinates are generated on a 650 by 700 grid, then multiplied by 1000. Planet coordinates take up the 0 to 1000 range of a stars x/y coordinate. So there is a magnification difference of about 1000 between the 2. So basically a ship moving on the x axis between 0 and 1000 wouldn't even move 1 pixel on the star scale.

So I have to alter at what value Thrust has depending on whether the ship is trying to just move within a star system or if its moving from star to star. That made figuring out the breakingdistance a little more trickier so I'm still tweaking that. It currently still wants to overshoot the target and then come back. But I think I'm pretty close to figuring that out.


Midimaster(Posted 2014) [#16]
As 300 is realistic number of ships the 5-6msec should be the realistic time consumption of the deceleration function.

This is to much! But you can do something very:

So now I would add a first check, whether the ship is closed to its target or not. Depending on your max speed, there is a "max braking distance". Try to find out this value by a test with max speed in BrakingDistance() and use the returned value as "ShipMaxBrakeDistance". When distance is higher than this, there is no need of checking anything:
Global Const ShipMaxBrakeDistance#=300

Function Automatik# (X#,Y#,TargX#,TargY#,Speed#,Thrust#)
      Local StopDistance#,Distance#
      Distance = DistAng(X,Y,TargX,TargY)
      If Distance >ShipMaxBrakeDistance Then Return ShipMaxSpeed

      StopDistance = BrakingDistance(Speed,Thrust)
      If StopDistance > Distance*1.01 Then
            .....


This prevents that the ships that are far away from there target will be checked. If we exepect that 20% of the ship are closed to the target and 80% are far away, this reduces the time consumption from 5msec to 1msec

More? Better? What do you think about a function EstimateBrakingDistance() ?

This function reduces the iterations, when the speed of the ship is very high, but makes a "fine tuning" if the speed is low:

Function EstimateBrakingDistance#(TestSpeed#,Thrust#)
     ShipMaxBrakeDistance=123456
     If TestSpeed>=ShipMaxSpeed Then Return ShipMaxBrakeDistance
     Local Way#=0
     Repeat
         If TestSpeed>ShipMaxSpeed*0.2
              TestSpeed=TestSpeed - 10*Thrust
              Way=Way+10*TestSpeed
         Else
             TestSpeed=TestSpeed - Thrust
              Way=Way+TestSpeed
         Endif
     Until TestSpeed<0
     Return Way
End Function



fox95871(Posted 2014) [#17]
Do you mean like the way everything always slows to a stop smoothly in Metal gear games? If so tell me, I have just the thing.


-Rick-(Posted 2014) [#18]
fox, I am not familiar with Metal gear games, so not sure if its the same thing or not.

Midi, this is becoming a bit problematic. I'm not yet accurately finding a BreakingDistance value where the ship slows to a stop. This is because of the 2 different levels of Thrust I'm using dependent on how far the ship is from the target.

I recognize where my problem here is and just have to work out how best to know when to slow the ship at the faster value or slower value. Until then I can't really implement what you've suggested.

However I do think that your suggestion is completely correct. The ship should never have to slow down before it reaches the halfway point, so I can skip making a breakdistance check up to that point. Once it reaches halfway then either it has achieved MaxSpeed or its at the fastest speed it can get so I can do a single check on what the Stopdistance is going to be. If the ship isn't going max speed it will then just start decelerating, else if its coasting at maxspeed the Stopdistance value will tell me when it starts decelerating.

I just wanted to make sure you know I recognize and understand what you are saying and that I'm not ignoring your suggestion. As soon as I get things smoothed out for the StopDistance I'll implement this and report the results to you.

Thanks!


fox95871(Posted 2014) [#19]
I mean for slowing things down like this:
.
.
 .
   .
       .
              .        .

The module I made can be used for gradual slowdowns or speedups, and can be stretched across any segment of your ships route.


-Rick-(Posted 2014) [#20]
That sounds like it could be quite helpful for me. One of the problems I'm facing is that I'm using a set acceleration value for increasing/decreasing speed. This works fine if I were using standard distances, but moving between stars and moving between planets requires to very different acceleration ratios. In a nut shell my x/y values for stars are in the 999,000 range while the x/y for planets is in the 999 range.

Basically, on the star scale, each planetary system is only 1 pixel across. So if my star x value is at 100,000 and my ship moves to 100,001 then its already left the system. So when I calculate my interplanetary movements I have demagnify the scale (if that makes sense). 1 pixel movement on the planetary scale would then become something like 1/1000 on the star scale.

If I used a set thrust value then accelerating out of the star system to go to another star takes a very long time before the ship achieves enough thrust to be noticeable on the star scale - and the converse of entering the planetary system after arriving from another star has my ship with speeds that are so high that it looks like its just teleporting around on that scale.

This has caused me to use 2 different values for thrust, but that makes figuring out when and how much to slow down problematic (at least for me). More often than not my ships overshoot their destination, turn around, overshoot again (but be a little closer) and just running back and forth until its close enough to be considered there.

So yes, a sloped curve like you show above, I think, would help out well because while the initial acceleration may be slow on the star scale, it would quickly increase in power for faster acceleration.

I'd be very interested to see what you have to see if it would solve some of the problems I'm having.


fox95871(Posted 2014) [#21]


You'll need this image file:
http://kiwi6.com/file/4c1sjmgwi3


-Rick-(Posted 2014) [#22]
Thanks Fox. I'm seeing very good potential here, but my mind just isn't grasping the mechanics of how I would implement it.

If I understand it correctly, I wouldn't even have to use thrust/acceleration to move an object (ship), I would just have to track the time of the travel and use a sine wave to see how far along the path it had gone. Visually it would appear to be accelerating and decelerating as its x/y would be plotted dependent on how far along the wave it was.

I'll need to mull this over a bit more to better absorb how I might use it.


Kryzon(Posted 2014) [#23]
Hello.
I don't understand why you're not using a kinematic equation as a solver for your system.


-Rick-(Posted 2014) [#24]
To be bluntly honest, its a combination of things at this point ranging from weak math skills to simple inexperience in knowing which path to follow to a bad case of wanting to just get something working so I could continue developing other parts of my program. Midi's initial code looked to do exactly what I needed and my being able to modify it to run and look exactly what I wanted to do left me focused on trying to conform it into my own code.

However, I have been looking back at what you explained to me earlier and am trying to see if I have a handle on it enough to plug that in. My first attempts when I began this involved trying to implement the kinematic equation, but my source knowledge was from a Texas Instrument Calculator manual (and I didn't even know it was called the kinematic equation then) but what I managed failed miserably.


-Rick-(Posted 2014) [#25]
Kryzon, one problem I'm seeing right away is the same issue I'm having with Midi's code - I need to manage 2 different thrust values for acceleration/deceleration dependent on whether I'm traveling in system or between stars. These 2 different values mix as a ship enters a system and uses a lower thrust value or exits a star system and starts thrusting at a higher value.

Whichever thrust value I use for one does not work with the other. The kinematic formula seems dependent on the same value of thrust being used at all times. I'm not sure how I would adapt to this, or even if I can?

This is why fox's example seemed promising to me. I like the idea of an initial low thrust value that quickly increases as the ship moves. This would allow the relatively short distance in planet to planet movement to use the lower thrust value, but if they continued moving toward another star it would increase with a higher rate of thrust to cover the much larger distances. But I have to admit, that I didn't even know where to start to convert what he posted into something I could use.

Unless that is what the "magnitude" equation you presented was for? I didn't quite understand how that came into play or how it would be used.

I'm sorry to be struggling with this so much.


-Rick-(Posted 2014) [#26]
Just as an update, I did successfully plug in the Kinematic formula. I used the same thrust value for the entire trip from 1 star to another. But the problem I ran into was what I explained - that set thrust value made macro movement vs micro movement problematic.

So obviously the tricky question is can the Kinematic formula still work if using a thrust value that changes? Ideally, if the thrust could start out quite low and then geometrically increase to its max amount. I'm reading over the link you posted, but I'm not sure if something like that is there as it all seems to depend on constant acceleration.

Here is the function I made for acceleration/deceleration, btw

Function Update_Accel#(ShipX#,ShipY#,DestX#,DestY#,ShipMaxSpeed#,Speed#)
	Local Distance#, StopDistance#, Thrust#
	
	Distance = DistAng(ShipX,ShipY,DestX,DestY,"")
	Thrust = ShipMaxSpeed / 10000
	
	StopDistance = Abs((Speed * Speed) / (-2 * Thrust))
	
	If Distance > StopDistance Then Speed = Speed + Thrust
	If Distance <= StopDistance Then Speed = Speed - Thrust
	
	Return Speed
End Function


The DistAng call is just a function call that returns the distance between two points, or their angle if 'ang' is put between the quotation marks.

I also made Stop distance an Abs value because it was coming up negative from that -2. Suppose I could have just taken the - off?


-Rick-(Posted 2014) [#27]
So I went on the search for Kinematic non constant acceleration ... I think I'm suffering some internal brain bleeding now. This subject is quickly destroying what little confidence in mathematics I thought I had ...


Rob the Great(Posted 2014) [#28]
I wrote this a while back, it might be useful. It essentially takes an entity and smoothly moves it from point A to point B. I understand that your system is a little more complex, but my thoughts are that you could possibly use two different points for movement: one for the interplanetary system, and one for the star system. The only problem I see is that the entity would appear to stop right as it reaches the boundary of the two systems before accelerating again.

http://blitzbasic.com/codearcs/codearcs.php?code=3058

I just want yo let you know that there's a logical bug in the demo in which if you slow the speed of one object, it will keep snapping back to the starting position until the other object finishes. But this is just a bug in the demo, not in the actual function.

I have to go to my math class (Calculus III) now, but I will be back later. I'm curious if I could provide a modified version which would be a better match for your needs.


Kryzon(Posted 2014) [#29]
I didn't realize that you were having trouble with implementing the kinematic solution.

I have written some example code.




-Rick-(Posted 2014) [#30]
Thanks for pointing that out to me Rob. I hadn't thoroughly gone through the 3d Graphics portion of the archives because I'm not currently using 3d spacial movement. However, one thought I am entertaining is that once I have the core code figured out that I would convert some of my GUI to render in 3d for effects and what not.

Kryzon, that is an amazing example! I'm going to spend some time now in running this and walking through it so that I can get a handle on what its doing. I sometimes have trouble understanding concepts as they are explained, and having a visual representation of what's going on goes quite far in allowing me to absorb and learn. Thank you!

Thanks to everyone in helping me out with this. I sincerely appreciate the time and effort in the responses!


Kryzon(Posted 2014) [#31]
I'm glad. If you have trouble understanding the code, please share.


-Rick-(Posted 2014) [#32]
I'm not having any trouble understanding the code. the commenting and notes have explained each part of it so that I'm easily able to see what its doing and how its doing it.

I'm at the point now where I'm digging around in it and tinkering. I admit the format that it follows still throws me off when I'm trying to recall where it goes next or in what order things happen. But each time I follow it through that sticks more readily in my memory.

I'm trying to change it so that movement always starts and ends in the Standard thrust mode and am trying to use the Distance_Threshold as the marker for that. The reason for this is because if the distance is great enough that MaxSpeed is achieved then it starts out and ends in "Turbo Mode". This is simply an aesthetic quibble on my part. So I'm seeing if I can have those trips where it reaches MaxSpeed and cruises start and end in Standard Mode the same as those distances in which MaxSpeed is not reached.

So as it looks now, using 'S' for Ship, 'T' for Target 'D' for the point in which slow down starts,'-' for Normal Thrust, '=' for Cruise and '+' for Turbo Thrust it looks like :

Max Speed Not Achieved -

S----------D----------T

Max Speed Achieved -

S++++++++++==========D++++++++++T

What I'm shooting for would look like this, where '>' a minimum distance that the Ship would Travel in Normal Thrust before switching to Turbo Thrust and '<' is the minimum remaining distance in which it would change from Turbo Thrust back to Normal Thrust

S----->+++++++=========D+++++++<-----T

The plan is to use the kinematic formula to determine what the ships speed will be in Standard Thrust when it reaches '>'. Then it will determine the deceleration point between > and <, keeping in mind that I don't want to find that point by decelerating all the way down to 0 when it reaches < and that it will be starting out with the speed it reached when it got to >. Then I will switch it to Standard Thrust again and decelerate to 0 between < and T.

I believe it should be fairly simple and the only trouble I'm having at the moment is adapting the code example you provided. It's more about my own remembering of where things occur and what order they occur in. Most likely I'll start it from scratch so that the format is more familiar to me.

I'm very excited about this and thank you again for all your help!


-Rick-(Posted 2014) [#33]
I think I got it. I had to fudge a bit at the end because the calculations didn't seem to be coming out precise. Once I calculated how far the ship moved to reach maximum speed I just took that and moved back from the target's position to get where I wanted to start slowing down. More often than not the precision was off so that one cycle of movement between Fast deceleration and slow deceleration was enough that either the ship stopped far short or overshot by a significant amount.

Basically, when the ship reached the point in which it was suppose to change from Turbo Speed to Normal Speed I force adjusted the speed to match what the speed was when it changed from Normal to Turbo.

I'm sorry, Kryzon, that I butchered your code up a little bit. But some of the math and techniques you used escaped me and I had to work around my own ignorance.

Here's what I worked out




-Rick-(Posted 2014) [#34]
I've edited my above code to include plotting the speed of the ship over the course. Was just curious how it would appear visually.


Kryzon(Posted 2014) [#35]
I'm glad that you're making progress.
One thing that I've been meaning to ask you is this. The starship knows the location of its destination and knows the distance that it will have to travel, so why does it need to travel with impulse thrust for a while, and only later engage the warp speed?

Considering a context such as Star Trek, for example, if they're travelling from a planet to its moon then they use their impulse (or "sub-light") engine. But if they have to travel to another planet or system, they engage the warp exclusively - they don't use the impulse thrust.
I presume that the warp is too costly to use with shorter distances, and that the impulse doesn't contribute that much with longer distances.

The reason I'm saying this is because deciding which thrust to use based on the total distance to travel and just using that thrust for the whole voyage requires a simpler logic.
Also, speaking as a player, seeing the ship travelling with a slower thrust when I know that it will later engage the warp speed because I selected a far away destination will feel a bit frustrating, not to mention spend more time than if it were using the warp thrust from the beginning.
Regards.


-Rick-(Posted 2014) [#36]
Sorry this got long. I'm terrible at brief, concise statements.

It's because of the game scales. To explain the scale, the area I generate the coordinates of my stars in is roughly 750,000 x 640,000. I divide that number by 1000 to display them on my map of 750 x 640.

Each star system has between 1 to 10 planets. Nothing fancy here, just 10 orbital distances around each star. Each planet's coordinate resides within a 1,000 x 1,000 area around each star. In effect each star system is 1 pixel across regardless if it has 1 planet or 10 planets.

The problem that arises by using a single thrust value is that what works for one level of scope is either too fast or too slow for the other. If I want my ships to move at a reasonably looking speed on the planet scale then I have to increment the speed by tiny amounts, but that means achieving that full warp speed to go to another star is going to take a long time when incrementing ship speed by such a small value. Most of the trip would be spent in constant acceleration/deceleration. Different warp values actually become inconsequential. At those thrust increment speeds the ship won't even hit max speed between most star movements so having warp 2 or warp 10 makes no difference.

If I use the larger Thrust value then the opposite happens - the ships zip around on the planetary scale and can't even accurately find their target destinations because their thrust range greatly exceeds any level of accuracy of determining when they've arrived. A ship moving just 1 warp thrust value on the planetary scale is enough to jump it between several planet orbits.

I felt that using 2 different thrust values dependent on how close the ship was to its stop and start area would give me both the accuracy I need for short distances and the speed I needed for long distances. In doing this I had to come up with an arbitrary point where one or the other kicks in.

I also need to keep in mind that there is almost yet a 3rd level of scale. What appears as acceptable movement between planets is still a bit too fast for very tiny control, such as to dock at a starbase, or eventually move in combat. That is the reason I prefer a gradual increase of speed on the small scale vs just having an arbitrary speed amount. Again, what works for one doesn't work well for the other.

However, in thinking this through to respond, the idea of getting rid of the Warp thrust value entirely and just automatically going to full warp between those initial speed up and final slowdown values is probably going to be more sensible. I was just initially turned off by the idea of a ship suddenly jumping to full speed. But since a ship moving on that scale is just moving and not maneuvering then I think you are right having the speed up and slow down to and from full speed just adds needless complication.

I'd work out some visual image at the point of entering and leaving warp, like a halo, or a blurred smear behind the ship or something like that.

I think a bulk of the problem I'm having is with float accuracy. I'm just now coming to realize the 6 significant figure level. I had assumed it meant 6 figures on each side of the decimal point when it seems to be 6 or 7 digits in total regardless of the decimal. I found RGR's float doubling code last night and am looking to see if using that might be a solution or if I'm going to have to rethink the scales (again). As it stands, a ship with an x coordinate of something like 305743.0 will not always increment if I increase it by any less than about .1 and .1 is far too large on the planetary scale. At that scale, ships docking at a colony base look like they either are teleporting or move in very blocky manners. Or they won't dock at all because the amount of movement is too small to register so they just sit.


-Rick-(Posted 2014) [#37]
The significant digit thing is really stumping me. Tried using RGR's double functions, but that didn't pan out. Looks like I'm going to have to rethink my entire coordinate system. I really liked the simplicity of everything residing in the same coordinates but it costs me the accuracy of fine level movement. Guess I'm going to have to store and track macro and micro locations separately and not together.

Rather than have a star's x location as 725,000 and a planet's x location in that star at 725,144 I'll just break them down to 725 for the star and 144 for the planet.

The trick will be ships recognizing if they are moving on the star's scale or the planet's scale. Gah .. gonna have to rewrite all the resolution and magnification code. What a pain.


fox95871(Posted 2014) [#38]
You sure you don't want to just use a simple sine wave? If you used gradual increase, sudden increase, gradual decrease, sudden decrease from the code I posted, you could easily simulate believable interstellar travel speed transitions.
                  .     . warp ten
              .
            .
          .               the speed of light
.     .                   five miles an hour



-Rick-(Posted 2014) [#39]
I had orginally wanted exactly that fox, but figuring out the formula to determine when and how much acceleration and deceleration was beyond my abilities. I appreciated your examples but I wasn't quite understanding how it worked or how I could adapt it.

Since that point I have to agree with Kryzon that a simpler system would probably serve best. I'll still require 2 basic thrust speeds depending on which scale I'm moving, but simplifying it by having Warp move only as a maximum speed and using impulse as a set speed (with a minor accel/decel transition from or to stop) for moving on the smaller scale.


Blitzplotter(Posted 2014) [#40]
This is a very interesting thread with some great examples of deccelerating entities in 3D space, really appreciated.


-Rick-(Posted 2014) [#41]
I think I got the movement figured out now. Discovered a flaw in the way I was moving ships - would only have them thrust if they were pointed at the destination coord, which translated them stopping dead in space no matter what their speed if they passed the destination point, turn around, then fly back at the target at the speed they passed it by. Created a see-saw movement that was quite annoying.

Also added in a check on the final leg of the journey when they drop to impulse engines. Because of rounding errors the initial calculated distance was usually off by the time the ship got there and it would over shoot (causing the see-saw movement). I just recalculate how far they would move from the target point (starting at 0 speed) to reach their current speed at the checkpoint. If they were overshooting then it just does another thrust subtraction to help trim the speed. Haven't seen an overshoot in a few days now.

The math isn't pretty, but visually everything works out.

Just wanted to say thank you again to everyone that helped me out with this through suggestions, code examples, and explanations. I learned things I didn't know before and can now apply that in other similar situations which I wouldn't easily be able to do if I just copy/pasted code I didn't understand.