Page 1 of 2

[SOLVED] Have some troubles with Animation again

Posted: Tue Apr 30, 2024 10:58 am
by Todespreis
Hey there! I'm trying to implement an animation function, but it does'nt work well. Here is the code:

Code: Select all

local player
local walkingDownAnimation
local walkingLeftAnimation
local walkingRightAnimation
local walkingUpAnimation
local tilemap
local num_tiles
local tiles

function love.load()
    FramesWalkingDown =    {
       love.graphics.newImage("/Character_Sprites/going_down_01.png"),
       love.graphics.newImage("/Character_Sprites/going_down_02.png"),
       love.graphics.newImage("/Character_Sprites/going_down_03.png"),
       love.graphics.newImage("/Character_Sprites/going_down_04.png"),
       love.graphics.newImage("/Character_Sprites/going_down_05.png"),
       love.graphics.newImage("/Character_Sprites/going_down_06.png")
    }
    FramesWalkingUp = {
       love.graphics.newImage("/Character_Sprites/going_up01.png"),
       love.graphics.newImage("/Character_Sprites/going_up02.png"),
       love.graphics.newImage("/Character_Sprites/going_up03.png"),
       love.graphics.newImage("/Character_Sprites/going_up04.png"),
       love.graphics.newImage("/Character_Sprites/going_up05.png"),
       love.graphics.newImage("/Character_Sprites/going_up06.png")
    }
    FramesWalkingRight = {
      love.graphics.newImage("/Character_Sprites/going_right01.png"),
      love.graphics.newImage("/Character_Sprites/going_right02.png"),
      love.graphics.newImage("/Character_Sprites/going_right03.png"),
      love.graphics.newImage("/Character_Sprites/going_right04.png"),
      love.graphics.newImage("/Character_Sprites/going_right05.png"),
      love.graphics.newImage("/Character_Sprites/going_right06.png")
    }
    FramesWalkingLeft = {
      love.graphics.newImage("/Character_Sprites/going_left01.png"),
      love.graphics.newImage("/Character_Sprites/going_left02.png"),
      love.graphics.newImage("/Character_Sprites/going_left03.png"),
      love.graphics.newImage("/Character_Sprites/going_left04.png"),
      love.graphics.newImage("/Character_Sprites/going_left05.png"),
      love.graphics.newImage("/Character_Sprites/going_left06.png")
    }

    walkingDownAnimation = createAnimation(0.1, FramesWalkingDown)
    walkingUpAnimation = createAnimation(0.1, FramesWalkingUp)
    walkingRightAnimation = createAnimation(0.1, FramesWalkingRight)
    walkingLeftAnimation = createAnimation(0.1, FramesWalkingLeft)

    tilemap = {
        {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16},
        {16, 16, 16, 16, 16, 16, 11, 12, 13, 12, 13, 12, 13, 12, 13, 15},
        {16, 16, 16, 16, 16, 16, 21, 22, 23, 22, 23, 22, 23, 22, 23, 25},
        {16, 16, 16, 16, 16, 16, 31, 33, 32, 33, 32, 33, 32, 33, 32, 35},
        {16, 16, 16, 16, 16, 16, 31, 33, 32, 33, 32, 33, 32, 33, 32, 35},
        {16, 16, 16, 16, 16, 16, 31, 33, 32, 33, 32, 33, 32, 33, 32, 35},
        {16, 16, 16, 16, 16, 16, 31, 33, 32, 33, 32, 33, 32, 33, 32, 35},
        {11, 12, 13, 12, 13, 12, 25, 33, 32, 33, 32, 33, 32, 33, 32, 35},
        {21, 22, 23, 22, 23, 22, 25, 33, 32, 33, 32, 33, 32, 33, 32, 35},
        {31, 32, 33, 32, 33, 32, 33, 32, 33, 32, 32, 33, 32, 32, 33, 35},
        {31, 32, 33, 32, 33, 32, 33, 32, 33, 32, 32, 33, 32, 32, 33, 35},
        {31, 32, 33, 32, 33, 32, 33, 32, 33, 32, 32, 33, 32, 32, 33, 35},
        {51, 52, 53, 52, 53, 15, 32, 33, 32, 33, 32, 33, 11, 52, 53, 55},
        {16, 16, 16, 16, 16, 31, 32, 33, 32, 33, 32, 33, 35, 16, 16, 16},
        {16, 16, 16, 16, 16, 31, 32, 33, 32, 33, 32, 33, 35, 16, 16, 16},
        {16, 16, 16, 16, 16, 51, 52, 53, 54, 52, 53, 54, 55, 16, 16, 16}
    }

    num_tiles = 60

    tiles = {}

    for i = 1, #tilemap do
        local row = tilemap[i]
        for j = 1, #row do
            local tile = row[j]
            if tiles[tile] == nil then
                tiles[tile] = love.graphics.newImage("/DungeonTiles01/" .. string.format("%02d", tile) .. ".png")
            end
        end
    end

    player = {}
    width = 16
    height = 16
    player.x = 70
    player.y = 70
    player.image = love.graphics.newImage("/Character_Sprites/standing_down.png" )
end

function resetAnimation(animation)
    animation.timer = 0.0
    animation.index = 1
end

function advanceAnimation(animation, dt)
    animation.timer = animation.timer + dt
    if animation.timer > animation.duration then
        animation.timer = 0
        animation.index = animation.index + 1
        if animation.index > animation.lastIndex then
            animation.index = 1
        end
    end
end

function createAnimation(frameDuration, frames)
    local animation = {timer = 0.0, index = 1, duration = frameDuration, frames = frames, lastIndex = #frames}
    return animation
end

local dt = love.timer.getDelta()
local Down = {}

function love.joystickpressed(joystick, button)
    Down[button] = true
end

function love.joystickreleased(joystick, button)
    Down[button] = nil
end

function getAnimationFrame(animation)
    return animation.frames[animation.lastIndex]
end



function love.update(dt)
    if Down[6] then 
        player.x = player.x + 4
        player.currentAnimation = walkingRightAnimation
    end
    if Down[4] then 
        player.y = player.y + 4
        player.currentAnimation = walkingDownAnimation
    end
    if Down[2] then 
        player.x = player.x - 4
        player.currentAnimation = walkingLeftAnimation
    end
    if Down[1] then 
        player.y = player.y - 4
        player.currentAnimation = walkingUpAnimation
    end
end

function love.draw()
    for i = 1, #tilemap do
        local row = tilemap[i]
        for j = 1, #row do
            local tile = row[j]
            if tiles[tile] then
                love.graphics.draw(tiles[tile], (j - 1) * width, (i - 1) * height)
            end
        end
    end

    love.graphics.draw(getAnimationFrame(player.currentAnimation), player.x, player.y)
end
I'm getting an error, that lua can't index the animation function. I think, the problem is in the getAnimationFrame function. I'm not sure, what to write there, because index and lastIndex are wrong or not indexable..???

Re: Have some troubles with Animation again

Posted: Tue Apr 30, 2024 11:42 am
by knorke
Hi
it is hard to help without seeing the full error message.
Also that code uses several png-files that it is best to include a full .love with all required files.
Otherwise it is too cumbersome to run the code which makes it harder to find the error.

Re: Have some troubles with Animation again

Posted: Tue Apr 30, 2024 11:50 am
by Todespreis
@knorke oh, sorry, sure. And what a cool name! XD I'm from Germany, too btw ^^

Re: Have some troubles with Animation again

Posted: Tue Apr 30, 2024 2:04 pm
by Roland Chastain
Hello!

player.currentAnimation should be defined in love.load(), and not only in love.update():

Code: Select all

function love.load()
    -- [...]

    player = {}
    player.currentAnimation = walkingRightAnimation

Re: Have some troubles with Animation again

Posted: Tue Apr 30, 2024 4:58 pm
by Todespreis
Hey! Thank you for the reply. I did, what you said, but i get now an error in love.load.

Re: Have some troubles with Animation again

Posted: Wed May 01, 2024 12:46 am
by RNavega
What you have in there is different than what they said though:

Code: Select all

player.currentAnimation = {walkingDownAnimation, walkingUpAnimation, walkingRightAnimation, walkingLeftAnimation}
You're making a table of tables. But 'player.currentAnimation' should be a reference to a single of those animation tables like in Knorke's.
So when getAnimationFrame() gets called, it samples a frame from the table pointed by 'player.currentAnimation'.

Also, your getAnimationFrame() function is different than in your original thread, see below:

Code: Select all

function getAnimationFrame(animation)
    return animation.frames[animation.lastIndex]
end
In there, you're always sampling 'lastIndex', the index to the the last frame of the animation (which doesn't change, it's just a reference to know when the animation must cycle back to the first frame). It should be 'animation.index' instead, the index of the current frame of animation that evolves with time.

Re: Have some troubles with Animation again

Posted: Thu May 02, 2024 5:44 pm
by Todespreis
Thank you @RNavega for responding. I did so, but now i get the error: main.lua line 45: attempt to index upvalue 'player' (a nil value). I don't get it, why. :(

Re: Have some troubles with Animation again

Posted: Thu May 02, 2024 9:48 pm
by RNavega
You're making some elementary mistakes. This is usually the sign of "biting more than you can chew" (trying to do something above your current experience level). Ideally you want to enter Flow, where the challenge is very close to your skills, otherwise, if it's too hard you'll suffer from the difficulty, and if it's too easy you'll get bored.

My recommendation is to take a step back, pause on this project, then work on things based on tutorials instead. The Sheepolution e-book for example: https://sheepolution.com/learn/book/contents

Re: Have some troubles with Animation again

Posted: Mon May 06, 2024 8:47 pm
by Todespreis
I don't get it - i changed the order of the functions and now it's working, but it only shows the first frame of the animation - so the index does'nt increase. Why? Is it because the function "currentAnimation" does not return anything back?

Code: Select all

function currentAnimation(animation, dt)
    animation.timer = animation.timer + dt
    if animation.timer >= animation.duration then
        animation.index = animation.index + 1        
        animation.timer = 0.0
        if animation.index >= animation.lastIndex then
            animation.index = 1
        end
        
    end
end

Re: Have some troubles with Animation again

Posted: Mon May 06, 2024 10:45 pm
by knorke
First something unrelated, what is up with your conf.lua?
It contains this: t.version = 60
My Löve refuses to run your game because it is made "for version 60."
That lines defines the Löve version, also it should be a string. So something like "11.5"
I simply renamed the file so that it does not get used.
---

Anyway, I tried to fix it and added some comments.
I added four lines in love.update for keyboard controls with arrows keys because I did not have a joystick attached.
It overwrites the joystick so maybe remove these lines.

Here is how I approached it:

Step 1
When there is a function that should do something but it does nothing then it is always good to check:
Does the function even get called?
Here currentAnimation() did not get called anywhere. So it can not do anything.
There are two ways to notice that:
1) Search (ctrl+f) your code for calls to currentAnimation() - There are none.
2) Add a print (" currentAnimation() says hello") as first line in the function.
If somethings gets printed to console then you know the function was called.
(Sometimes a call to the function exists but it gets never executed because some if-condition is never true or similar problem)

You do have this line:
love.graphics.draw(getAnimationFrame(player.currentAnimation), player.x, player.y)
But here currentAnimation is not the function. It is an image, as returned by getAnimationFrame.
Maybe that confused you?

Step 2
I did not have a joystick attached so I added:

Code: Select all

function love.update(dt)
Down[6] = true --test
Basically always hold down the walk-right button.
For now, I only wanted to test the walk-right animation.

Step 3
I was not sure if your player.currentAnimation property works.
That is why I limited to testing the walk-right ani.
I added this line to love.update:
currentAnimation(walkingRightAnimation, dt)

That worked.

Step 4
Full keyboard controls:

Code: Select all

    Down[6]=love.keyboard.isDown("right")
	Down[4]=love.keyboard.isDown("down")
	Down[2]=love.keyboard.isDown("left")
	Down[0]=love.keyboard.isDown("up")
Step 5:
updating the actual animation inside of always using walk-right:
currentAnimation(player.currentAnimation, dt)
This gave an error:
attempt to index local 'animation' (a nil value)
in function 'currentAnimation'
Step 6:
To get rid of the error, I added a lazy check:
If the animation is nil/not defined/empty then the function simply returns.

Code: Select all

function currentAnimation(animation, dt)
	if not animation then return end
Now it worked and animated.

Step 7:
Why was the check needed?
In love.load you have:

Code: Select all

    player.currentAnimation = walkingDownAnimation
So the player should start with walkingDownAnimation.
But at this point walkingDownAnimation is not defined yet. It is stil set to nil / nothing.
Only in the next line do you have

Code: Select all

    walkingDownAnimation = createAnimation(0.6, FramesWalkingDown)
So player.currentAnimation = ... should be after those createAnimation lines.
When love.update() runs for the first time, player.currentAnimation is set there.
So maybe it would actually be better to call currentAnimation(player.currentAnimation, dt) after those joystick-input-checks.
But now there is the check, so it works either way. Having such check is sometimes a good idea anyway.


Naming is also important and helps avoid/find errors:
What does the function currentAnimation(animation, dt) do?
It advances the index of an animation to the next index.
That animation does not have to be the 'current' animation - it can be any animation that gets passed as argument.
So remove 'current' from name. (I missed that in comments)
Instead add 'update' to name. So you get something like: updateAnimation(animation, dt)

Also:
You move the player 4 pixels every update() frame.
However the faster a computer is, the more often update() gets called in a given time.
Meaning on fast CPUs the player walks faster.
The fix is to use the dt argument of love.update(dt)
See https://love2d.org/wiki/dt

good luck ;)