ID:2581898
 
(See the best response by Lummox JR.)
Code:
client
proc/GetSpeedDelay(n)
return world.tick_lag * (n ? n : 1)

var
frames_per_tile_movement = 2 // The amount of frames you wait for each tile you move
tmp
move_time = 0

Move()
if(world.time < move_time) return

move_time = world.time + GetSpeedDelay(frames_per_tile_movement)

return ..()


Problem description:
Heyo, I've created a very simple player movement script, and I'm having some unexpected results.

Basically, the player moves 1 tile every 2 frames in a world running on 20 FPS.
So overall, 10 tiles per second is the speed I'm aiming to achieve.

The problem I'm running into is that input is sometimes unresponsive, and some input commands (arrow keys for example) are being ignored. This is very noticable if I spam the left and right keys, I take too many steps sometimes, sometimes I dont take a step to the other direction at all, just overall unresponsive.

Is there perhaps a better solution to player movement that can bypass this responsiveness issue? Thanks!!!

Best response
A couple of issues may be in play here.

First, I think you'll find that if you replace the default movement scheme with one that uses the Any and Any+UP macros, and a global movement loop, you'll get much smoother results across the board.

Likely most or even all of what you're seeing relates to the fact that the default movement system is based on macros such as North+REP pointing to the .north command, which is not an instant verb, and those commands therefore have to queue up. That's why you see it taking too many steps if you switch direction, and probably why it's sometimes not moving at all. A system based on keydown/keyup and a movement loop, using an instant verb, would eliminate all of that. Here's a very simple system I put in place on a test project recently:

proc/MoveLoop()
while(1)
for(var/client/C)
if(C.movedir && C.mob)
try
step(C.mob, C.movedir)
catch()
sleep(world.tick_lag)
world/New()
spawn() MoveLoop()


client
var/list/keys = list()
var/movedir = 0

var/list/dirlist = list(\
"North"=NORTH,
"South"=SOUTH,
"East"=EAST,
"West"=WEST,
"Northeast"=NORTHEAST,
"Northwest"=NORTHWEST,
"Southeast"=SOUTHEAST,
"Southwest"=SOUTHWEST)

client/verb/KeyDown(k as text,d as num)
set instant = 1
if(d)
keys[k] = 1
if(keys.len > 10) keys.Cut()
else keys -= k
d = 0
for(k in keys) d |= dirlist[k]
movedir = d

Note that system simply does one move per tick, so it doesn't take last movement time or a cooldown into account; that's something you'd need to change. To use this you'd set up two macros in your game skin, losing all the default movement macros, to do this:

Any     KeyDown "[[*]]" 1
Any+UP KeyDown "[[*]]" 0

Now above I said that a movement loop will fix most of your problems. It's also possible that you're overtaxing the keyboard if you press too many keys at once, causing what's called "ghosting". Gaming keyboards don't tend to have this problem as they have a much higher limit of simultaneous keypresses, but cheap keyboards sometimes struggle with 3 non-modifier keys, or even 2 in some cases.