Godot Version
GODOT 4.2.2
Introduction:
Previously, I used this Youtube video on making a boss using the state machine,
I tried to use it as a reference to create a sandworm trap and an arrow trap using this Youtube video.
SandwormTrap Nodes:
For the sandworm trap I created, I used the characterbody2d
as the main node for the sandworm trap and the remaining nodes are
Sprite2D
and Sprite2D2
are for the animation changing when changing from Idle state to Attack State or Attack State to Idle State.
The UI
and the debug
tag is for checking if the state is changing properly.
Sandworm Trap Scripts:
In SandwormTrap(CharacterBody2D
) has a script called SandwormTrap.gd that contains the following lines:
extends CharacterBody2D
@onready var player = get_parent().find_child(“Player”)
@onready var sprite = $Sprite2Dvar direction : Vector2
func _ready():
set_physics_process(false)func _process(_delta):
direction = player.position - position
print(direction.length())func _physics_process(_delta):
pass
For the FiniteStateMachine(Node2D
) has a script named SandwormFiniteStateMachine.gd that contains the lines:
extends Node2D
var current_state: SandwormState
var previous_state: SandwormStatefunc _ready():
current_state = get_child(0) as SandwormState
previous_state = current_state
current_state.enter()func change_state(state):
current_state = find_child(state) as SandwormState
current_state.enter()previous_state.exit()
previous_state = current_state
And for each of the State(Idle and Attack) contains a StateScript that has named SandwormState.gd:
extends Node2D
class_name SandwormState@onready var debug = owner.find_child(“debug”)
@onready var player = owner.get_parent().find_child(“Player”)
@onready var animation_player = owner.find_child(“AnimationPlayer”)Called when the node enters the scene tree for the first time.
func _ready():
set_physics_process(false)func enter():
set_physics_process(true)func exit():
set_physics_process(false)func transition():
passfunc _physics_process(_delta):
transition()
debug.text = name
and the state scripts are extended with another script.
For Idle State, it was extended with the scipt named Idle:
extends SandwormState
@onready var collision = $“…/…/PlayerDetection/CollisionShape2D”var player_entered: bool = false:
set(value):
player_entered = value
collision.set_deferred(“disabled”, value)func transition():
if player_entered:
get_parent().change_state(“Attack”)func _on_player_detection_body_entered(_body):
player_entered = true
For Attack State, it was extended with the script named Attack:
extends SandwormState
func enter():
super.enter()
owner.set_physics_process(true)
animation_player.play(“Attack”)func exit():
super.exit()
owner.set_physics_process(false)func transition():
var distance = owner.direction.length()
print('distance ', distance)
if distance < 1:
get_parent().change_state(“Attack”)
ArrowTrap Nodes:
The nodes are basically the same with the SandwormTrap. So, I’m not gonna explain it again.
ArrowTrap Scripts:
The ArrowTrap(CharacterBody2D) has the script lines of this:
extends CharacterBody2D
@onready var player = get_parent().find_child(“Player”)
@onready var sprite = $Sprite2Dvar direction : Vector2
func _ready():
set_physics_process(false)func _process(_delta):
direction = player.position - position
For FiniteStateArrow(FiniteStateMachine) also has the script lines of this:
extends Node2D
var current_state: ArrowState
var previous_state: ArrowStatefunc _ready():
current_state = get_child(0) as ArrowState
previous_state = current_state
current_state.enter()func change_state(state):
current_state = find_child(state) as ArrowState
current_state.enter()previous_state.exit()
previous_state = current_state
The states are the same, they have State Script attached to them each(Arrow_Idle and Arrow_Attack) and it looked like this:
extends Node2D
class_name ArrowState
@onready var debug = owner.find_child(“Debug”)
@onready var player = owner.get_parent().find_child(“Player”)
@onready var animation_player = owner.find_child(“AnimationPlayer”)func _ready():
set_physics_process(false)func enter():
set_physics_process(true)func exit():
set_physics_process(false)func transition():
passfunc _physics_process(_delta):
transition()
debug.text = name
Problem 1:
My sandworm trap should be able to detect what’s the distance between ‘it’ and the player and when the distance between them is less than 1, it will change state from Idle to Attack as shown in the Attack Script of Sandworm Trap:
func transition():
var distance = owner.direction.length()
print('distance ', distance)
if distance < 1:
get_parent().change_state(“Attack”)
But it didn’t. It just executes it anyway even if the player is so far away from it.
Attempts:
I debugged the distance and the distance always to zero and I don’t understand why? I suspect it must’ve something wrong with the owner variabele or is it because I have two owner
variable used within one game scene. What I mean by that was I duplicated the boss in this video:
and I also used the owner
variable for that and another owner for my sandwormTrap.
Problems 2:
I can’t extend a script named Arrow_Attack.gd to my ArrowTrap Attack State, it just created this:
NO IDEA WHAT THIS IS
Attempts:
I suspect it might have been I created the Script for FiniteStateArrow and the state script another folder, so the file path to those Scripts is:
res://New folder/Arrow_State.gd
res://New folder/Arrow_Trap.gd
res://New folder/FiniteStateArrow.gd
The file path to the ArrowTrap scene is:
res://arrow_trap.tscn
Any help would be great thanks!