How do I update my crouch animation? (anim8)
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
How do I update my crouch animation? (anim8)
Ok so I decided to give my character a crouching function and have a variable called Player.crouch to check if the character is crouching or not. The code works as intended however the animations aren't working as well as I'd hope. What is supposed to happen is a transition animation called "hide" before he stays in the crouched position, but the character immediately goes to the crouched position without transition. I tried the keypresses function but without luck.
- Attachments
-
- TestGame.love
- (217.7 KiB) Downloaded 73 times
Re: How do I update my crouch animation? (anim8)
Don't define love.keypressed inside another function; that's not how it's supposed to work. In that place you can use love.keyboard.isScancodeDown instead. Also don't use love.keyboard.isDown, always use the isScancodeDown version if you want your game to be playable by French users (in French keyboards, the WASD keys are actually ZQSD).
The immediate problem that you're having is that after changing self.anim.curr to the hide animation, Player:move() detects that self.crouch = true and then overwrites self.anim.curr with the hat animation. However, you want to change to the hat animation only when the hide one ends.
To do this, remove the line self.anim.curr = self.anim.hat from Player:move(), so that it doesn't get overwritten, and in Player:load change the animation loading line for the hide animation to this:
Lastly, you may want to obey the 's' key only when not already crouching, so that the hide animation is not played every time 's' is pressed.
The immediate problem that you're having is that after changing self.anim.curr to the hide animation, Player:move() detects that self.crouch = true and then overwrites self.anim.curr with the hat animation. However, you want to change to the hat animation only when the hide one ends.
To do this, remove the line self.anim.curr = self.anim.hat from Player:move(), so that it doesn't get overwritten, and in Player:load change the animation loading line for the hide animation to this:
Code: Select all
self.anim.hide = anim8.newAnimation(self.grid('22-27', 1), 0.1,
function () self.anim.curr = self.anim.hat end)
Re: How do I update my crouch animation? (anim8)
The problem was partly caused by Player:move at the last condition, the state changing to "hat" while the "hide" anim hadn't even started:
I don't hide from you that I had trouble identifying the problem, I quickly understood that you tried a lot of things to get by but it quickly became complicated to find your way around, so I took the liberty I tried to clean up the code and I managed to get it to work like that, so I guess it's from the moment I removed the condition I quoted that the problem went away, although I had already made a lot of small modifications, I could not tell you with certainty if there were other problems elsewhere unfortunately.
By the way the code had an error from the launch, it was not very easy to debug
Here's how I rewrote it, it should be easier to maintain:
Code: Select all
else
if self.crouch == false then
self.anim_curr = self.anim.idle
else
self.anim_curr = self.anim.hat
end
end
By the way the code had an error from the launch, it was not very easy to debug
Here's how I rewrote it, it should be easier to maintain:
Code: Select all
Player = {}
function Player:load()
self.x = love.graphics.getWidth() / 2
self.y = love.graphics.getHeight() / 2 - 62
self.spriteSheet = love.graphics.newImage("Sprites/TheWizzl.png")
self.speed = 400
self.ground = self.y
self.yVel = 0
self.jump_height = -300
self.gravity = -500
-- Animation Information
local grid = anim8.newGrid( -- No need to store this function in the table
32,32, self.spriteSheet:getWidth(), self.spriteSheet:getHeight()
)
self.anim = {}
self.anim.idle = anim8.newAnimation(grid('1-4', 1), 0.2)
self.anim.run = anim8.newAnimation(grid('8-11', 1), 0.1)
self.anim.jump = anim8.newAnimation(grid(19, 1), 0.2)
self.anim.fall = anim8.newAnimation(grid(20, 1), 0.2)
self.anim.hide = anim8.newAnimation(grid('22-27', 1), 0.1)
self.anim.hat = anim8.newAnimation(grid(28, 1), 0.1)
self.anim.hatWalk = anim8.newAnimation(grid('29-33', 1), 0.1)
self.anim.getUp = anim8.newAnimation(grid('35-38', 1), 0.1)
self:setState("idle")
self.on_anim = false -- I added this so that the movement does not break the animation of getting up or lying down
self.crouch = false
self.switch = 2
end
function Player:setState(state)
if state ~= self.state then
self.anim_curr = self.anim[state]
self.anim_curr:gotoFrame(1)
self.prev_state = self.state
self.state = state
end
end
function Player:update(dt)
if love.keyboard.isDown("s") then
if not self.crouch then
self:setState("hide")
self.anim_on = true
self.crouch = true
end
end
if love.keyboard.isDown("space") then
if self.crouch then
self:setState("getUp")
self.anim_on = true
self.crouch = false
end
end
if love.keyboard.isDown("escape") then
love.event.quit()
end
-- State management --
local state = self.state
if state == "hide" then -- You can manage behaviors related to states here
if self.anim_curr.position == 6 then
self:setState("hat")
self.anim_on = false
end
elseif state == "getUp" then
if self.anim_curr.position == 3 then
self:setState("idle")
self.anim_on = false
end
end
-- Movement and anim update --
Player:move(dt)
Player:jump(dt)
self.anim_curr:update(dt)
end
function Player:draw()
self.anim_curr:draw(self.spriteSheet, self.x, self.y, nil, self.switch, 2, 16)
end
function Player:move(dt)
local onMove;
if love.keyboard.isDown("a") then
self.x = self.x - self.speed * dt
self.switch = -2
onMove = true
elseif love.keyboard.isDown("d") then
self.x = self.x + self.speed * dt
self.switch = 2
onMove = true
end
if not self.anim_on then
if onMove then
self:setState((self.crouch) and "hatWalk" or "run")
else
self:setState((self.crouch) and "hat" or "idle")
end
end
end
function Player:jump(dt) -- I haven't touched this function.
if self.crouch == false then
if love.keyboard.isDown("w") then
if self.yVel == 0 then
self.yVel = self.jump_height
end
end
if self.yVel ~= 0 then
self.y = self.y + self.yVel * dt
self.yVel = self.yVel - self.gravity * dt
end
if self.y > self.ground then
self.yVel = 0
self.y = self.ground
end
if self.yVel < 0 then
self.anim_curr = self.anim.jump
elseif self.yVel > 0 then
self.anim_curr = self.anim.fall
end
end
end
- Attachments
-
- TestGame-corrected.love
- (216.09 KiB) Downloaded 92 times
Re: How do I update my crouch animation? (anim8)
Thank you, finally someone who thinks about it ! I did not dare to add this modification, it should not be imposed but it tempted me well
Re: How do I update my crouch animation? (anim8)
So do I change it to self.anim.curr = self.anim.hide in the move function?pgimeno wrote: ↑Tue Mar 21, 2023 1:17 pm Don't define love.keypressed inside another function; that's not how it's supposed to work. In that place you can use love.keyboard.isScancodeDown instead. Also don't use love.keyboard.isDown, always use the isScancodeDown version if you want your game to be playable by French users (in French keyboards, the WASD keys are actually ZQSD).
The immediate problem that you're having is that after changing self.anim.curr to the hide animation, Player:move() detects that self.crouch = true and then overwrites self.anim.curr with the hat animation. However, you want to change to the hat animation only when the hide one ends.
To do this, remove the line self.anim.curr = self.anim.hat from Player:move(), so that it doesn't get overwritten, and in Player:load change the animation loading line for the hide animation to this:
Lastly, you may want to obey the 's' key only when not already crouching, so that the hide animation is not played every time 's' is pressed.Code: Select all
self.anim.hide = anim8.newAnimation(self.grid('22-27', 1), 0.1, function () self.anim.curr = self.anim.hat end)
Re: How do I update my crouch animation? (anim8)
Bigfoot71 wrote: ↑Tue Mar 21, 2023 1:48 pm The problem was partly caused by Player:move at the last condition, the state changing to "hat" while the "hide" anim hadn't even started:I don't hide from you that I had trouble identifying the problem, I quickly understood that you tried a lot of things to get by but it quickly became complicated to find your way around, so I took the liberty I tried to clean up the code and I managed to get it to work like that, so I guess it's from the moment I removed the condition I quoted that the problem went away, although I had already made a lot of small modifications, I could not tell you with certainty if there were other problems elsewhere unfortunately.Code: Select all
else if self.crouch == false then self.anim_curr = self.anim.idle else self.anim_curr = self.anim.hat end end
By the way the code had an error from the launch, it was not very easy to debug
Here's how I rewrote it, it should be easier to maintain:Code: Select all
Player = {} function Player:load() self.x = love.graphics.getWidth() / 2 self.y = love.graphics.getHeight() / 2 - 62 self.spriteSheet = love.graphics.newImage("Sprites/TheWizzl.png") self.speed = 400 self.ground = self.y self.yVel = 0 self.jump_height = -300 self.gravity = -500 -- Animation Information local grid = anim8.newGrid( -- No need to store this function in the table 32,32, self.spriteSheet:getWidth(), self.spriteSheet:getHeight() ) self.anim = {} self.anim.idle = anim8.newAnimation(grid('1-4', 1), 0.2) self.anim.run = anim8.newAnimation(grid('8-11', 1), 0.1) self.anim.jump = anim8.newAnimation(grid(19, 1), 0.2) self.anim.fall = anim8.newAnimation(grid(20, 1), 0.2) self.anim.hide = anim8.newAnimation(grid('22-27', 1), 0.1) self.anim.hat = anim8.newAnimation(grid(28, 1), 0.1) self.anim.hatWalk = anim8.newAnimation(grid('29-33', 1), 0.1) self.anim.getUp = anim8.newAnimation(grid('35-38', 1), 0.1) self:setState("idle") self.on_anim = false -- I added this so that the movement does not break the animation of getting up or lying down self.crouch = false self.switch = 2 end function Player:setState(state) if state ~= self.state then self.anim_curr = self.anim[state] self.anim_curr:gotoFrame(1) self.prev_state = self.state self.state = state end end function Player:update(dt) if love.keyboard.isDown("s") then if not self.crouch then self:setState("hide") self.anim_on = true self.crouch = true end end if love.keyboard.isDown("space") then if self.crouch then self:setState("getUp") self.anim_on = true self.crouch = false end end if love.keyboard.isDown("escape") then love.event.quit() end -- State management -- local state = self.state if state == "hide" then -- You can manage behaviors related to states here if self.anim_curr.position == 6 then self:setState("hat") self.anim_on = false end elseif state == "getUp" then if self.anim_curr.position == 3 then self:setState("idle") self.anim_on = false end end -- Movement and anim update -- Player:move(dt) Player:jump(dt) self.anim_curr:update(dt) end function Player:draw() self.anim_curr:draw(self.spriteSheet, self.x, self.y, nil, self.switch, 2, 16) end function Player:move(dt) local onMove; if love.keyboard.isDown("a") then self.x = self.x - self.speed * dt self.switch = -2 onMove = true elseif love.keyboard.isDown("d") then self.x = self.x + self.speed * dt self.switch = 2 onMove = true end if not self.anim_on then if onMove then self:setState((self.crouch) and "hatWalk" or "run") else self:setState((self.crouch) and "hat" or "idle") end end end function Player:jump(dt) -- I haven't touched this function. if self.crouch == false then if love.keyboard.isDown("w") then if self.yVel == 0 then self.yVel = self.jump_height end end if self.yVel ~= 0 then self.y = self.y + self.yVel * dt self.yVel = self.yVel - self.gravity * dt end if self.y > self.ground then self.yVel = 0 self.y = self.ground end if self.yVel < 0 then self.anim_curr = self.anim.jump elseif self.yVel > 0 then self.anim_curr = self.anim.fall end end end
Thanks a lot honestly! There only issue I see is that there is a bug where the character doesn't completely end the falling animation once he hits the ground, but I will surely take you corrections to consideration
Re: How do I update my crouch animation? (anim8)
But no problem, it's with pleasure, and yes, as I noted in the comments, I didn't modify the last `Player:jump` method.
You can also apply PGimeno's advice, especially with his last example, you should be able to do something even more compact than what I advised
Re: How do I update my crouch animation? (anim8)
About the jumping mechanic, I thought it was a simple issue and I sort of managed to fix it. However now my character can't preform the getting up animation. Is there another variable I should add? I am also confused about the state stuff.Bigfoot71 wrote: ↑Tue Mar 21, 2023 4:13 pmBut no problem, it's with pleasure, and yes, as I noted in the comments, I didn't modify the last `Player:jump` method.
You can also apply PGimeno's advice, especially with his last example, you should be able to do something even more compact than what I advised
Re: How do I update my crouch animation? (anim8)
Since I don't have your modifications I can't understand either why after modifying `Player:jump` the player does not stand up anymore... But don't panic!
I gave you an example of what the Player: jump method could look like, it could be optimized but hey, given the little it does for now, it's still very suitable. Here's the full script because I also made a few other changes, like PGimeno's suggestion, which will save you from handling state transitions in conditions in `Player:update` (I also added isScancodeDown instead of isDown, because not easy with an AZERTY keyboard):
Code: Select all
Player = {}
function Player:load()
self.x = love.graphics.getWidth() / 2
self.y = love.graphics.getHeight() / 2 - 62
self.spriteSheet = love.graphics.newImage("Sprites/TheWizzl.png")
self.speed = 400
self.ground = self.y
self.yVel = 0
self.jump_height = -300
self.gravity = -500
-- Animation Information
local grid = anim8.newGrid( -- No need to store this function in the table
32,32, self.spriteSheet:getWidth(), self.spriteSheet:getHeight()
)
self.anim = {}
self.anim.idle = anim8.newAnimation(grid('1-4', 1), 0.2)
self.anim.hat = anim8.newAnimation(grid(28, 1), 0.1)
self.anim.run = anim8.newAnimation(grid('8-11', 1), 0.1)
self.anim.hatWalk = anim8.newAnimation(grid('29-33', 1), 0.1)
self.anim.jump = anim8.newAnimation(grid(19, 1), 0.2)
self.anim.fall = anim8.newAnimation(grid(20, 1), 0.2)
self.anim.hide = anim8.newAnimation(grid('22-27', 1), 0.1, function ()
self:setState("hat") -- Applies the "hat" state at the end of the animation
self.on_anim = false
end)
self.anim.getUp = anim8.newAnimation(grid('35-38', 1), 0.1, function ()
self:setState("idle") -- Applies the "idle" state at the end of the animation
self.on_anim = false
end)
self:setState("idle")
self.on_anim = false -- This variable will be used to not launch a walk animation while another is in progress (jump, fall, hide, getUp)
self.crouch = false
self.switch = 2
end
function Player:setState(state)
if state ~= self.state then
self.anim_curr = self.anim[state]
self.anim_curr:gotoFrame(1)
self.prev_state = self.state
self.state = state
end
end
function Player:update(dt)
if love.keyboard.isScancodeDown("s") then
if not self.crouch
and self.y == self.ground then -- To avoid squatting in the air
self:setState("hide")
self.on_anim = true
self.crouch = true
end
end
if love.keyboard.isScancodeDown("space") then
if self.crouch then
self:setState("getUp")
self.on_anim = true
self.crouch = false
end
end
if love.keyboard.isScancodeDown("escape") then
love.event.quit()
end
-- Movement and anim update --
Player:move(dt)
Player:jump(dt)
self.anim_curr:update(dt)
end
function Player:draw()
self.anim_curr:draw(self.spriteSheet, self.x, self.y, nil, self.switch, 2, 16)
end
function Player:move(dt)
local onMove;
if love.keyboard.isScancodeDown("a") then
self.x = self.x - self.speed * dt
self.switch = -2
onMove = true
elseif love.keyboard.isScancodeDown("d") then
self.x = self.x + self.speed * dt
self.switch = 2
onMove = true
end
if not self.on_anim then
if onMove then
self:setState((self.crouch) and "hatWalk" or "run")
else
self:setState((self.crouch) and "hat" or "idle")
end
end
end
function Player:jump(dt)
if self.crouch == false then
if love.keyboard.isScancodeDown("w") then
if self.yVel == 0 then -- Start jump action
self.yVel = self.jump_height
self:setState("jump")
self.on_anim = true -- To prevent the animation from changing in `Player:move`
end
end
if self.yVel ~= 0 then -- Perform the jumping movement
self.y = self.y + self.yVel * dt
self.yVel = self.yVel - self.gravity * dt
if self.yVel > 0 then self:setState("fall") end
end
if self.y > self.ground then -- Check if you touch the ground
self:setState("idle")
self.on_anim = false -- Animation can change again in `Player:move`
self.y = self.ground
self.yVel = 0
end
end
end
So I advise you to understand how it works and write your own mechanic afterwards, you will need it anyway if you will use Windfield in the end.
If I ever answered wrong or something is still unclear for you, don't hesitate to ask.
- Attachments
-
- TestGame-corrected-2.love
- (216.18 KiB) Downloaded 54 times
Re: How do I update my crouch animation? (anim8)
Bigfoot71 wrote: ↑Wed Mar 22, 2023 11:40 amSince I don't have your modifications I can't understand either why after modifying `Player:jump` the player does not stand up anymore... But don't panic!
I gave you an example of what the Player: jump method could look like, it could be optimized but hey, given the little it does for now, it's still very suitable. Here's the full script because I also made a few other changes, like PGimeno's suggestion, which will save you from handling state transitions in conditions in `Player:update` (I also added isScancodeDown instead of isDown, because not easy with an AZERTY keyboard):Note: I remind you that the `Player:setState` method is only launched if the state given as a parameter is not the current state, it is practical because you do not have to handled the fact whether it should be called or not in the rest of the code. However if the project becomes more substantial it will still be better to manage the condition before the call, because a call remains a little expensive. Well you're not at this stage yet, it's just to say that it's practical but you don't have to get used to itCode: Select all
Player = {} function Player:load() self.x = love.graphics.getWidth() / 2 self.y = love.graphics.getHeight() / 2 - 62 self.spriteSheet = love.graphics.newImage("Sprites/TheWizzl.png") self.speed = 400 self.ground = self.y self.yVel = 0 self.jump_height = -300 self.gravity = -500 -- Animation Information local grid = anim8.newGrid( -- No need to store this function in the table 32,32, self.spriteSheet:getWidth(), self.spriteSheet:getHeight() ) self.anim = {} self.anim.idle = anim8.newAnimation(grid('1-4', 1), 0.2) self.anim.hat = anim8.newAnimation(grid(28, 1), 0.1) self.anim.run = anim8.newAnimation(grid('8-11', 1), 0.1) self.anim.hatWalk = anim8.newAnimation(grid('29-33', 1), 0.1) self.anim.jump = anim8.newAnimation(grid(19, 1), 0.2) self.anim.fall = anim8.newAnimation(grid(20, 1), 0.2) self.anim.hide = anim8.newAnimation(grid('22-27', 1), 0.1, function () self:setState("hat") -- Applies the "hat" state at the end of the animation self.on_anim = false end) self.anim.getUp = anim8.newAnimation(grid('35-38', 1), 0.1, function () self:setState("idle") -- Applies the "idle" state at the end of the animation self.on_anim = false end) self:setState("idle") self.on_anim = false -- This variable will be used to not launch a walk animation while another is in progress (jump, fall, hide, getUp) self.crouch = false self.switch = 2 end function Player:setState(state) if state ~= self.state then self.anim_curr = self.anim[state] self.anim_curr:gotoFrame(1) self.prev_state = self.state self.state = state end end function Player:update(dt) if love.keyboard.isScancodeDown("s") then if not self.crouch and self.y == self.ground then -- To avoid squatting in the air self:setState("hide") self.on_anim = true self.crouch = true end end if love.keyboard.isScancodeDown("space") then if self.crouch then self:setState("getUp") self.on_anim = true self.crouch = false end end if love.keyboard.isScancodeDown("escape") then love.event.quit() end -- Movement and anim update -- Player:move(dt) Player:jump(dt) self.anim_curr:update(dt) end function Player:draw() self.anim_curr:draw(self.spriteSheet, self.x, self.y, nil, self.switch, 2, 16) end function Player:move(dt) local onMove; if love.keyboard.isScancodeDown("a") then self.x = self.x - self.speed * dt self.switch = -2 onMove = true elseif love.keyboard.isScancodeDown("d") then self.x = self.x + self.speed * dt self.switch = 2 onMove = true end if not self.on_anim then if onMove then self:setState((self.crouch) and "hatWalk" or "run") else self:setState((self.crouch) and "hat" or "idle") end end end function Player:jump(dt) if self.crouch == false then if love.keyboard.isScancodeDown("w") then if self.yVel == 0 then -- Start jump action self.yVel = self.jump_height self:setState("jump") self.on_anim = true -- To prevent the animation from changing in `Player:move` end end if self.yVel ~= 0 then -- Perform the jumping movement self.y = self.y + self.yVel * dt self.yVel = self.yVel - self.gravity * dt if self.yVel > 0 then self:setState("fall") end end if self.y > self.ground then -- Check if you touch the ground self:setState("idle") self.on_anim = false -- Animation can change again in `Player:move` self.y = self.ground self.yVel = 0 end end end
So I advise you to understand how it works and write your own mechanic afterwards, you will need it anyway if you will use Windfield in the end.
If I ever answered wrong or something is still unclear for you, don't hesitate to ask.
Thanks! I was mostly just confused about how states work. I am not very experiences with coding in Lua and I've only made one game with Love2D so I apologize if my code seemed a bit amateurish. I'll try my best to tinker around to make it my own since it feels weird using someone else's code lol. But thanks for all the help.
Who is online
Users browsing this forum: No registered users and 2 guests