Artigos anteriores:
- Primeira parte
- A segunda parte
- A terceira parte
Melhorias no sistema de escalada do conjunto 2 e mais
Adicione um nó RayCast2D à cena do jogador.

É assim que meu personagem se parece. Adicione RayCast ao início da seta.
Em geral, vou mostrar todo o código do meu personagem e tentar comentá-lo da forma mais clara possível.
# , .
extends KinematicBody2D
signal timer_ended # _process
const UP_VECTOR: Vector2 = Vector2(0, -1) #
const GRAVITY: int = 40 #
const MOVE_SPEED: int = 100 #
const JUMP_POWER: int = 480 #
const CLIMB_SPEED: int = 40 #
const WALL_JUMP_SPEED: int = 80 #
enum States {ON_FLOOR, ON_WALL} # , 2
onready var ray_cast: Object = $RayCast2D # .
var velocity: Vector2 = Vector2.ZERO # .
var walls: Array = [false, false, false] # . , , .
var timer_enabled: bool = false #
var climbing: bool = false # ,
var is_wall_jump: bool = false # ,
var is_double_jump: bool = true #
var right_pressed: float = 0 # ,
var left_pressed: float = 0
var timer: float = 0 #
var prev_direction: float = 0 # .
var direction: float = 0 # .
var keys: int = 0 # . ,
var current_state: int = States.ON_FLOOR #
func _ready():
ray_cast.add_exception($WallLeft) # ray_cast
ray_cast.add_exception($WallRight)
ray_cast.add_exception(self)
func _process(_delta: float) -> void: # _process
if timer > 0 or timer_enabled:
timer -= _delta # _delta
if timer <= 0 and timer_enabled:
timer_enabled = false
timer = 0 #
emit_signal("timer_ended") # .
if self.direction != 0:
self.ray_cast.cast_to *= -1
self.prev_direction = self.direction # 0
func _physics_process(_delta: float) -> void:
self.control_character()
self.pause_opened() # -
if (!self.climbing): # ,
if (!self.is_wall_jump): # self.velocity.y
self.velocity.y += GRAVITY
else: # 4
self.velocity.y += float(GRAVITY) / 4
self.velocity = self.move_and_slide(self.velocity, UP_VECTOR) # self.velocity
func check_states() -> void:
if self.is_on_floor():
self.current_state = States.ON_FLOOR
is_double_jump = true
elif self.is_on_wall():
self.current_state = States.ON_WALL
is_double_jump = true
elif self.is_on_floor() and self.is_on_wall():
self.current_state = States.ON_WALL
func fall() -> void:
self.velocity.y += GRAVITY
func update_controls(): # "" ""
if !is_wall_jump: # -
self.left_pressed = Input.get_action_strength("ui_left")
self.right_pressed = Input.get_action_strength("ui_right")
func control_character() -> void: #
check_states() #
update_controls() #
self.interact_with() # +
match current_state:
States.ON_WALL:
self.climb()
self.move()
if !climbing:
self.jump()
self.fall()
self.wall_jump()
# States.IN_AIR: #
# self.jump()
# self.move()
# self.fall()
States.ON_FLOOR:
self.jump()
self.move()
func climb():
if (walls[0] or walls[2]): # - self.climbing = "ui_climb".
self.climbing = Input.is_action_pressed("ui_climb")
else: #
self.climbing = false
func climb_up() -> void: #
self.velocity.y = (CLIMB_SPEED)
func climb_down() -> void: #
self.velocity.y = (-CLIMB_SPEED)
func move() -> void: # . ,
self.direction = self.right_pressed - self.left_pressed
if (self.climbing and !self.is_wall_jump):
if self.walls[0]: #
if direction > 0: # -
climb_up()
elif direction < 0: # -
climb_down()
else: #
self.velocity.y = 0
elif self.walls[2]: # ,
if direction < 0:
climb_up()
elif direction > 0:
climb_down()
else:
self.velocity.y = 0
# else: # ,
# self.velocity.y = 0
else: #
self.velocity.x = self.direction * float(MOVE_SPEED) * (1 + (float(self.is_wall_jump) / 2))
if !(climbing): #
if direction == 0:
$AnimatedSprite.flip_h = (-self.prev_direction >= 0)
$AnimatedSprite.play("idle")
else:
$AnimatedSprite.flip_h = direction < 0
$AnimatedSprite.play("run")
return
func jump() -> void: #
if Input.is_action_just_pressed("ui_accept"):
if is_on_floor():
self.velocity.y = -JUMP_POWER
if !is_on_floor() and is_double_jump:
is_double_jump = false
self.velocity.y = -JUMP_POWER
func wall_jump() -> void:
if Input.is_action_just_pressed("ui_accept") and Input.is_action_pressed("ui_climb"):
self.is_wall_jump = true
self.velocity.y = -JUMP_POWER
if walls[0]:
self.timer = 0.3
self.timer_enabled = true
self.right_pressed = 1 # -
yield(self, "timer_ended") #
self.right_pressed = Input.get_action_strength("ui_right")
#
elif walls[2]:
self.timer = 0.3
self.timer_enabled = true
self.left_pressed = 1 # -
yield(self, "timer_ended")
self.left_pressed = Input.get_action_strength("ui_left")
#
self.is_wall_jump = false #
func interact_with() -> void: #
if Input.is_action_pressed("ui_use"): #
var coll: Object = self.ray_cast.get_collider() #
if coll: # null
if coll.has_method("open"): # ,
use_key(coll)
elif coll.has_method("interact"):
use_object(coll)
func use_object(collider: Object) -> void: #
collider.interact(self) #
func use_key(collider: Object) -> void: # .
if self.keys > 0: #
collider.open() #
self.keys -= 1 #
func key_picked_up():
self.keys += 1
func _on_WallRight_body_entered(_body): # .
if (_body.name != self.name): # - -
self.walls[2] = true # walls true false.
func _on_WallRight_body_exited(_body): #
self.walls[2] = false #
func _on_WallLeft_body_entered(_body): #
if (_body.name != self.name): #
self.walls[0] = true #
func _on_WallLeft_body_exited(_body): #
self.walls[0] = false #
func dead():
# $Particles2D.emitting = true # -
LevelMgr.goto_scene("res://scenes/dead_screen/dead_screen.tscn") # .
func pause_opened(): #
if Input.is_action_just_pressed("ui_cancel"): #
$PositionResetter/WindowDialog.popup_centered()
Conclusão
No momento, este é o código de caractere mais atualizado que acabei de criar. Devido ao fato de que o código está totalmente pronto, não tenho nada a acrescentar a ele separadamente. E como tive as aulas sobre armadilhas em um ciclo separado, também não tenho nada a dizer sobre os exemplos de uso do sistema de interação. Também me perguntei o que você gostaria de saber na próxima parte e apresentei a seguir um levantamento feito de ideias para a mecânica que me vieram à mente. Obrigado pela leitura e até a próxima.