This is the testing Godot forums! All forum posts unique to this forum will be deleted! Please use the main forums here for any posts you want to keep. All forum rules still apply.

new dude need help to move on

Hello everyone
I started a small 2d game project and as I am good in graphics I made every thing by my self
but I faced some problems I didn't know how to fix it
so if there is any one can tell me what I have to do it will be very helpful

I have a small Hamster as a character it can move and jump perfectly and I attached animation sprites for walking , jumping and fulling as well .
the problem is when I jump or fall it should play the animation sprite
but it doesn't work and it shows one image only !!

you can check it here

can you guys tell me what wrong ?

Comments

  • TwistedTwiglegTwistedTwigleg Posts: 2,561Admin

    Hmm, hard to say for sure. Watching the video, it looks like the fall animation gets stuck with the character's hands up in the air. Based on what you wrote, I'm guessing this is the first frame of the Fall animation. In the code posted, I do not necessarily see anything that looks out of place.

    Have you tried playing the fall animation by itself, just to ensure the animation is setup correctly? While I doubt this is the case, maybe the fall animation is setup with only a single frame? I would try debugging and verifying that the fall animation is properly setup, just to make sure.

    The other issue that might be causing the problem is that the fall animation is being called without checking to see if the fall animation is already playing. Perhaps the play function is constantly resetting the animation, so the animation cannot get beyond the first fame.
    If this is the issue, then the fix is relatively simple. All you need to do is check whether the animation playing is the animation you want to change to. I generally make a helper function to make this process a little easier. Something like this should work, though I have not tested the code:

    func change_animation(animation_name):
        if $Sprite.animation == animation_name:
            return
        else:
            $Sprite.play(animation_name)
    

    Then you can replace $Sprite.play("Fall") with change_animation("Fall"), and the animation should play normally, if the animation being reset was causing the issue. Also, before making changes, backup your project so you do not loose any progress if something doesn't work!

    Outside of that, I'm not totally sure. I have not really done a lot of 2D Godot work and I've only briefly touched on nodes like the AnimatedSprite node, so it is quite possible I'm missing something.
    (Side note: Welcome to the forums)

  • animax940animax940 Posts: 6Member

    Thank you so much " TwistedTwigleg" for the very fast reply
    I tried your options on my script but unfortunately it doesn't work :(
    or maybe I post your code in wrong place I'm not sure though there was no warning

    the "Jump" and "Fall" animations has more than one frame I didn't mess that
    look at this video
    and if you want me to send more information please let me know cos I would like to avoid this problem in the future and learn next tutorial .
    also I need a solution to make the character's collision shape change with the character state "Idle" and "Run"

  • TwistedTwiglegTwistedTwigleg Posts: 2,561Admin

    Hmm, hard to say for sure. Could you post the entire character script? I do not know if I'll be able to figure it out, but maybe looking at the entire script will help.

    Another thing you can try is adding something like print($Sprite.animation) and look at the console to see what is going on. I don't know if it will yield anything, but it might help narrow down what is causing the animation not to play.


    For making the collision shape change, I think the easiest way would be to use an AnimationPlayer node instead of a AnimatedSprite node. That way you could enable/disable collision shapes based on the animation playing directly within the animation itself.
    Another way is you could enable/disable the collision shapes through code, you would just need to do something like the following pseudo GDScript code:

    var current_collision_shape
    func _ready():
        # Disable all of the collision shapes initially.
        current_collision_shape = $CollisionShape_Idle.disabled = true
        current_collision_shape = $CollisionShape_Jump.disabled = true
        current_collision_shape = $CollisionShape_Duck.disabled = true
        # Enable the initial/starting collision shape
        current_collision_shape = $CollisionShape_Idle
        current_collision_shape.disabled = false
    
    func change_animation(animation_name):
        if $Sprite.animation == animation_name:
            return
        else:
            $Sprite.play(animation_name)
            change_collision_shape(animation_name)
    
    # Have it's initial value the same as the initial animation.
    var current_collision_shape = $CollisionShape_Idle
    func change_collision_shape(animation_name):
        # Disable the current collision shape
        current_collision_shape.disabled = true
        # set current_collision_shape to the correct collision shape based on
        # the name of the animation.
        if animation_name == "Jump":
            current_collision_shape = $CollisionShape_Jump
        elif animation_name == "Duck":
            current_collision_shape = $CollisionShape_Duck
        else
            current_collision_shape = $CollisionShape_Idle
        # Enable the new collision shape
        current_collision_shape.disabled = false
    

    I have not tested the code, but that's probably how I would initially try to enable/disable collision shapes if it was my project. I'd probably write a simple animation state-machine that would handling enabling/disabling the collision shape(s) when the state changes, but that is a tad more complex and unnecessary depending on the needs of your project.

    (Moving this project from the Forum Chat category to the Programming category, as its contents fit a little bit better there)

  • animax940animax940 Posts: 6Member
    edited September 2019

    **ok I will try that and actually this project is just for learning Godot nothing more to make my own game later
    so I'm open for any suggestion that will solve my problems to move on

    I had watch a tutorial about how game machine state is works but yeah it was complicated as I'm still new in programming

    here is the entire script I used in this project**

    extends KinematicBody2D
    
    const Gravity = 40
    const ACCELERATION = 1000
    const MAX_SPEED = 600
    const JUMP_HEIGHT = -1000
    const UP = Vector2 ( 0 , -1 )
    var motion = Vector2()
    
    func _physics_process(delta):
        var friction = false
    
        motion.y += Gravity
    
        if Input.is_action_pressed("ui_right"):
            motion.x = min(motion.x+ACCELERATION , MAX_SPEED)
            $Sprite.flip_h = false
            $Sprite.play("Run")
        elif Input.is_action_pressed("ui_left"):
            motion.x = max(motion.x-ACCELERATION , -MAX_SPEED)
            $Sprite.flip_h = true
            $Sprite.play("Run")
        else:
            $Sprite.play("Idle")
            friction = true
    
        if is_on_floor():
            if Input.is_action_just_pressed("ui_up"):
                motion.y = JUMP_HEIGHT
            if friction == true:
                motion.x = lerp(motion.x , 0 , 0.2)
        else:
            if motion.y < 0 :
                $Sprite.play("Jump")
            else:
                $Sprite.play("Fall")
            if friction == true:
                motion.x = lerp(motion.x , 0 , 0.009)
    
        motion = move_and_slide(motion , UP)
        pass
    
  • TwistedTwiglegTwistedTwigleg Posts: 2,561Admin

    Looking at the code, I think I see the problem. It looks like the issue is that the Run or Idle animations are playing and overriding the Fall animation, which causes the Fall animation to be stuck on the first frame as it constantly changes back and fourth between Fall and Run/Idle.

    I have not tested, but I think the following should fix the issue:

    extends KinematicBody2D
    
    const Gravity = 40
    const ACCELERATION = 1000
    const MAX_SPEED = 600
    const JUMP_HEIGHT = -1000
    const UP = Vector2 ( 0 , -1 )
    var motion = Vector2()
    var input_vector = Vector2()
    
    func _physics_process(delta):
        var friction = false
    
        motion.y += Gravity
    
        input_vector = Vector2.ZERO
        if Input.is_action_pressed("ui_right"):
            motion.x = min(motion.x+ACCELERATION , MAX_SPEED)
            $Sprite.flip_h = false
            input_vector.x = 1
        elif Input.is_action_pressed("ui_left"):
            motion.x = max(motion.x-ACCELERATION , -MAX_SPEED)
            $Sprite.flip_h = true
            input_vector.x = -1
        else:
            friction = true
    
        if is_on_floor():
            if Input.is_action_just_pressed("ui_up"):
                motion.y = JUMP_HEIGHT
                input_vector.y = 1
            if friction == true:
                motion.x = lerp(motion.x , 0 , 0.2)
        else:
            if friction == true:
                motion.x = lerp(motion.x , 0 , 0.009)
    
        motion = move_and_slide(motion , UP)
    
        _process_animation()
    
    
    func _process_animation():
        if is_on_floor():
            # Play the jump animation if jump was just pressed
            if input_vector.y > 0.75:
                $Sprite.play("Jump")
            # Run when on the floor and the input is over 0.75 in either direction:
            elif input_vector.x < -0.75 or input_vector.x > 0.75:
                $Sprite.play("Run")
            else:
                $Sprite.play("Idle")
        else:
            # Play the jump animation if the character is moving up
            if motion.y < 0
                $Sprite.play("Jump")
            elif motion.y > 0
                $Sprite.play("Fall")
    

    The biggest change is that the code for the animations is now a separate function, and it uses a new variable called input_vector to help tell which animation should be playing. Using a separate variable allows for having the input still move the player while in the air, but it shouldn't effect the animation, as the _process_animation function checks if the player is in the air or not.

    I have not tested the code, but I think that should, hopefully, fix the issue. :smile:

  • animax940animax940 Posts: 6Member

    Thank you so much :)
    it works now very well you are amazing bro ^^
    I'm glad I came here and I wish to be like you one day
    but until then I will need more help in the future :(

    about the collide shape while sliding I think it must change to different shape
    the method you made I didn't know how to add it in the script

    also can I add another animation sprite while jumping for example attack in the air and how ?
    thanks again ^^

  • TwistedTwiglegTwistedTwigleg Posts: 2,561Admin

    @animax940 said:
    Thank you so much :)
    it works now very well you are amazing bro ^^
    I'm glad I came here and I wish to be like you one day
    but until then I will need more help in the future :frown:

    Awesome! I'm glad the code works.

    As for being like me, I am honored. I've been programming and doing game development for years, and I can safely say that all my experience has come from lots of learning, experimenting, and receiving help from others.

    There is nothing wrong with needing help! You cannot know what you don't know. Helping others is part of what the community here is for. I still need help and struggle too, I just generally don't post about it online and instead ask friends for ideas/help.


    As far as the collision shape changing, to be honest I'm not sure what the best method would be. The example I gave basically just turns CollisionShape nodes on/off based on the animation used. To integrate it into the main script, you just need to slightly change the _process_animation function:

    func _process_animation():
        if is_on_floor():
            # Play the jump animation if jump was just pressed
            if input_vector.y > 0.75:
                $Sprite.play("Jump")
            # Run when on the floor and the input is over 0.75 in either direction:
            elif input_vector.x < -0.75 or input_vector.x > 0.75:
                $Sprite.play("Run")
            else:
                $Sprite.play("Idle")
        else:
            # Play the jump animation if the character is moving up
            if motion.y < 0
                $Sprite.play("Jump")
            elif motion.y > 0
                $Sprite.play("Fall")
    
        # (Potentially) change the collision shape
        _process_animation_collision_shape()
    
    # Some class variables we'll need. We'll assume the default/initial collision shape
    # node is named "CollisionShape_Standing"
    var current_collision_shape = $CollisionShape_Standing
    # Note: for this to work, all of the other collision shapes except
    # "CollisionShape_Standing" will need to be disabled initially in the player scene.
    
    func _process_animation_collision_shape():
        # If the jump/fall animation is playing...
        if $Sprite.animation == "Jump" or $Sprite.animation == "Fall":
            # Enable the CollisionShape node for jumping/falling.
            current_collision_shape.disabled = true
            current_collision_shape = $CollisionShape_InAir
            current_collision_shape.disabled = false
        # If the slide animation is playing...
        elif $Sprite.animation == "Slide":
            # Enable the CollisionShape node for sliding.
            current_collision_shape.disabled = true
            current_collision_shape = $CollisionShape_Sliding
            current_collision_shape.disabled = false
        # If the current animation does not have a specific collision shape, then use
        # the default/initial collision shape
        else:
            current_collision_shape.disabled = true
            current_collision_shape = $CollisionShape_Standing
            current_collision_shape.disabled = false
    

    Or something like that. It primarily requires that you know the names of the CollisionShape nodes to use for the player states, and that all of the CollisionShape nodes but the initial CollisionShape have the disabled property set to true.

    Though as I said, I do not know what the best method/solution would be.


    As for adding additional animations, like animations that play when the character attacks, it really depends on how the rest of the code for attacking works. If you are using a boolean to track whether the player is attacking, then you just need to check if the attack boolean is true as the first if statement in the conditionals within the air. For example:

    func _process_animation():
        if is_on_floor():
            # Play the jump animation if jump was just pressed
            if input_vector.y > 0.75:
                $Sprite.play("Jump")
            # Run when on the floor and the input is over 0.75 in either direction:
            elif input_vector.x < -0.75 or input_vector.x > 0.75:
                $Sprite.play("Run")
            else:
                $Sprite.play("Idle")
        else:
            # Play the attack animation is the player is attacking in the air
            if is_attacking == true:
                $Sprite.play("InAir_Attack")
            # Play the jump animation if the character is moving up
            elif motion.y < 0
                $Sprite.play("Jump")
            elif motion.y > 0
                $Sprite.play("Fall")
    

    Though as I said, it really depends. You'll probably need to experiment and see what works best for you based on how your attacking system works, how the animation works, and the complexity of the code.

    Hopefully this helps!

  • animax940animax940 Posts: 6Member

    Thank you so much
    I will try them in the next days
    where I can find your games that you made ? :)

  • TwistedTwiglegTwistedTwigleg Posts: 2,561Admin

    You can find most of the games I've made on my Itch.IO page. Most of them are games I've made for various game jams.

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.