Faster movement

BlitzMax Forums/BlitzMax Beginners Area/Faster movement

JiPrime(Posted 2011) [#1]
I've been using Bresenham's line algorithm for player movement, and I am trying to make the player move faster when the basespeed is increased.

I tried multiplying the steps by the basespeed, but that ended up with the player passing through the target location entirely.

Is there any way to increase the speed of the player's movement using Bresenham's line algorithm?

Graphics 640,480,0
x = 250
y = 250
xspeed = 0
yspeed = 0
targetx = x
targety = y
sx = 0
sy = 0
velocity = 0
angle:Float = 0
basespeed:Int = 1

Repeat
	Cls
	distance:Float = Sqr((x-targetx)*(x-targetx) + (y-targety)*(y-targety))
	If MouseHit(2) 'Right Click
		targetx = MouseX()
		targety = MouseY()
		dx = Abs(targetx-x)
		dy = Abs(targety-y)
		If x < targetx
			sx = 1
		Else
			sx = -1
		EndIf
		
		If y < targety
			sy = 1
		Else
			sy = -1
		EndIf
		err = dx-dy
		
		ax = targetx-x
		ay = targety-y
		
		angle = ATan2(ax,ay) * -1 + 90
		EndIf
	
	If KeyDown(KEY_SPACE)
		x = 250
		y = 250
	EndIf
	
	If KeyDown(KEY_UP)
		basespeed :+ 1
	EndIf
	
	If KeyDown(KEY_DOWN)
		basespeed :- 1
	EndIf
	
	If Not(x-targetx=0) Or Not(y-targety=0)
		e2 = 2*err
		If e2 >= (-1 * dy)
			err :- dy
			x :+ sx
		EndIf
		If e2 < dx
			err :+ dx
			y :+ sy
		EndIf
	EndIf
		
	DrawRect(x-4,y-4,8,8)
	
	DrawLine(x,y,targetx,targety)
	'Draw 30 degree cone splash borders
	DrawLine(x, y, x + 100 * Cos(angle-15), y + 100 * Sin(angle-15))
	DrawLine(x, y, x + 100 * Cos(angle+15), y + 100 * Sin(angle+15))
	'Draw middleline according to angle
	'DrawLine(x, y, x + 100 * Cos(angle), y + 100 * Sin(angle))
	DrawText("Angle: " + angle, 50, 50)
	DrawText("Current Coord: " + x + " , " + y, 50, 80)
	DrawText("Target Coord: " + targetx + " , " + targety, 50, 110)
	DrawText("dx: " + dx + " dy: " + dy, 50, 140)
	DrawText("distance: " + distance, 50, 170)
	DrawText("basespeed: " + basespeed, 50, 210)
	Flip
	Until KeyDown(KEY_ESCAPE) Or AppTerminate()
End



Midimaster(Posted 2011) [#2]
I do not not, whether I understand what you want, but if you want to increase the speed of the player, just do two things:


1. use "Flip 0" instead of "Flip"

2. use Timers to get induvidual turnarounds for the actors:


Because it is not the moving algorithm, that wastes time, but the drawing. So, if you reduce the amount of drawing per second, there is more time for the rest of the code.

Each "FLIP" waits upto ~15msec for the "VSYNC", until it is turning back to the application. You will have 60 FPS (turnarounds per second). "Flip 0" does not wait!

With "Flip 0 " the speed of the program rises dramatically (200fps), so you now have to intervent, that the computer (other apps and OS) keeps operable. The speed now depents on the "bottleneck" in your code. And this is the drawing.

There is no use to draw more often than 60 times a second. So add a painting-timer, which allows drawing only every 16msec. (16msec*60times=~960msec).

Now the FPS rises upto ~1000! From this moment you cannot longer handle the keyboard! So now add a Keyboard-timer, which allows to check the keyboard only 5 times a second. (=200msec). This is enough.

The player gets and individual update rate between 100msec and 1msec. This means 10 times (1000msec:100msec=10 times) upto 1000 times a second. So now he can walk 10 steps in one second upto 1000 steps.


Graphics 640,480,0
x = 250
y = 250
xspeed = 0
yspeed = 0
targetx = x
targety = y
sx = 0
sy = 0
velocity = 0
angle:Float = 0
basespeed:Int = 1

Repeat

	If KeyTime<MilliSecs() Then
			KeyTime = MilliSecs()+200
			If MouseHit(2) 'Right Click
				targetx = MouseX()
				targety = MouseY()
				dx = Abs(targetx-x)
				dy = Abs(targety-y)
				If x < targetx
					sx = 1
				Else
					sx = -1
				EndIf
				
				If y < targety
					sy = 1
				Else
					sy = -1
				EndIf
				err = dx-dy
				
				ax = targetx-x
				ay = targety-y
				
				angle = ATan2(ax,ay) * -1 + 90
			EndIf
			
			If KeyDown(KEY_SPACE)
				x = 250
				y = 250
			EndIf
			
			If KeyDown(KEY_UP)
				basespeed :+ 1
			EndIf
			
			If KeyDown(KEY_DOWN)
				basespeed :- 1
			EndIf
			PlayerSpeed=(100*0.9^baseSpeed)
	EndIf
	
			
	If PlayerTime<MilliSecs() Then
			PlayerTime=MilliSecs()+PlayerSpeed
			distance:Float = Sqr((x-targetx)*(x-targetx) + (y-targety)*(y-targety))
		
			If Not(x-targetx=0) Or Not(y-targety=0)
				e2 = 2*err
				If e2 >= (-1 * dy)
					err :- dy
					x :+ sx
				EndIf
				If e2 < dx
					err :+ dx
					y :+ sy
				EndIf
			EndIf
	EndIf	
	
	
	If PaintTime<MilliSecs()
			Cls
			PaintTime=MilliSecs()+16	
			DrawRect(x-4,y-4,8,8)
			
			DrawLine(x,y,targetx,targety)
			'Draw 30 degree cone splash borders
			DrawLine(x, y, x + 100 * Cos(angle-15), y + 100 * Sin(angle-15))
			DrawLine(x, y, x + 100 * Cos(angle+15), y + 100 * Sin(angle+15))
			'Draw middleline according to angle
			'DrawLine(x, y, x + 100 * Cos(angle), y + 100 * Sin(angle))
			DrawText("Angle: " + angle, 50, 50)
			DrawText("Current Coord: " + x + " , " + y, 50, 80)
			DrawText("Target Coord: " + targetx + " , " + targety, 50, 110)
			DrawText("dx: " + dx + " dy: " + dy, 50, 140)
			DrawText("distance: " + distance, 50, 170)
			DrawText("basespeed: " + basespeed, 50, 210)
			Flip 0
	EndIf
	Delay 1	' very important to keep the computer operable 
Until KeyDown(KEY_ESCAPE) Or AppTerminate()
End


Try "Basespeed" over 30 to understand what happens. The system is getting faster and faster without side-effects to key-check and drawing-interval. every step +1 at basespeed rises the players speed +10%.

If you want to rise it faster, use...

;for 25% increase:
		PlayerSpeed=(100*0.8^baseSpeed)
;for 100% increase:
		PlayerSpeed=(100*0.5^baseSpeed)


Last edited 2011


JiPrime(Posted 2011) [#3]
You understood me perfectly.

You forgot that millisecs() start with a value below 0, so the if conditions are never fulfilled, giving me black screen.

So I just multiplied it by -1 and tried running it.

It draws once, and does nothing now.

So, what now?

Thanks.

Last edited 2011


Midimaster(Posted 2011) [#4]
Millisecs() does not start with a value below 0! It counts the milliseconds since the computer started and is always positiv.

One known bug:
You only will have problems with the Millisecs() function, if your computer is a server running 24h/day and 7 days a week without new starts.

Restart the computer and try again my code (without multiplying by -1)


Jesse(Posted 2011) [#5]
no, millisecs is not always positive. it all depends on how long the computer has been left running and is the error you mention. when the computer is started it starts at 0 then when it reaches the point to where the last bit in the "Long" counter is reached that bit makes the number a negative. then it continues from -$9fffffff! to $8ffffffff! (or something like that) continually approximately every 7 days.

Last edited 2011


JiPrime(Posted 2011) [#6]
I restarted my computer and it works now.

But it doesn't get noticeably faster after a certain point.

While this is perfectly adequate for player speed, it's too slow for projectiles.

Is there any other way to make an accurate RTS-style movement?

Btw, kinda off topic, but is it bad for a computer to be left on for a long time?

Last edited 2011


Midimaster(Posted 2011) [#7]
if you "remove" the line

Delay 1


you will be able to accelerate the Main-Loop, but this can cause a hang of the OP. try it...


For a projectil I would do it like this:

	'If PlayerTime<MilliSecs() Then
			PlayerTime=MilliSecs()+PlayerSpeed
			distance:Float = Sqr((x-targetx)*(x-targetx) + (y-targety)*(y-targety))
		For Local I%=0 To 3 ' or try 10
			If (x-targetx=0) And (y-targety=0)
				Exit
			Else
				e2 = 2*err
				If e2 >= (-1 * dy)
					err :- dy
					x :+ sx
				EndIf
				If e2 < dx
					err :+ dx
					y :+ sy
				EndIf
			EndIf
		Next
	'EndIf	


Last edited 2011


JiPrime(Posted 2011) [#8]
My good sir, you are godsend.

Many thanks.