Faster movement
BlitzMax Forums/BlitzMax Beginners Area/Faster movement
| ||
| 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
|
| ||
| 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 |
| ||
| 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 |
| ||
| 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) |
| ||
| 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 |
| ||
| 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 |
| ||
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 |
| ||
| My good sir, you are godsend. Many thanks. |