Im very new and trying to make a dark fantasy platformer. Right now im working on getting movement implemented before I work on the harder stuff like combat and what not and I want to implement a wall jump. Specifically one that doesn’t incentivize or even allow the player to just hold one direction key and spam jump to climb the wall. To ascend the player should have to jump from wall to wall. The following is my entire player script. I KINDA have wall jumping implemented to a degree but no matter what I try the player doesnt kick off the wall. Am I doing something wrong or is my code just too simple?
# 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
func wall_jump():
if is_on_wall_only() and Input.is_action_just_pressed(“Jump”):
velocity.y = walljumpvelocity
velocity.x = walljumpHspeed
# Get the input direction and handle the movement/deceleration.
var direction := Input.get_axis("Move_left", "Move_Right")
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
# Sprite Flipping
if direction > 0:
animated_sprite_2d.flip_h = false
elif direction < 0:
animated_sprite_2d.flip_h = true
# Animation ifs
if is_on_floor():
if direction == 0:
animated_sprite_2d.play("Idle")
else:
animated_sprite_2d.play("Run")
else:
animated_sprite_2d.play("Jump")
if (is_wall_sliding):
animated_sprite_2d.play("Wall Slide")
move_and_slide()
The basic movement template sadly does not support acceleration or forces well. If there is a player input (direction) then your .x speed is directly set to the max speed, when there isn’t a player input it is using move_toward, but as a such a high rate that it’s similar to immediately setting it to zero speed.
You will have to change most of your velocity sets to use move_toward or addition instead of instant assignments.
For example, converting the above script to use move_toward properly. This assumes you would make a ACCELERATION and DECELERATION variable about eight times your speed.
Some games limit the player’s acceleration in the air, this can help prevent wall climbing while keeping the movement fast.
In this section the wall jump will always result in negative 120 on the x axis, which is only ever to the left. If you want to jump to the right you will need to detect which direction is away from the wall, this can be done with normals.
var normal: Vector2 = get_last_slide_collision().get_normal()
velocity += normal * walljumpHspeed
I appreciate the reply. I actually ended up fixing the issue before the moderator approved my post.
my main issue was simply that walljumpHspeed simply wasnt high enough with the basic physics. From there I tweaked the physics and added acceleration and deceleration to add a sense of momentum and now the wall jumping works relatively well (so long as you dont take into account the janky animations) but the actual movement FUNCTIONS and thats the important part. Right now Im trying to figure out ledge climbing.
Ill post my current player script including the fix just in case anyone else finds this thread and is having this problem.
extends CharacterBody2D
const jump_force = -350.0
const WALL_JUMP_VELOCITY = -300.0
const WALL_JUMP_HSPEED = 350.0
const GRAVITY = 800.0
const WALL_SLIDE_SPEED = 50.0
const LEDGE_CLIMB_OFFSET = Vector2(0, -40)
@export var Walk_Speed = 150.0
var is_wall_sliding = false
var wall_jump_cooldown = 0.2
var wall_jump_timer = 0.0
var isGrabbing = false
var isFalling = false
var current_position = "position"
var climb_position = global_position + Vector2(30, -30)
var Run_Speed = 220.0
@export_range(0, 1) var deceleration = 0.1
@export_range(0, 1) var acceleration = 0.1
@export_range(0, 1) var decelerate_on_jump_release = 0.5
@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
@onready var grab_hand_rc: RayCast2D = $Raycasts/Walljump/GrabHandRC
@onready var grab_check_rc: RayCast2D = $Raycasts/Walljump/GrabCheckRC
func _physics_process(delta: float) -> void:
_check_ledge_grab()
ledge_climb()
# Add gravity
if not is_on_floor():
velocity.y += GRAVITY * delta
wall_slide()
wall_jump()
# Add gravity if not on the floor or wall sliding
if not is_on_floor() and not is_wall_sliding:
velocity.y += GRAVITY * delta
# Handle jump
if Input.is_action_just_pressed("Jump") and (is_on_floor() || isGrabbing):
isGrabbing = false
velocity.y = jump_force
isFalling = true
if Input.is_action_just_released("Jump") and velocity.y < 0:
velocity.y *= decelerate_on_jump_release
if isGrabbing: return
var speed
if Input.is_action_pressed("Run"):
speed = Run_Speed
else:
speed = Walk_Speed
# Handle movement
var direction := Input.get_axis("Move_left", "Move_Right")
if direction != 0:
velocity.x = move_toward(velocity.x, direction * speed, speed * acceleration)
else:
velocity.x = move_toward(velocity.x, 0, speed * deceleration)
# Sprite Flipping
if direction > 0:
animated_sprite_2d.flip_h = false
elif direction < 0:
animated_sprite_2d.flip_h = true
# Running, Jumping, Idle Animation
if is_on_floor():
if direction == 0:
animated_sprite_2d.play("Idle")
else:
animated_sprite_2d.play("Run")
if is_on_floor() and Input.is_action_pressed("Jump"):
animated_sprite_2d.play("Jump")
if is_wall_sliding and is_on_wall():
animated_sprite_2d.play("Wall Slide")
if is_on_wall() and Input.is_action_just_pressed("Jump") and isGrabbing == false:
animated_sprite_2d.play("Wall_Jump")
animated_sprite_2d.flip_h
# Apply movement
move_and_slide()
func _check_ledge_grab():
var isFalling = velocity.y >= 0
var checkHand = not grab_hand_rc.is_colliding()
var checkGrabHeight = grab_check_rc.is_colliding()
var canGrab = isFalling && checkHand && checkGrabHeight && not isGrabbing && is_on_wall_only()
if canGrab:
isGrabbing = true
animated_sprite_2d.play("Ledge Grab")
func ledge_climb(): #Current project. Minimal progress made in last 9 hours.
if isGrabbing and Input.is_action_just_pressed("Climb"):
$AnimationPlayer.play("Ledge Climb")
func wall_jump():
if is_on_wall_only() and Input.is_action_just_pressed("Jump"):
var wall_direction = get_wall_direction()
velocity.y = WALL_JUMP_VELOCITY
velocity.x = wall_direction * WALL_JUMP_HSPEED
# Start cooldown timer
wall_jump_timer = wall_jump_cooldown
is_wall_sliding = false
func wall_slide():
if is_on_wall_only() and velocity.y > 0:
is_wall_sliding = true
velocity.y = WALL_SLIDE_SPEED
else:
is_wall_sliding = false
func get_wall_direction() -> int:
# Determine if the wall is on the left (-1) or right (1)
if is_on_wall():
var test_left = test_move(global_transform, Vector2(-1, 0))
var test_right = test_move(global_transform, Vector2(1, 0))
if test_left:
return 1 # Wall is on the left, jump to the right
elif test_right:
return -1 # Wall is on the right, jump to the left
return 0