Godot Version
4.2.2 stable
Question
Hello, I have once again come to seek your help.
I made a FSM by following this great tutorial https://www.youtube.com/watch?v=hqys6_S2WQs by GeMakesGames. But now, I am lost. I want the player to be able to walljump only against a specific layer in my game. My main problem is adding a way to stop the player from jumping against the wall it is currently climbing against (either by just pressing “jump” or by pressing the direction against it and pressing “jump”.
Here are the scripts that I think are revelant:
fsm.gf:
extends Node
class_name FSM
var states = {}
var current_state
var current_state_node
var previous_state
func _ready():
var object = get_parent()
for child in get_children():
if child is State:
states[child.name.to_lower()] = child
child.fsm = self
child.object = object
func physics_update(delta):
if not current_state: return
current_state_node.update(delta)
if current_state: current_state_node.update(delta)
func _physics_process(delta):
if not current_state: return
current_state_node.physics_update(delta)
func change_state(next_state):
if current_state:
current_state_node.exit()
previous_state = current_state
current_state = next_state
current_state_node = states[next_state]
current_state_node.enter()
input_handler.gd:
extends Node
@onready var jump_buffer_timer = $JumpBufferTimer
var x = 0
var jump_pressed = false
var jump_just_pressed = false:
get:
return jump_just_pressed
set(value):
jump_just_pressed = value
if value: jump_buffer = true
var jump_buffer:
get:
return not jump_buffer_timer.is_stopped()
set(value):
if value: jump_buffer_timer.start()
else: jump_buffer_timer.stop()
func update():
x = Input.get_axis("btn_left", "btn_right")
jump_just_pressed = Input.is_action_just_pressed("btn_jump")
jump_pressed = Input.is_action_pressed("btn_jump")
player.gd:
extends CharacterBody2D
class_name Player
@onready var fsm = $FSM
@onready var sprite = $AnimatedSprite2D
@onready var input = $InputHandler
const AIR_MULTIPLIER = 0.7
const MAX_SPEED = 90.0
const ACCELERATION = 900.0
const JUMP_GRAVITY = 900.0
const FALL_GRAVITY = 500.0
const TERMINAL_VELOCITY = 600.0
# direction = the direction that the player is facing
var direction :
get: return direction
set(value):
if value == 0 or value == direction: return
direction = value
sprite.flip_h = value == -1
func _ready():
fsm.change_state("idle")
func _physics_process(delta):
input.update()
fsm.physics_update(delta)
if is_on_floor():
# Disable collision with objects on layer 9
set_collision_mask_value(9, false)
else:
# Enable collision with objects on layer 9
set_collision_mask_value(9, true)
player_base_state.gd:
extends State
class_name PlayerBaseState
var input:
get: return object.input
func play(animation):
object.sprite.play(animation)
func accelerate(delta, direction = input.x):
var mult = Player.AIR_MULTIPLIER if not object.is_on_floor() else 1.0
object.velocity.x = move_toward(object.velocity.x, Player.MAX_SPEED * direction, Player.ACCELERATION * mult * delta)
func apply_gravity(delta):
var g = Player.JUMP_GRAVITY if fsm.current_state == "jump" else Player.FALL_GRAVITY
object.velocity.y = move_toward(object.velocity.y, Player.TERMINAL_VELOCITY, g * delta)
func move(delta, apply_g, update_direction = true, direction = input.x):
accelerate(delta, direction)
if apply_g: apply_gravity(delta)
if update_direction: object.direction = direction
object.move_and_slide()
player_fall_state.gd:
extends PlayerBaseState
@onready var coyote_timer = $CoyoteTimer
func enter():
play("fall")
if fsm.previous_state != "jump":
coyote_timer.start()
func physics_update(delta):
move(delta, true)
if not coyote_timer.is_stopped() && input.jump_just_pressed:
change_state("jump")
elif object.is_on_floor():
if input.jump_buffer:
change_state("jump")
elif input.x == 0:
change_state("idle")
else:
change_state("run")
elif object.is_on_wall():
change_state("climb")
player_jump_state:
extends PlayerBaseState
var variable_jump_height
func enter():
play("jump")
object.velocity.y = -300
object.velocity.x += input.x * Player.MAX_SPEED
variable_jump_height = false
input.jump_buffer = false
func physics_update(delta):
move(delta, true)
if not variable_jump_height and not input.jump_pressed:
variable_jump_height = true
if object.velocity.y <= 0:
object.velocity.y /= 2
if object.velocity.y >= 0:
change_state("fall")
elif object.is_on_wall():
change_state("climb")
player_climb_state.gd:
extends PlayerBaseState
func enter():
play("climb")
func physics_update(delta):
if input.jump_pressed:
change_state("jump")
And here is a video showing what I don’t want to occur:
I also want to be able to change how the jump is handled after jumping from the wall, but like I said my main issue is just that I am not managing to tell Godot that: if the player is pressing the direction against the wall or no direction at all, I don’t want it to be able to jump. I just want the player to be able to jump while pressing the opposite direction of the wall and then jumping. The player needs to be stuck against the wall until it jumps.
I tried finding answers in the documentation or here but I am way too lost. I checked multiple tutorials but there is always something that “blocks” me. I long for the day I can just stop checking tutorials and mainly use the documentation because I tried this learning code thing for a few weeks now and I have nothing to show for it, very discouraging!
Thanks in advance everyone.