Hello,
I am new to game developing as am doing as final project for a course.
I managed to animate everything as I am doing a small 2d beat 'em up type of game.
The issue I am facing is that I set the key "u" to be a punch button. When key "u" is pressed (using keypressed) I set the character attribute of self.jab to true. That will stop the idle and walking sprite from being drawn and the sprite of the punch will be drawn.
I then set the keyreleased to set self.jab = false so the idle or waking sprite to be drawn again.
The issue I am facing is that it all works on press, however, if I hold key "u" down, the idle or walking sprite are never drawn, only when I release the key "u".
I have tried to add logic using isrepeat, love.keyboard.isDown("u") and nothing makes it work. The default attribute for self.jab is set to false.
I have attached the full code for limbs.lua, which creates the limbs (arms and legs) and their properties.
They directly related to the character, so I attached that as well.
keypressed and keyreleased logic are in character.lua.
Hope you can help!
Thanks in advance!
punch animation - keypressed, keyreleased
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
punch animation - keypressed, keyreleased
- Attachments
-
- limbs.lua
- (3.25 KiB) Downloaded 240 times
-
- character.lua
- (8.7 KiB) Downloaded 255 times
Re: punch animation - keypressed, keyreleased
Hi. That's a fun but also very complicated part of coding your game, when you're taking input events and translating them into behaviors in your game, so as to solve the problem of "when I press a key I want to trigger this thing to happen, and this thing will go on by the next few frames regardless of whether that key is still pressed or not".
You need to learn about a design pattern called "Finite State Machine", which is a way of organizing the behaviors of things in your game. You can use it for animation, for enemy AI, for player actions etc., with many FSMs handling different aspects of your game.
You're already trying to do that with that "self.jab = true" logic. That is a form of state. With an FSM you can make it much more organized to support many different actions (jab, kick, run, walk, crawl, jump). You do that by taking an object-oriented approach, with all states sharing the same interface, so your code can go "update the current state, whatever it is".
When you press U, the character changes to the "jab" state, and in that state, per-frame, they will proceed to do whatever they have to do to complete that jab state, like advancing a frame of animation and checking if their fist hit an enemy sprite. By the end of it (like when the jab animation finishes, or whatever other rule that you chose), they will change to whatever state that they should change to next, usually the "idle" state.
So once you press U and the jab action begins, it doesn't matter whether the U key is still pressed while the jab is being performed, as what triggered the jab was the pressing of U, not the holding or the release of it. This would solve your "jab won't end until I release the key" problem.
You need to look for tutorials on implementing FSMs in your game. Here are some:
- https://gamedevelopertips.com/finite-st ... evelopers/
- https://code.tutsplus.com/finite-state- ... dev-11867t
You need to learn about a design pattern called "Finite State Machine", which is a way of organizing the behaviors of things in your game. You can use it for animation, for enemy AI, for player actions etc., with many FSMs handling different aspects of your game.
You're already trying to do that with that "self.jab = true" logic. That is a form of state. With an FSM you can make it much more organized to support many different actions (jab, kick, run, walk, crawl, jump). You do that by taking an object-oriented approach, with all states sharing the same interface, so your code can go "update the current state, whatever it is".
When you press U, the character changes to the "jab" state, and in that state, per-frame, they will proceed to do whatever they have to do to complete that jab state, like advancing a frame of animation and checking if their fist hit an enemy sprite. By the end of it (like when the jab animation finishes, or whatever other rule that you chose), they will change to whatever state that they should change to next, usually the "idle" state.
So once you press U and the jab action begins, it doesn't matter whether the U key is still pressed while the jab is being performed, as what triggered the jab was the pressing of U, not the holding or the release of it. This would solve your "jab won't end until I release the key" problem.
You need to look for tutorials on implementing FSMs in your game. Here are some:
- https://gamedevelopertips.com/finite-st ... evelopers/
- https://code.tutsplus.com/finite-state- ... dev-11867t
Re: punch animation - keypressed, keyreleased
Thank you very much for your input! I will surely have a look at these tutorials!RNavega wrote: ↑Tue Nov 14, 2023 11:23 pm Hi. That's a fun but also very complicated part of coding your game, when you're taking input events and translating them into behaviors in your game, so as to solve the problem of "when I press a key I want to trigger this thing to happen, and this thing will go on by the next few frames regardless of whether that key is still pressed or not".
You need to learn about a design pattern called "Finite State Machine", which is a way of organizing the behaviors of things in your game. You can use it for animation, for enemy AI, for player actions etc., with many FSMs handling different aspects of your game.
You're already trying to do that with that "self.jab = true" logic. That is a form of state. With an FSM you can make it much more organized to support many different actions (jab, kick, run, walk, crawl, jump). You do that by taking an object-oriented approach, with all states sharing the same interface, so your code can go "update the current state, whatever it is".
When you press U, the character changes to the "jab" state, and in that state, per-frame, they will proceed to do whatever they have to do to complete that jab state, like advancing a frame of animation and checking if their fist hit an enemy sprite. By the end of it (like when the jab animation finishes, or whatever other rule that you chose), they will change to whatever state that they should change to next, usually the "idle" state.
So once you press U and the jab action begins, it doesn't matter whether the U key is still pressed while the jab is being performed, as what triggered the jab was the pressing of U, not the holding or the release of it. This would solve your "jab won't end until I release the key" problem.
You need to look for tutorials on implementing FSMs in your game. Here are some:
- https://gamedevelopertips.com/finite-st ... evelopers/
- https://code.tutsplus.com/finite-state- ... dev-11867t
Re: punch animation - keypressed, keyreleased
The tutorials are great but I think it would take me too much time given my deadline to apply all of that. As I would have to learn and likely refactor lots of my code.
That being said, I was trying to find a work around and I do not understand why the following does not work:
function love.keypressed(key, isrepeat)
love.keyboard.setKeyRepeat(true, 2, 0)
if key == "u" then
P1_punch.jab = true
P1.jab = true
P1_punch.punchActive = love.timer.getTime()
end
if key == "u" and isrepeat then
P1_punch.jab = false
P1.jab = false
print("repeat")
end
The code above would print "repeat" as soon as key u is pressed. Shouldn't it wait 2 seconds to do so as per setKeyRepeat function states?
Or is add it into a ifelse statement, it never prints "repeat". So it always reverts back to self.jab = true
Character punch mechanics
if key == "u" then
P1_punch.jab = true
P1.jab = true
P1_punch.punchActive = love.timer.getTime()
elseif key == "u" and isrepeat then
P1_punch.jab = false
P1.jab = false
print("repeat")
end
That being said, I was trying to find a work around and I do not understand why the following does not work:
function love.keypressed(key, isrepeat)
love.keyboard.setKeyRepeat(true, 2, 0)
if key == "u" then
P1_punch.jab = true
P1.jab = true
P1_punch.punchActive = love.timer.getTime()
end
if key == "u" and isrepeat then
P1_punch.jab = false
P1.jab = false
print("repeat")
end
The code above would print "repeat" as soon as key u is pressed. Shouldn't it wait 2 seconds to do so as per setKeyRepeat function states?
Or is add it into a ifelse statement, it never prints "repeat". So it always reverts back to self.jab = true
Character punch mechanics
if key == "u" then
P1_punch.jab = true
P1.jab = true
P1_punch.punchActive = love.timer.getTime()
elseif key == "u" and isrepeat then
P1_punch.jab = false
P1.jab = false
print("repeat")
end
- BrotSagtMist
- Party member
- Posts: 662
- Joined: Fri Aug 06, 2021 10:30 pm
Re: punch animation - keypressed, keyreleased
love.keypressed( key, scancode, isrepeat ) Is the definition of that function.
You can not just left values out.
You should read up on how to actually call a function and pass arguments.
I also see zero reason why anyone would need to dabble with repeats for controlling stuff on the screen.
There is a fundamental error in what you think you need to do here, the key repeat is pretty much only useful for gui elements, text input and menus.
All you get here is pretty bad autofire buttons.
You can not just left values out.
You should read up on how to actually call a function and pass arguments.
I also see zero reason why anyone would need to dabble with repeats for controlling stuff on the screen.
There is a fundamental error in what you think you need to do here, the key repeat is pretty much only useful for gui elements, text input and menus.
All you get here is pretty bad autofire buttons.
obey
Re: punch animation - keypressed, keyreleased
Hm, now that I think about it, isn't it odd that your course asked you to do a project but didn't teach you the fundamentals needed to make that project?
Anyway, you need two switches / flags: one that tells if the character 'is currently punching', and another that tells if the character 'can begin punching'.
Also, I'd suggest separating the responsibilities of functions in your code. The keypressed() handler shouldn't change stuff about the player directly, but rather just read the key-presses and translate them into "what the human player wants the game to do". After that, in other parts of your code outside of keypressed(), that information will be read and reacted to -- which keypressed() will know nothing about, since it doesn't care about that.
Code: Select all
local actionInputs = {
jab = false,
moveRight = false,
moveLeft = false,
}
local P1 = {
isJabbing = false, -- Whether the player character is doing a jab.
canJab = false, -- Whether the player character can START a jab.
}
function love.keypressed(key, isrepeat)
if key == 'u' then
actionInputs.jab = true
end
if key == 'right' then
actionInputs.moveRight = true
end
if key == 'left' then
actionInputs.moveLeft = true
end
end
function love.keyreleased(key)
if key == 'u' then
actionInputs.jab = false
end
if key == 'right' then
actionInputs.moveRight = false
end
if key == 'left' then
actionInputs.moveLeft = false
end
end
function playerUpdate(dt)
if P1.isJabbing then
-- Update the jabbing animation, check for enemy collisions etc.
-- When the animation is over, set P1.isJabbing = false
else
if actionInputs.jab then
if P1.canJab then
P1.isJabbing = true
P1.canJab = false
-- Initialize the punchActive timer and other stuff that this
-- function "playerUpdate" doesn't need to know about.
P1_punch.startJab()
end
else
P1.canJab = true
end
end
if actionInputs.moveRight then
P1.x = P1.x + P1.speed
-- Test for collisions etc.
end
end
Re: punch animation - keypressed, keyreleased
Thank you very much for another helpful insight! I will refactor my code and try to move things to my character file instead of separating the limbs for now as it makes less confusion in my head. I will certainly try and implemented as you suggested!RNavega wrote: ↑Wed Nov 15, 2023 10:23 pmHm, now that I think about it, isn't it odd that your course asked you to do a project but didn't teach you the fundamentals needed to make that project?
Anyway, you need two switches / flags: one that tells if the character 'is currently punching', and another that tells if the character 'can begin punching'.
Also, I'd suggest separating the responsibilities of functions in your code. The keypressed() handler shouldn't change stuff about the player directly, but rather just read the key-presses and translate them into "what the human player wants the game to do". After that, in other parts of your code outside of keypressed(), that information will be read and reacted to -- which keypressed() will know nothing about, since it doesn't care about that.
Code: Select all
local actionInputs = { jab = false, moveRight = false, moveLeft = false, } local P1 = { isJabbing = false, -- Whether the player character is doing a jab. canJab = false, -- Whether the player character can START a jab. } function love.keypressed(key, isrepeat) if key == 'u' then actionInputs.jab = true end if key == 'right' then actionInputs.moveRight = true end if key == 'left' then actionInputs.moveLeft = true end end function love.keyreleased(key) if key == 'u' then actionInputs.jab = false end if key == 'right' then actionInputs.moveRight = false end if key == 'left' then actionInputs.moveLeft = false end end function playerUpdate(dt) if P1.isJabbing then -- Update the jabbing animation, check for enemy collisions etc. -- When the animation is over, set P1.isJabbing = false else if actionInputs.jab then if P1.canJab then P1.isJabbing = true P1.canJab = false -- Initialize the punchActive timer and other stuff that this -- function "playerUpdate" doesn't need to know about. P1_punch.startJab() end else P1.canJab = true end end if actionInputs.moveRight then P1.x = P1.x + P1.speed -- Test for collisions etc. end end
As for the course, it is CS50, so it's more a computer science course rather than a game development specific one. The "build a game with Lua in love2d" was one of their suggestions as to what I could try as a final project, which I choose given I am really keen on video games.
thanks again, hopefully I will figure this out and make it work soon!
Re: punch animation - keypressed, keyreleased
So I tried to implement the below based on what you recommended. I added a print statement and although as soon as I press u it does print "true", as soon I press I get an error for the draw() function stating that expects a quad but got nil.
mind you that self.jab should be doing the job of P1.jabbing on your code.
-- jab animation
within draw() function I have
Which was working ok back on my original code apart from the issue that I had originally. Which would make the sprite disappear if I held "u" down.
I also updated the keypress() and key release() to only change the actionInputs and not the character attributes
e.g.
I have tried many different variations of this logic but could not make it work
mind you that self.jab should be doing the job of P1.jabbing on your code.
-- jab animation
Code: Select all
if self.jab then
jab_elapsedTime = jab_elapsedTime + dt
if jab_elapsedTime > 0.5 then
if jab_currentFrame < 3 then
jab_currentFrame = jab_currentFrame + 1
else
jab_currentFrame = 3
end
jab_activeFrame = jabFrames[jab_currentFrame]
end
else
if actionInputs.jab then
if self.canjab then
self.jab = true
self.canjab = false
self.punchActive = love.timer.getTime()
end
else
self.canjab = true
self.jab = false
end
print(self.jab)
end
--end of jab animation
Code: Select all
--jab sprit jabbing right
if self.facing == "right" and self.jab == true and (love.timer.getTime() - self.punchActive) < 0.1 then
love.graphics.rectangle("line", self.x +30, self.y, self.width, 10)
love.graphics.draw(P1_jab, jab_activeFrame, self.x, self.y, 0, 2.3, 2.3, (self.width * 1.2) + 10, 23)
end
I also updated the keypress() and key release() to only change the actionInputs and not the character attributes
e.g.
Code: Select all
if key == "u" then
--P1_punch.jab = true
-- P1.jab = true
actionInputs.jab = true
-- P1.punchActive = love.timer.getTime()
end
I have tried many different variations of this logic but could not make it work
Re: punch animation - keypressed, keyreleased
Edit: in the draw function, is P1_jab nil, or is jab_activeFrame?
For the latter to be nil, it means that the jabFrames table is being indexed with some key that leads to no value, therefore it returns nil.
Remember that in Lua tables are usually indexed from 1 and above, see if that's not the cause. You also need to reset jab_currentFrame to 1 right when the jab starts.
PS you shouldn't set self.jab to false in case actionInputs.jab is false. Those are two separate things: what's happening in the game vs. what the player wants the game to do, which won't always happen. For instance, if the player is pressing actionInputs.moveRight so they want to move right, but the character might be facing a wall and won't move -- the game has a final say on what happens (in this case, nothing).
The jab ends when the next frame of animation is outside the range, so you know that all frames were properly displayed before. That's when you set self.jab to false and change state to idle or whatever (unless you're going for something like the character stays with their arm extended until you let go of the key, which would be a different logic)
For the latter to be nil, it means that the jabFrames table is being indexed with some key that leads to no value, therefore it returns nil.
Remember that in Lua tables are usually indexed from 1 and above, see if that's not the cause. You also need to reset jab_currentFrame to 1 right when the jab starts.
PS you shouldn't set self.jab to false in case actionInputs.jab is false. Those are two separate things: what's happening in the game vs. what the player wants the game to do, which won't always happen. For instance, if the player is pressing actionInputs.moveRight so they want to move right, but the character might be facing a wall and won't move -- the game has a final say on what happens (in this case, nothing).
The jab ends when the next frame of animation is outside the range, so you know that all frames were properly displayed before. That's when you set self.jab to false and change state to idle or whatever (unless you're going for something like the character stays with their arm extended until you let go of the key, which would be a different logic)
Re: punch animation - keypressed, keyreleased
Thank you very much for your help! I have managed to make it work as I intended nowRNavega wrote: ↑Fri Nov 17, 2023 7:04 pm Edit: in the draw function, is P1_jab nil, or is jab_activeFrame?
For the latter to be nil, it means that the jabFrames table is being indexed with some key that leads to no value, therefore it returns nil.
Remember that in Lua tables are usually indexed from 1 and above, see if that's not the cause. You also need to reset jab_currentFrame to 1 right when the jab starts.
PS you shouldn't set self.jab to false in case actionInputs.jab is false. Those are two separate things: what's happening in the game vs. what the player wants the game to do, which won't always happen. For instance, if the player is pressing actionInputs.moveRight so they want to move right, but the character might be facing a wall and won't move -- the game has a final say on what happens (in this case, nothing).
The jab ends when the next frame of animation is outside the range, so you know that all frames were properly displayed before. That's when you set self.jab to false and change state to idle or whatever (unless you're going for something like the character stays with their arm extended until you let go of the key, which would be a different logic)
I had forgotten to re-set the jab_elapsedTime back to 0 after the frame was drawn.
Thank you once again!
Who is online
Users browsing this forum: Google [Bot], Semrush [Bot] and 10 guests