Here's what SC3D looks like:
In card 1:
Open card:
// main loop
IF MAPLOADED = TRUE THEN
ON TIMER 1
// if a key has been hit, check what it is.
// I had to include seperate statements for the
// option, command, control, and shift keys because of the way that SC handles input
IF keyhit = TRUE THEN
KEYDOWN
END IF
IF OPTIONKEY = TRUE THEN
KEYDOWN
END IF
IF COMMANDKEY = TRUE THEN
KEYDOWN
END IF
IF SHIFTKEY = TRUE THEN
KEYDOWN
END IF
IF CONTROLKEY = TRUE THEN
KEYDOWN
END IF
// render the world and show the frame
LET oktorender = true
IF changed = TRUE THEN
UPDATESCREEN
LET changed = false
END IF
END TIMER
END IF
Keydown:
Global:
KEYDOWN method:
LET blockotherkeys = FALSE
// option - move up
IF OPTIONKEY = TRUE THEN
// do stuff
LET blockotherkeys = TRUE // becuase SC handles key presses strangely
END IF
// command - move down
IF COMMANDKEY = TRUE THEN
// do stuff
LET blockotherkeys = TRUE
END IF
// shift - look up
IF SHIFTKEY = TRUE THEN
// do stuff
LET blockotherkeys = TRUE
END IF
// control - look down
IF CONTROLKEY = TRUE THEN
// do stuff
LET blockotherkeys = TRUE
END IF
IF blockotherkeys = FALSE THEN
// turn left - left arrow
IF KEY$ = LEFTARROW$ THEN
// do stuff
END IF
// turn right - right arrow
IF KEY$ = RIGHTARROW$ THEN
// do stuff
END IF
// move forward - up arrow
IF KEY$ = UPARROW$ THEN
// do stuff
END IF
// move backwards - down arrow
IF KEY$ = DOWNARROW$ THEN
// do stuff
END IF
END IF
LET keyhit = false // tell the main loop to get on with it
LET changed = true // tell the engine that something is different
You could incorporate a "stop" button and have keydown code execute on a timer instead. Something like this: (GM syntax)
ON TIMER 1
IF keydown$ = "UPARROW" THEN
' Code to execute while up arrow is the last button pressed.
END IF
IF keydown$ = "DOWNARROW" THEN
' Code to execute while down arrow is the last button pressed.
END IF
IF keydown$ = "LEFTARROW" THEN
' Code to execute while left arrow is the last button pressed.
END IF
IF keydown$ = "RIGHTARROW" THEN
' Code to execute while right arrow is the last button pressed.
END IF
END TIMER
Then, as soon as an unassigned button is pressed (spacebar for example), the timer routine will stop executing the code for the arrow buttons.
Oh. Here's a GM example: http://www.mediafire.com/?7c312c1v639i4gv
And here's the code:
spriteX = 286
spriteY = 132
SPRITE 1 spriteX spriteY ship.gif
ON KEYDOWN
SETWINDOWTITLE Last key pressed: $keydown$$
END KEYDOWN
ON TIMER 1
YMoveAmount = 0
XMoveAmount = 0
IF keydown$ = "UPARROW" THEN YMoveAmount = -5
IF keydown$ = "DOWNARROW" THEN YMoveAmount = 5
IF keydown$ = "LEFTARROW" THEN XMoveAmount = -5
IF keydown$ = "RIGHTARROW" THEN XMoveAmount = 5
spriteX = spriteX + XmoveAmount
spriteY = spriteY + YmoveAmount
SPRITE 1 spriteX spriteY
END TIMER
And here's a screencast, you lucky people: http://screencast.com/t/8DaMq2OSHX9
I've just tried your code in Sc and it turns out that KEY$ stays equal to the last key pressed until a new key is pressed. It's unfortunate.
I did figure a way to make smooth movement, though the player keeps moving a second after the key was depressed:
Open CardCREATESPRITE 1, "guy"
MOVESPRITE 1, 210, 100
LET moveCount = 0
ON TIMER 0
IF moveCount > 0 THEN
IF KEY$ = UPARROW$ THEN
PUSHSPRITE 1, 0, -1
END IF
IF KEY$ = DOWNARROW$ THEN
PUSHSPRITE 1, 0, 1
END IF
IF KEY$ = LEFTARROW$ THEN
PUSHSPRITE 1,
-1, 0
END IF
IF KEY$ = RIGHTARROW$ THEN
PUSHSPRITE 1, 1, 0
END IF
LET moveCount = moveCount - 1
END IF
END TIMER
Key Down
I just figured a better way:
Open CardCREATESPRITE 1, "guy"
MOVESPRITE 1, 210, 100
LET moveCount = 0
LET LASTARROW$ = ""
ON TIMER 0
IF moveCount > 0 THEN
IF KEY$ = UPARROW$ THEN
PUSHSPRITE 1, 0, -1
END IF
IF KEY$ = DOWNARROW$ THEN
PUSHSPRITE 1, 0, 1
END IF
IF KEY$ = LEFTARROW$ THEN
PUSHSPRITE 1, -1, 0
END IF
IF KEY$ = RIGHTARROW$ THEN
PUSHSPRITE 1, 1, 0
END IF
LET moveCount = moveCount - 1
END IF
END TIMER
Key DownIF moveCount = 0 THEN
LET moveCount = 80
ELSE
LET moveCount = 14
END IF
IF LASTARROW$ = KEY$ THEN
ELSE
LET moveCount = 80
END IF
LET LASTARROW$ = KEY$
The movement is nearly perfect. The only issue is if you tap an arrow key once it moves for a second before stopping.
Here's a video: http://cl.ly/380B1B352g1G1d1y2x3Y
oh i see now, i never noticed that before. gandolfs solution works pretty good. i tweaked the code and time limits a little. this would be a good thing to mention to mike, theres a mouseup so it should be easy to add a keyup.
key down:
IF moveCount = 0 THEN LET moveCount = 30
IF moveCount > 0 THEN LET moveCount = 10
IF LASTARROW$ <> KEY$ THEN LET moveCount = 30
LET LASTARROW$ = KEY$
open card:
CREATESPRITE 1, "x"
MOVESPRITE 1, 200, 200
ON TIMER 1
IF moveCount > 0 THEN
IF KEY$ = UPARROW$ THEN PUSHSPRITE 1, 0, -2
IF KEY$ = DOWNARROW$ THEN PUSHSPRITE 1, 0, 2
IF KEY$ = LEFTARROW$ THEN PUSHSPRITE 1, -2, 0
IF KEY$ = RIGHTARROW$ THEN PUSHSPRITE 1, 2, 0
LET moveCount = moveCount - 1
END IF
END TIMER