very new to all this just messing about with it seeing what sort of 3d 3rd person game i could do and got as far as getting a very basic world to test in my player model and animations in and a player controller script that all works but trying to tweak the animations somehow so the animation for jumping i have slightly crouches first before jumping up but obviously the model leaves the floor straight away is there anyway to delay leaving the floor for say half a second or any other way to sync them up? Cheers
extends CharacterBody3D
@onready var camera_mount = $"camera mount"
@onready var visuals = $visuals
@onready var animation_player = $visuals/test/AnimationPlayer
var SPEED = 2.0
const JUMP_VELOCITY = 6.0
var walking_speed = 2.0
var sprinting_speed = 5.0
var crouching_speed = 2.0
var running = false
var crouching = false
var in_air = false
@export var sens_horizontal = 0.1
@export var sens_vertical = 0.1
func _ready():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _input(event):
if event is InputEventMouseMotion:
rotate_y(deg_to_rad(-event.relative.x*sens_horizontal))
visuals.rotate_y(deg_to_rad(event.relative.x*sens_horizontal))
camera_mount.rotate_x(deg_to_rad(-event.relative.y*sens_vertical))
camera_mount.rotation.x = clamp(camera_mount.rotation.x, deg_to_rad(-80), deg_to_rad(45))
func _physics_process(delta):
if not is_on_floor():
velocity += get_gravity() * delta
in_air = true
else:
if in_air:
in_air = false
if velocity.length() > 0:
if crouching:
animation_player.play("crouch walk")
elif running:
animation_player.play("sprint")
else:
animation_player.play("walk")
else:
animation_player.play("idle")
# Handle sprinting and crouching
running = Input.is_action_pressed("sprint")
crouching = Input.is_action_pressed("crouch")
if crouching:
SPEED = crouching_speed
elif running:
SPEED = sprinting_speed
else:
SPEED = walking_speed
# Handle jump
if Input.is_action_just_pressed("jump") and is_on_floor():
if animation_player.current_animation != "jump":
animation_player.play("jump")
velocity.y = JUMP_VELOCITY
in_air = true
# Get the input direction
var input_dir = Input.get_vector("left", "right", "forward", "backward")
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction.length() > 0 and not in_air:
if crouching:
if animation_player.current_animation != "crouch walk":
animation_player.play("crouch walk")
elif running:
if animation_player.current_animation != "sprint":
animation_player.play("sprint")
else:
if animation_player.current_animation != "walk":
animation_player.play("walk")
visuals.rotation.y = lerp_angle(visuals.rotation.y, atan2(-input_dir.x, -input_dir.y), 0.15)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
elif not in_air:
if crouching:
if animation_player.current_animation != "crouch":
animation_player.play("crouch")
else:
if animation_player.current_animation != "idle":
animation_player.play("idle")
var DECELERATION = 12.0
velocity.x = move_toward(velocity.x, 0, DECELERATION * delta)
velocity.z = move_toward(velocity.z, 0, DECELERATION * delta)
# Move the character and apply gravity using move_and_slide()
move_and_slide()
Create a new function called apply_jump_force and move this code for this function:
After that save your script and restart the editor.
In your jump animation, create a call method track and select the node with the character script. In this track do a right click, select insert key and select the apply_jump_force function. Now you just need to drag the created key for the point you want the character start leaving the floor.
Hi cheers for that! again quite new to all this so it maybe the way ive wrote the code or done something else but its not quite working properly yet but think thats down to how ive done it rather than the method, so done what you said and created a new func apply_jump_force(): and copied the velocity.y = JUMP_VELOCITY
in_air = true to under that func and that is doing exactly what i asked just after my initial jump now haha so character jumps how i first described but then after the roughly half a second delay on the key on the call method track for the jump animation it jumps again while already mid air but synced up if thats makes sense, so like he has a double jump now with one press of the button but the animation is in time for the “second” jump
and also lefy my bit that handles the jump the same
# Handle jump
if Input.is_action_just_pressed("jump") and is_on_floor():
if animation_player.current_animation != "jump":
animation_player.play("jump")
velocity.y = JUMP_VELOCITY
in_air = true
so with it like that i get the weird double jump thing but if i remove “velocity.y = JUMP_VELOCITY” from either of them blocks i end up with only the first out of sync jump and lose the in sync one
yeah ill attach here, so ive only got the one script with everything at the moment and chances are its all wrote horribly aswell as im just trying random things and seeing what works, only thing that is different at this very second is the line " @onready var animation_player = $visuals/test/AnimationPlayer" is now “@onready var animation_player = $visuals/test2/AnimationPlayer” as ive just changed the jump animation for now to one that doesnt crouch down first aha and also removed the func _apply_jump_force bit you said before but everything else is the same as it was
extends CharacterBody3D
@onready var camera_mount = $"camera mount"
@onready var visuals = $visuals
@onready var animation_player = $visuals/test2/AnimationPlayer
var SPEED = 2.0
const JUMP_VELOCITY = 4.5
var walking_speed = 2.0
var sprinting_speed = 5.0
var crouching_speed = 2.0
var running = false
var crouching = false
var in_air = false
@export var sens_horizontal = 0.1
@export var sens_vertical = 0.1
func _ready():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _input(event):
if event is InputEventMouseMotion:
rotate_y(deg_to_rad(-event.relative.x*sens_horizontal))
visuals.rotate_y(deg_to_rad(event.relative.x*sens_horizontal))
camera_mount.rotate_x(deg_to_rad(-event.relative.y*sens_vertical))
camera_mount.rotation.x = clamp(camera_mount.rotation.x, deg_to_rad(-80), deg_to_rad(45))
func _physics_process(delta):
if not is_on_floor():
velocity += get_gravity() * delta
in_air = true
else:
if in_air:
in_air = false
if velocity.length() > 0:
if crouching:
animation_player.play("crouch walk")
elif running:
animation_player.play("sprint")
else:
animation_player.play("walk")
else:
animation_player.play("idle")
# Handle sprinting and crouching
running = Input.is_action_pressed("sprint")
crouching = Input.is_action_pressed("crouch")
if crouching:
SPEED = crouching_speed
elif running:
SPEED = sprinting_speed
else:
SPEED = walking_speed
# Handle jump
if Input.is_action_just_pressed("jump") and is_on_floor():
if animation_player.current_animation != "jump":
animation_player.play("jump")
velocity.y = JUMP_VELOCITY
in_air = true
# Get the input direction
var input_dir = Input.get_vector("left", "right", "forward", "backward")
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction.length() > 0 and not in_air:
if crouching:
if animation_player.current_animation != "crouch walk":
animation_player.play("crouch walk")
elif running:
if animation_player.current_animation != "sprint":
animation_player.play("sprint")
else:
if animation_player.current_animation != "walk":
animation_player.play("walk")
visuals.rotation.y = lerp_angle(visuals.rotation.y, atan2(-input_dir.x, -input_dir.y), 0.15)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
elif not in_air:
if crouching:
if animation_player.current_animation != "crouch":
animation_player.play("crouch")
else:
if animation_player.current_animation != "idle":
animation_player.play("idle")
var DECELERATION = 12.0
velocity.x = move_toward(velocity.x, 0, DECELERATION * delta)
velocity.z = move_toward(velocity.z, 0, DECELERATION * delta)
# Move the character and apply gravity using move_and_slide()
move_and_slide()
Might not be an elegant solution but you could set up a timer as a child node and change the code to something like this. (don’t know if code is different for 3d - I’ve only tried 2d)
# Handle jump
if Input.is_action_just_pressed("jump") and is_on_floor():
timer.start()
#this is a signal
func _on_timer_timeout():
if animation_player.current_animation != "jump":
animation_player.play("jump")
velocity.y = JUMP_VELOCITY
in_air = true
then set the time to equal whatever amount of time between the crouch and the actual jump and make the timer a one shot
dont worry nothing ive done so far has been elegant haha and chances are ive used something wrong somewhere already, never even used timers or anything like that very very new aha but ive just tried it but not sure if i even set it up correctly, so i added a timer as a child node to my characterbody3d and just left on 1 sec for now and oneshot on then in my script added
@onready var timer = $Timer
func _on_timer_timeout():
if animation_player.current_animation != "jump":
animation_player.play("jump")
velocity.y = JUMP_VELOCITY
in_air = true
if Input.is_action_just_pressed("jump") and is_on_floor():
timer.start()
so they are the 3 changes ive just made to the code but now i cant jump and no animation again, is it the way ive done my initial code for the jumping? i had to try a few different things to even get the animation to play at first but got it working with all the in_air = true/false stuff but most of the things ive tried for this issue have just stopped the jump and animation all togther so im wondering have i done something weird early on
var jump_queued = false
func _apply_jump_force():
if !in_air and !jump_queued: # Only allow jump if not in air and jump hasn't been queued
velocity.y = JUMP_VELOCITY
in_air = true
jump_queued = true # Mark jump as queued to prevent double jumping
func _physics_process(delta):
if not is_on_floor():
velocity += get_gravity() * delta
in_air = true
else:
if in_air:
in_air = false
jump_queued = false
func _animation_jump_trigger():
# This method is called by the animation's call method track at the correct moment
_apply_jump_force()
might have missed some there but tried along them lines aswell and couldnt get it im pretty sure when i tried that it just got rid of the second jump i had that was in sync but started mid air and kept the normal out of sync one
just to make sure with the timer code did you insert the func on_timer_timeout() as a signal?
if not, you can find the signal by pressing on the timer node then pressing node in the top right.
@onready var timer = $Timer
func _physics_process(delta):
if Input.is_action_just_pressed("jump") and is_on_floor():
timer.start()
func _on_timer_timeout():
if animation_player.current_animation != "jump":
animation_player.play("jump")
velocity.y = JUMP_VELOCITY
in_air = true
Also it looks a bit unclear but if Input.is_action_just_pressed("jump") and is_on_floor(): should still be in func _physics_process(delta): So that when you are on the floor and pressing jump, the timer will start - then when it ends the actual jump should happen.
so is that bit saying if the jump animation isnt playing when the timer finishes start playing it? if so do i not want the animation to start straight away and the actual jump be delayed
I’m going to be honest and say i’m not too familiar with using animation player on it’s own (I’ve found that animation trees give a bit more overview).
If you could explain something for me it might help a bit but why do you need the line if animation_player.current_animation != "jump":
Or you could change the code to look something like this:
if velocity.y != 0:
animation_player.play("jump")
(that’s the y axis should be handling up- or down force)
But I’m not really familiar with 3d programming so not sure if this is correct
ahh right see ive not even looked at that yet like im guessing theres just a lot of things i dont know about in godot yet that would make these things easier ill have a read into that now! and with regards to that line of code so i ended up with that through trial an error like i menioned before i just could not get the animation to play when jumping so i went through various different bits defining is on floor and is in air true/false
var in_air = false
func _physics_process(delta):
if not is_on_floor():
velocity += get_gravity() * delta
in_air = true
else:
if in_air:
in_air = false
if velocity.length() > 0:
if crouching:
animation_player.play("crouch walk")
elif running:
animation_player.play("sprint")
else:
animation_player.play("walk")
else:
animation_player.play("idle")
# Handle jump
if Input.is_action_just_pressed("jump") and is_on_floor():
if animation_player.current_animation != "jump":
animation_player.play("jump")
velocity.y = JUMP_VELOCITY
in_air = true
if direction.length() > 0 and not in_air:
if crouching:
if animation_player.current_animation != "crouch walk":
animation_player.play("crouch walk")
elif running:
if animation_player.current_animation != "sprint":
animation_player.play("sprint")
else:
if animation_player.current_animation != "walk":
animation_player.play("walk")
visuals.rotation.y = lerp_angle(visuals.rotation.y, atan2(-input_dir.x, -input_dir.y), 0.15)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
elif not in_air:
if crouching:
if animation_player.current_animation != "crouch":
animation_player.play("crouch")
else:
if animation_player.current_animation != "idle":
animation_player.play("idle")
so between all them bits is how i ended up getting the jump and the animation to work ill try and remember how i originally had the script that was basically just for movement before trying to add the animations but yeah it was fine with walking,crouching,running etc but when i tried adding jump if just didnt want to do it and ended up with all that nonsense above haha but gurantee theres someone who knows loads more and will know a method to do it without being as much of a mess
extends CharacterBody3D
@onready var camera_mount = $"camera mount"
@onready var animation_player = $visuals/test/AnimationPlayer
@onready var visuals = $visuals
var SPEED = 2.0
const JUMP_VELOCITY = 4.5
var walking_speed = 2.0
var sprinting_speed = 5.0
var running = false
@export var sens_horizontal = 0.1
@export var sens_vertical = 0.1
func _ready():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _input(event):
if event is InputEventMouseMotion:
rotate_y(deg_to_rad(-event.relative.x*sens_horizontal))
visuals.rotate_y(deg_to_rad(event.relative.x*sens_horizontal))
camera_mount.rotate_x(deg_to_rad(-event.relative.y*sens_vertical))
func _physics_process(delta):
if Input.is_action_pressed("sprint"):
SPEED = sprinting_speed
running = true
else:
SPEED = walking_speed
running = false
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var input_dir = Input.get_vector("left", "right", "forward", "backward")
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
if running:
if animation_player.current_animation != "running":
animation_player.play("running")
else:
if animation_player.current_animation != "walking":
animation_player.play("walking")
visuals.look_at(position + direction)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
if animation_player.current_animation != "idle":
animation_player.play("idle")
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
thats roughly how it started out i think but just been trying different things and adding stuff just like adding little bits for the camera controls and stuff etc seeing what i can do but its a bit of a mess now haha but no unfortunately not yet haha probably be a lot easier now to start from scratch and maybe watch some tutorials see if other people have done it issue is most of the time i dont remember it the next day if im just watching/copying some do it haha
yeah definitely think thats the way to go rather than spend 10x the time to figure out a way 10x worse to do it aha also other problems i havent figured out yet since getting the jump and animation to play like now i have no directional control when in the air where as i did before the jumping animation but cheers anyway still learnt some good things from your guys suggestions