Implementing player movement in a Finite State Machine
Posted: Sat Feb 28, 2015 2:08 pm
Hello everyone,
first of all, I'm really grateful for having found LÖVE and this forum. Game development has always been my favorite hobby, and with LÖVE it feels like the game I'm day-dreaming about (like everyone else here probably ) could be really achieved with enough effort and time.
Right now, I'm trying to prototype a basic platformer---walking, jumping, and some combat later. I've attached a .love file that represents the current state. If you open it, you'll be able to control the player using A/D (left/right) and W (a single jump). (Big thanks to kikito for his bump.lua (and other libraries) that I'm using here. Most of the movement methods are from his bump.lua example game.)
(I've stripped away some unnecessary stuff like the component system so that only the important parts about player movement remain. These are mainly located in the player.lua file and in the love.update(dt) function.)
So far I'm quite satisfied with the current mechanics--for instance, the player has to release W if he (she, in this case) wants to jump again. (In the beginning it was the case that while holding W, the player would immediately start another jump after she touched the ground again.)
However, I'm a little bit concerned about how the game logic processes the player movement. If you look at the .lua files, player movement is split into two parts: love.update(dt) checks whether a specific key is pressed, but love.keypressed(key) is also processing the W key---giving the player a little bit of a "jump" velocity.
I was under the impression that it's best to keep player movement uniform in a single update() function. Especially since my next goal would be to process player movement using a finite state machine---something that I've read about here: http://gameprogrammingpatterns.com/state.html
This is where I'm currently finding myself at a loss. My first idea would be to use love.keypressed() to change the player stage, e.g. like this:
And using love.keyreleased() in a similar manner, for instance to set the player state to "FALLING" (meaning that the player cannot jump during this time until he touches the ground again):
The player:update(dt) function could then look something like (this time in pseudo-code):
I'm using goto and labels here because of another pattern that I've found in "Programming in Lua" (something about State Machines being easy to implement using goto).
However, I find it terribly hard to reconcile this state machine with all the booleans the game has to check if it wants to allow the player to jump, or allowing movement while jumping (e.g. jumping to the right in an arc-like shape).
That's why I wanted to ask here first if you think that there's a better approach to this. If I shouldn't use a FSM---do you think it's alright to have movement logic both in love.update() and love.keypressed()?
first of all, I'm really grateful for having found LÖVE and this forum. Game development has always been my favorite hobby, and with LÖVE it feels like the game I'm day-dreaming about (like everyone else here probably ) could be really achieved with enough effort and time.
Right now, I'm trying to prototype a basic platformer---walking, jumping, and some combat later. I've attached a .love file that represents the current state. If you open it, you'll be able to control the player using A/D (left/right) and W (a single jump). (Big thanks to kikito for his bump.lua (and other libraries) that I'm using here. Most of the movement methods are from his bump.lua example game.)
(I've stripped away some unnecessary stuff like the component system so that only the important parts about player movement remain. These are mainly located in the player.lua file and in the love.update(dt) function.)
So far I'm quite satisfied with the current mechanics--for instance, the player has to release W if he (she, in this case) wants to jump again. (In the beginning it was the case that while holding W, the player would immediately start another jump after she touched the ground again.)
However, I'm a little bit concerned about how the game logic processes the player movement. If you look at the .lua files, player movement is split into two parts: love.update(dt) checks whether a specific key is pressed, but love.keypressed(key) is also processing the W key---giving the player a little bit of a "jump" velocity.
I was under the impression that it's best to keep player movement uniform in a single update() function. Especially since my next goal would be to process player movement using a finite state machine---something that I've read about here: http://gameprogrammingpatterns.com/state.html
This is where I'm currently finding myself at a loss. My first idea would be to use love.keypressed() to change the player stage, e.g. like this:
Code: Select all
function love.keypressed(key)
if key == "a" then
player.state = "WALKING_LEFT"
elseif key == "a" then
player.state = "WALKING_RIGHT"
elseif key == "w" then
player.state = "JUMPING"
else
player.state = "STANDING"
end
end
Code: Select all
function love.keyreleased(key)
if key == "w" and player.isJumpingOrFlying then
player.state = "FALLING"
end
end
Code: Select all
if player.state == "STANDING" then
goto STANDING
end
if player.state == "WALKING_LEFT" then
goto WALKING_LEFT
end
if player.state == "WALKING_RIGHT" then
goto WALKING_RIGHT
end
if player.state == "JUMPING" then
goto JUMPING
end
::STANDING::
applyFriction()
goto END_MOVEMENT
::WALKING_LEFT::
player.vx = player.vx - player.movementSpeed
goto END_MOVEMENT
::WALKING_RIGHT::
player.vx = player.vx + player.movementSpeed
goto END_MOVEMENT
::JUMPING::
player.vy = player.vy + player.jumpVelocity
goto END_MOVEMENT
::END_MOVEMENT::
if checkIfNoCollisions() then
player.left = player.vx
player.top = player.vy
end
However, I find it terribly hard to reconcile this state machine with all the booleans the game has to check if it wants to allow the player to jump, or allowing movement while jumping (e.g. jumping to the right in an arc-like shape).
That's why I wanted to ask here first if you think that there's a better approach to this. If I shouldn't use a FSM---do you think it's alright to have movement logic both in love.update() and love.keypressed()?