Hello i am programming a game. A 2D Metroidvania but I am a little bit confused right now. I can’t figure why I can’t jump and why the Idle Anim doesnt start when I am not jumping anymore. If I ‘jump’ from a cliff i just fly up for ever.
Can someone look at this please?
extends CharacterBody2D
const SPEED = 200
const JUMP_FORCE = -40
const CALLABLE_STATES := [
PlayerState.ATTACKING,
PlayerState.ATTACKING_BIG,
PlayerState.HEALING,
PlayerState.TAKING_DAMAGE,
PlayerState.DODGING,
]
const CAN_CHANGE_STATE := {
PlayerState.IDLE: [
PlayerState.IDLE,
PlayerState.RUNNING,
PlayerState.JUMPING,
PlayerState.ATTACKING,
PlayerState.HEALING,
PlayerState.TAKING_DAMAGE,
],
PlayerState.RUNNING: [
PlayerState.IDLE,
PlayerState.RUNNING,
PlayerState.JUMPING,
PlayerState.ATTACKING,
PlayerState.HEALING,
PlayerState.TAKING_DAMAGE,
PlayerState.DODGING,
],
PlayerState.DODGING: [
PlayerState.IDLE,
PlayerState.RUNNING,
],
}
const ENDLESS_STATES := [ # Die Liste enthält die Zustände die nicht mit Animationsende beendet werden sollen
PlayerState.IDLE,
PlayerState.RUNNING,
PlayerState.JUMPING,
]
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
var canceable_animation := false
var current_player_state: PlayerState = PlayerState.IDLE # current_player_state ist vom Datentyp PlayerState. Damit auch nur die Staten aus der enum in der Variable stehen können
@onready var anim := $AnimationPlayer
enum PlayerState { # Diese Enumeration möchte Ich zum besseren wechseln des Statuses des Spielers benutzen.
IDLE, # Für jeden Status gibt es ein Objekt in der enum. In der späteren Logik werden die Staten
RUNNING, # durchgewechselt, damit manche Aktionen unter gewissen Staten nicht druchgeführt werden
JUMPING, # können.
ATTACKING,
ATTACKING_BIG,
HEALING,
TAKING_DAMAGE,
DODGING
}
func is_callable_state(state: PlayerState) -> bool:
return state in CALLABLE_STATES
func can_change_state(to_state: PlayerState) -> bool: # Diese FUnktion prüft ob der Status geändert werden darf
match current_player_state:
PlayerState.IDLE:
# Vom IDLE State kann man nur in folgende States wechseln:
return to_state in CAN_CHANGE_STATE[PlayerState.IDLE]
PlayerState.RUNNING:
# Vom Running State kann man nur in folgende States wechseln:
return to_state in CAN_CHANGE_STATE[PlayerState.RUNNING]
PlayerState.DODGING:
# Nach dem Dodge sollen die States von IDLE oder RUN verfügbar sein
return to_state in CAN_CHANGE_STATE[PlayerState.DODGING]
_:
# Bei diesen States darf der Status nicht geändert werden.
return false
func set_state(new_state: PlayerState): # Diese Funktion setzt einen neuen Status, wenn er geändert werden darf
if is_callable_state(current_player_state) and current_player_state != new_state:
print("Anim läuft noch, Zustand nicht abbrechbar: ", current_player_state)
elif can_change_state(new_state):
current_player_state = new_state
print("Zustandgewechselt --> ", current_player_state)
update_animation(current_player_state)
else:
print("Zustand konnte nicht gewechselt werden: ", current_player_state, "--> ", new_state)
func update_animation(state : PlayerState): # Diese Funktion aktualisiert die Animationen je nach Status
match state:
# 'passes' durch die jeweilige Animation ersetzen
PlayerState.IDLE:
anim.play("Player-Idle")
PlayerState.RUNNING:
anim.play("Player-Run")
PlayerState.JUMPING:
anim.play("Player-Jump")
PlayerState.ATTACKING:
anim.play("Player-Attack")
PlayerState.ATTACKING_BIG:
anim.play("Player-Attack-Big")
PlayerState.HEALING:
anim.play("Player-Healing")
PlayerState.TAKING_DAMAGE:
anim.play("Player-Hurt")
PlayerState.DODGING:
anim.play("Player-Dodge")
func _on_animation_player_animation_finished(_anim_name: StringName) -> void:
if not current_player_state in ENDLESS_STATES:
print("Anim beendet, Zustand auf IDLE gesetzt: ", current_player_state)
current_player_state = PlayerState.IDLE
update_animation(current_player_state)
func _ready():
anim.active = true
func _physics_process(delta: float) -> void:
input_handle()
# Wendet das Movement auf den CharacterBody an
# direction kann entweder -1 | 0 | 1
var direction = Input.get_axis("move-left", "move-right")
match current_player_state:
PlayerState.IDLE:
velocity.x = 0
PlayerState.RUNNING:
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
if velocity.x == 0:
set_state(PlayerState.IDLE)
if direction < 0:
$AnimatedSprite2D.flip_h = true
$"DamageBox-Small"/CollisionShape2D.position.x = -23
$HitBox.position.x = -1
elif direction > 0:
$AnimatedSprite2D.flip_h = false
$"DamageBox-Small"/CollisionShape2D.position.x = 23
$HitBox.position.x = 1
PlayerState.JUMPING:
if is_on_floor():
velocity.y = JUMP_FORCE
PlayerState.DODGING:
velocity.x = direction * SPEED * 1.5
_:
velocity.x = 0
velocity.y += gravity * delta
if is_on_floor() and current_player_state == PlayerState.JUMPING:
velocity.y = 0
current_player_state = PlayerState.IDLE
move_and_slide()
func input_handle(): # Verändert die States je nach Player Eingabe
var direction = Input.get_axis("move-left", "move-right")
if direction != 0 and can_change_state(PlayerState.RUNNING):
set_state(PlayerState.RUNNING)
if Input.is_action_just_pressed("move-jump") and can_change_state(PlayerState.JUMPING):
set_state(PlayerState.JUMPING)
if Input.is_action_just_pressed("action-attack") and can_change_state(PlayerState.ATTACKING):
set_state(PlayerState.ATTACKING)
if Input.is_action_just_pressed("action-attack-big") and can_change_state(PlayerState.ATTACKING_BIG):
print("dicker angriff")
set_state(PlayerState.ATTACKING_BIG)
if Input.is_action_just_pressed("move-dodge") and can_change_state(PlayerState.DODGING):
set_state(PlayerState.DODGING)
if Input.is_action_just_pressed("action-heal") and can_change_state(PlayerState.HEALING):
set_state(PlayerState.HEALING)