• Godot HelpProgramming
  • How can I alternate between animations during user Input with a Animated Sprite3D node?[ANSWERED]

@KindosaurGaming said:

@Megalomaniak said: Might it be you have 2D and 3D nodes mixed in your hierarchy?

My hierarchy of the nodes is as follows: Spatial Node (named World) -> MeshInstance (used for a plane to walk on: Not Important) (Extra Nodes inside) -> Sprite3D (ment for a different character: Not Important) (Also has extra nodes inside) -> KinematicBody (the player) - - -> CollisionShape - - -> AnimatedSprite3D - - - - - -> Spatial Node (named Head) - - - - - -> Camera

I have also used the copy paste funtion of the Node route so I am not really sure :/

Either you made a mistake in typing it out(which I'm guessing is the case) or the camera isn't parented to the spatial named Head. If latter it might be you at some point accidentally moved it in the hierarchy and it got re-parented. But as I said it's probably the former and seems like @TwistedTwigleg already offered some answers.

Ok I am really sorry for making it confusing :'(

But yeah I just want it to happen like so: The character can move everywhere so you can use the walking forward(Backward, Left , Right and even the diagonals) can be applied on all coördinates in the field like how 3D-bodied characters do it (I have a 2D sprite with animations that need to do that trick)

The characters axis and the worlds axis are seperate from eachother, so this means that the character can move on it's own (with user input of course), but he isn't constrained on what the X and Z axis are for his world.

cuz what your code on October 17th was kinda working . I walked forward turned my camera all the way to the right and walked forward without a problem =), But then the backward and Left crashed my game. And with the new code you sent me it is completly stuck in one spot not able to move.

is that the character won't walk at all (animation do play and still do the toggle between states) and is now stuck on the location I have placed him on (weirdly enough :# )

Or A the controls don't do it anymore or B the whole plateau (my world) is moving together with my character. So my character does change position, but I can't see it because his feet are stuck to the plateau the moves in the same direction with the same speed.

So in short: The character moves with its local axis (so it's own axis, not the ones of the whole world :) )

Again I am really sorry if I am very unclear, I might make drawings of what I wan.t If this is still a bit fuzzy :/

Which node is your script attached to again? Seems odd that the world would be transformed alongside the character.

@Megalomaniak said: Which node is your script attached to again? Seems odd that the world would be transformed alongside the character.

It is on my AnimatedSprite3D node

Yeah, strange then indeed, I can't think of a reason why the world would be transformed along at all.

@KindosaurGaming said: Ok I am really sorry for making it confusing :'(

But yeah I just want it to happen like so: The character can move everywhere so you can use the walking forward(Backward, Left , Right and even the diagonals) can be applied on all coördinates in the field like how 3D-bodied characters do it (I have a 2D sprite with animations that need to do that trick)

The characters axis and the worlds axis are seperate from eachother, so this means that the character can move on it's own (with user input of course), but he isn't constrained on what the X and Z axis are for his world.

cuz what your code on October 17th was kinda working . I walked forward turned my camera all the way to the right and walked forward without a problem =), But then the backward and Left crashed my game. And with the new code you sent me it is completly stuck in one spot not able to move.

I think I see now, though it is strange that the new code is making the character stuck. I tried the code in a test project and it seemed to be working okay.

Can you post the code you have in your _process function? Maybe something with the formatting is off or something. The code crashing on the 17th makes sense, because there was a small typo, but the most recent code just amends that small typo, it shouldn't really change much of anything.

is that the character won't walk at all (animation do play and still do the toggle between states) and is now stuck on the location I have placed him on (weirdly enough :# )

Or A the controls don't do it anymore or B the whole plateau (my world) is moving together with my character. So my character does change position, but I can't see it because his feet are stuck to the plateau the moves in the same direction with the same speed.

So in short: The character moves with its local axis (so it's own axis, not the ones of the whole world :) )

I think the issue is likely something with the code is messing up the movement, though I suppose the world could be moving with the player depending on how the scene is setup.

The MeshInstance node, which I am assuming is the plateau, isn't parented to the AnimatedSprite3D in the scene layout you posted above, so it shouldn't be moving. My hunch is that the formatting of the code is slightly off or something, as the code on the 17th and the most recent code should be almost exactly the same, with lines 22 and 31 being the only difference (velocity.x -> velocity and velocity.z -> velocity)

Again I am really sorry if I am very unclear, I might make drawings of what I wan.t If this is still a bit fuzzy :/

No worries, it is all good! That said, if you want to make drawings, that might help clarify some things, but after reading the post I think I know what type of movement yo uare looking for.

I thought it might be more handy to upload the full code of the AnimatedSprite3D

extends AnimatedSprite3D

var moving_anim_name = "Walking";
var idle_anim_name = "Idle";
var velocity = Vector3(0,0,0);
var move_speed = 20;

var input_vector = Vector3.ZERO;
var last_directional_input = Vector3.ZERO;

var view_camera;

var camera_angle = 0
var mouse_sensitivity = 0.3

var motion = Vector3()
var gravity = -9.8



func _ready():
	play("Idle_F")
	view_camera = get_node("Head/Camera")

func _physics_process(delta):
	motion.y += gravity
	var aim = $Head/Camera.get_global_transform().basis

func _process(delta):
	
	var view_camera_right = view_camera.global_transform.basis.x;
	var view_camera_forward = -view_camera.global_transform.basis.z;

	view_camera_right.y = 0
	view_camera_forward.y = 0;
	view_camera_right = view_camera_right.normalized();
	view_camera_forward = view_camera_forward.normalized();

	velocity = Vector3.ZERO;

	if (Input.is_action_pressed("Walk_Right")):
		    velocity += view_camera_right * move_speed;
		    input_vector.x = 1
	elif (Input.is_action_pressed("Walk_Left")):
		    velocity -= view_camera_right * move_speed;
		    input_vector.x = -1
	else:
		    input_vector.x = 0
	if (Input.is_action_pressed("Walk_Forward")):
		    velocity += view_camera_forward * move_speed;
		    input_vector.z = -1
	elif (Input.is_action_pressed("Walk_Backward")):
		    velocity -= view_camera_forward * move_speed;
		    input_vector.z = 1
	else:
		    input_vector.z = 0

    # If the input_vector is NOT zero, then we want to store the direction
    # for the idle animation.
	if (input_vector != Vector3.ZERO):
        last_directional_input  = input_vector
    # last_directional_input should always contain the direction the player
    # is moving towards if the player is moving, or the last direction the player
    # moved towards if the player is no longer moving.
    # Now we can replace input_vector with last_directional_input for
    # animations.

	var h_vel = velocity;
	h_vel.y = 0;
    # Walking animations below:
	if (h_vel.length() > 0):
		if (last_directional_input .z <= -1):
            if (last_directional_input .x <= -1):
                _change_sprite_animation("Walking_FL")
            elif (last_directional_input .x >= 1):
                _change_sprite_animation("Walking_FR")
            else:
                _change_sprite_animation("Walking_F")
		elif (last_directional_input .z >= 1):
            if (last_directional_input .x <= -1):
                _change_sprite_animation("Walking_BL")
            elif (last_directional_input .x >= 1):
                _change_sprite_animation("Walking_BR")
            else:
                _change_sprite_animation("Walking_B")
		else:
            if (last_directional_input .x <= -1):
                _change_sprite_animation("Walking_L")
            elif (last_directional_input .x >= 1):
                _change_sprite_animation("Walking_R")
    # Idle animations below:
	else:
        if (last_directional_input .z <= -1):
            if (last_directional_input .x <= -1):
                _change_sprite_animation("Idle_FL")
            elif (last_directional_input .x >= 1):
                _change_sprite_animation("Idle_FR")
            else:
                _change_sprite_animation("Idle_F")
        elif (last_directional_input .z >= 1):
            if (last_directional_input .x <= -1):
                _change_sprite_animation("Idle_BL")
            elif (last_directional_input .x >= 1):
                _change_sprite_animation("Idle_BR")
            else:
                _change_sprite_animation("Idle_B")
        else:
            if (last_directional_input .x <= -1):
                _change_sprite_animation("Idle_L")
            elif (last_directional_input .x >= 1):
                _change_sprite_animation("Idle_R")

func _change_sprite_animation(new_animation_name):
	if (animation != new_animation_name):
		play (new_animation_name);

func _input(event):
	if event is InputEventMouseMotion:
		$Head.rotate_y(deg2rad(-event.relative.x * mouse_sensitivity))
		
		var change = -event.relative.y * mouse_sensitivity
		if change + camera_angle < 90 and change + camera_angle > -90:
			$Head/Camera.rotate_x(deg2rad(change))
			camera_angle += change

the func _input(event) is for the 3D camera so I can move it

@KindosaurGaming said: I thought it might be more handy to upload the full code of the AnimatedSprite3D ... the func _input(event) is for the 3D camera so I can move it

While I do not know for sure, I think the reason the code isn't working is because there isn't any code to move the player. You'll want to add something like global_translate(velocity * delta) or get_parent().move_and_slide(velocity) (assuming the parent node is a KinematicBody node) so the player moves relative to the velocity. You'll probably want to add the code around line 57.

Looking at the rest of the code, everything else seems to be okay. I haven't tested the code in a test project, but I don't see anything that looks like it would be causing an issue. If adding global_translate(velocity * delta) or get_parent().move_and_slide(velocity) does not fix it, let me know and I'll pull the code into a test project and see if I can figure out what is going on there.

It works these were all my questions (hopefully)

Huge thanks again :)

8 days later

@TwistedTwigleg Ok I am back again with a question (LOL :))

I have made a world in Blender (.dae default) and I have imported it with collision into my godot project but my character keeps walking through the walls and stuff (and also has no gravity). I was thinking that the child of the KinematicBody (AnimatedSprite3D) was the only one changing it's position in the world and doesn't drag the KinematicBody and it's collision.

I tried fixing it by applying the moving input to the KinematicBody, thinking it will drag the AnimatedSprite3D and thereby also the collison with it. But it has no effect or I am not thinking this through.

Can you please help me again with this :# ?

The issue is likely how the AnimatedSprite3D node is moving.

Are you moving the AnimatedSprite3D with global_translate? The global_translate function will move the node through 3D space, but it does not account for physics, which is likely why it is going through things. You'll instead need to use either the move_and_slide or move_and_collide functions from KinematicBody. I think all you will need to do is remove global_translate(velocity) and replace it with get_parent.move_and_slide(velocity) for it to work.

Also, does the KinematicBody have a CollisionShape node? If not, then you will need to make a CollisionShape node for the KinematicBody to collide with the physics world.


If you are already using move_and_slide and it is not colliding (and there is a CollisionShape child node), then the issue might be something else. It is hard to say for sure what could be causing the issue in that case.


As far as gravity goes, you will need to add some form of gravity to velocity. There are several different ways to do this depending on your project and the intended gameplay. One of the most common ways is to do something like this (untested):

const GRAVITY = -18
# Other code here...

func _process(delta):
	# Other code here...
	# Before move_and_slide and/or move_and_collide:
	velocity.y += GRAVITY * delta

You can find an example of a working 3D platformer character on the Godot Demo GitHub repository that might be a helpful reference to look at.


Hopefully this helps a bit :smile:

@TwistedTwigleg To answer your questions :)

  1. Are you moving the AnimatedSprite3D with global_translate?

Yes I am moving the character via the global_translate code

  1. Does the KinematicBody have a CollisionShape node? The hierarchy is as follows :

Spatial Node(named : World) > KinematicBody(Parent) >> CollisionShape(Child of KinematicBody) >> AnimatedSprite3D

So yes the KinematicBody has a CollisionShape

The get_parent.move_and_slide(velocity) doesn't work and will give an error: Identifier "get_parent" is not declared in the current scope

I do know that I might give up a variable, but do I need to specify what parent the code needs to grab? for example : var get_parent = $KinematicBody

also the gravity thing is a constant and it works kinda weird.

The collision is still not established in my world, so I can kinda see what the gravity does in my world.

Here I see that my character is slowly dragged down. I can edit it so that my character can fall down faster so no worries from there.

1 thing that found in godot was in the Engine settings / there you can alter the gravity settings of the 3D world I am able to get there via code so the settings of my project are attached to the script?

Thanks

Thanks for answering the questions, now I think I have a better idea on what is going on.

First, you need to remove global_translate(velocity) and replace it with get_parent().move_and_slide(velocity), which will move the KinematicBody instead of the AnimatedSprite. This should fix the issue with "get_parent not declared in the current scope", as get_parent() is a function and so it needs () at the end to be called. Hopefully that will allow the player to move around using physics.

You can get the gravity from the project settings using ProjectSettings.get_setting("physics/3d/default_gravity"). I have always defined the gravity of the player within the player script for fine tuning, so I'm not totally positive the code snippet above will work, but I believe that is how you get the gravity value from the project settings.

@TwistedTwigleg It is all running smoothly :) just figgiting with the gravity, cuz my character eventually needs to jump (because it is a platformer after all). The only thing is is that my character is somehow sliding in a direction that he isn't suppose to do

edit: well it really is bugging me now at the moment I really am not able to set the gravity I tried following a tutorial but it didnt help.

I want it so that my character does only slide down when a slope is in a certain angle

and the gravity is really bugging me, I really cant get it to work :'(

The gravity needs to be fast and my character really needs to be stuck on the ground

so what happens now is that when I move from a slighty down angled slope he will float for a while and slowly drop down to where the character will colide with the world.

how can I fix this thanks

Great, I’m glad that everything, minus gravity, is going smoothly.

Solving the slow/floating gravity issue is something I have dealt with in several different projects and I haven’t discovered the best solution that completely solves the issue.

I have found that additive gravity is one of the most predictable ways to reduce the floating issue, but finding the right values can be tricky.

I’m away from my pc right now, but the code I’ve used before for additive gravity looks something like this (untested):

# You will probably need to change the values until
# it has the desired effect.
const GRAVITY = -12
const ADDITIONAL_GRAVITY =-8
var applied_gravity = 0

func _physics_process(delta):
    if (get_parent().is_on_floor() == true)):
        applied_gravity = GRAVITY
    else:
        applied_gravity += ADDITIONAL_GRAVITY
    velocity.y += applied_gravity * delta

Something like the code above is what I have most commonly used to reduce the ‘floaty’ feeling that can occur with constant gravity. It doesn’t always work and it can be tricky to find the best values that work with a project, but I have found it works pretty well for most projects.

@TwistedTwigleg It is partially working! =)
cuz my world has a lot of slopes and with the gravity + additional gravity being so high you were not able to get over a small hump in the ground Is there also a way to maybe accelerate when falling so you will slowly go faster the longer you fall down (of course with a MAX_SPEED in it so you won't go through the sound barrrier :p )

The only thing I need to figure out is how to set the code so that my character doesnt slide down hill This is alright if the slope is very steep but if the slope is very minimal it must not accure.

I think that there are a lot of videos about this

Great, I'm glad it is at least somewhat working. :smile:

Is there also a way to maybe accelerate when falling

Technically that is what ADDITIONAL_GRAVITY is for. It should make the gravity value in applied_gravity increasingly stronger as the player is in the air. If you want to have other movement, like going forward, backward, left, or right accelerate when the player is in the air, then you will need code similar to how ADDITIONAL_GRAVITY is added to applied_gravity, but for the X and Z axis.

The only thing I need to figure out is how to set the code so that my character doesnt slide down hill This is alright if the slope is very steep but if the slope is very minimal it must not accure.

Yeah, that I'm not totally sure on. I haven't found a decent solution for slopes and sliding. I normally use a Raycast node to detect if the character is 'grounded', which can help with very minor slopes, but it can be inconsistent at times.

I have found the slope issue and it was really simple. get_parent().move_and_slide(velocity) needed a little more code to make it work.

get_parent().move_and_slide(velocity, Vector3(0,1,0)) this little bit makes my character stuck on a slope and if it is a steep slope he will automatically slide down a bit

thanks for all of your help. I am going to work on the talk boxes now =)

I am following a tutorial wich uses a RayCast and when I tried to call that node it says the following message Attempt to call function 'is_colliding' in base 'null instance' on a null instance.

I the person used the following way to find the node

if (is_on_floor()): has_contact = true else: if !$Tail <--- (This is a RayCast I myself kept the name RayCast) .is_colliding(): `has_contact = false'

3 months later

@TwistedTwigleg Hey I still have a problem with this one because my character goes sliding down eventhough the angle is way less than -1 degrees I again tried screwing around with the code to figure out what could be the solution but : Nope

Cant I make a "Hey-You-Are-Standing-On-A-Slope-That-Is-More-Than-15-Degrees" detection system because I am not able to make that happen as of yet.

Also How can add the jump function in the code because a few months back (I lost the code to it) I was able to make my character jump but it was like teleporting instead of a smooth jump.

(I am asking so much lately because I need to iron out most of the bugs/glitches :) )

@KindosaurGaming said: @TwistedTwigleg Hey I still have a problem with this one because my character goes sliding down eventhough the angle is way less than -1 degrees I again tried screwing around with the code to figure out what could be the solution but : Nope

Cant I make a "Hey-You-Are-Standing-On-A-Slope-That-Is-More-Than-15-Degrees" detection system because I am not able to make that happen as of yet.

It should be possible, at least theoretically. If you find the normal of the ground underneath the player (using a raycast or otherwise) and then calculate the difference in angle between it and a vector pointing straight up, perhaps using the Vector3.angle_to function. That is how I would try to approach the problem.

Also How can add the jump function in the code because a few months back (I lost the code to it) I was able to make my character jump but it was like teleporting instead of a smooth jump.

I don’t remember right off, but something like the following should allow for jumping if you are using a KinematicBody node (untested):

# Define gravity strength for the player
const GRAVITY = -12.0
# Define how high the player can jump
const JUMP_SPEED = 20

# Starting a jump:
if is_on_floor():
	if Input.is_action_just_pressed("movement_jump"):
		vel.y = JUMP_SPEED

# Somewhere before calling move_and_slide:
vel.y += delta * GRAVITY