Hello,
I am really new to programming and godot and would like a little guidance on how to properly implement something.
So, what you see below is the script for a character. my problem is regarding the targeting system for my character. the way it works right now is that it detects when a character of another faction enters an area2D and append it to a target_list (see func on_body_entered). if the target leaves the area2D, it removes it from the target_list. My problem lies in the fact that when a target dies, it does not trigger the on_body_exited function, when the character tries to attack the target again, the node is not there anymore since the target used the function queue_free(). Since i can have many character fighting all at once (rts style), i do not want to send the death information only to the character that killed the target but to everyone that might see the target.
I thought of using the emit_signal but since it says :" The signal must exist, so it should be a built-in signal of this class or one of its parent classes" I do not think i can use it for what i want to achieve unless i create a script in the main scene node.. which seems like a weird thing to do.. right now i duck taped the code and move the character somewhere if it dies to trigger the on_body_exited function.
By the way, if you have guidelines for ways to improve my code let me know, its my first learning project 🙂. Especially around the fact that I duck taped the wander function with a mouvement_imprecision_allowance (rounding the wander_target value did not fix the problem) since the character could not always move to the exact wander_target position..
extends KinematicBody2D
onready var detection_circle := $DetectionArea
onready var detection_circle_shape := $DetectionArea/DetectionCircle
onready var attack_timer := $AttackTimer
onready var health_bar := $ProgressBar
export var faction := "player"
export var character_max_speed := 100.0
export var detection_circle_dimension := 200
export var character_attack_range := 35
export var character_damage := 10
export var character_attack_speed := 1
export var maximum_health := 100
var wander_target = Vector2(0,0)
var target_list := []
var target : Node = null
var current_health := 0
var velocity = 0.0
var mouvement_imprecision_allowance := 10
func _ready():
randomize()
##sets the detection circle diameter
detection_circle_shape.shape.radius = detection_circle_dimension
##connects the detection circle to send signal when entered and exited
detection_circle.connect("body_entered",self,"on_body_entered")
detection_circle.connect("body_exited",self,"on_body_exited")
##sets the attack speed and connect it to the dealing damage function
attack_timer.wait_time = character_attack_speed
attack_timer.connect("timeout", self, "dealing_damage")
##sets the health and health bar values
health_bar.max_value = maximum_health
current_health = maximum_health
health_bar.value = current_health
##sets a starting wander target position
set_new_wander_target()
func _process(delta):
##checks if there is a valid ennemy target
if target == null:
wander()
##sets the character state to attack if target in range
elif check_if_in_attack_range(target) == true:
character_attack_target()
return
else:
move_character_to(target)
position += move_and_slide(velocity * delta)
func on_body_entered(body : Node) -> void:
##checks if the body entered is in the facton of the character
#print("Detection")
if body.faction == faction:
return
##adds the target to the possible target array and set the target
target_list.append(body)
target = target_list[0]
select_target()
func on_body_exited(body: Node) -> void:
var index = target_list.find(body)
target_list.remove(index)
if target_list:
select_target()
else:
target = null
set_new_wander_target()
func move_character_to(target_node : Node) -> void:
if target_node == null:
return
elif is_instance_valid(target) == false:
target_list[0].erase()
var direction_to_target = (target_node.position - self.position).normalized()
velocity = direction_to_target * character_max_speed
func check_if_in_attack_range(body : Node) -> bool:
var vector_to_target = (position - target.position).abs()
var distance_to_target = vector_to_target.length()
if distance_to_target <= character_attack_range:
return true
return false
func character_attack_target() -> void:
select_target()
if attack_timer.is_stopped() == true :
attack_timer.start()
#print("timer start")
return
func dealing_damage() -> void:
if check_if_in_attack_range(target) == true:
target.recieving_damage(character_damage)
else:
return
func recieving_damage(damage : int) -> void:
current_health -= damage
if current_health <= 0:
death()
else:
health_bar.value = current_health
func select_target() -> void:
if target == null:
return
if is_instance_valid(target) == true:
target = target_list[0]
else:
target_list[0].erase()
select_target()
## duck taped with position to ensure it exits the visible radius
func death() -> void:
set_process(false)
position = Vector2(-10000,-10000)
queue_free()
pass
func wander() -> void:
var vector_to_wander_target = self.position - wander_target
if vector_to_wander_target.length() < mouvement_imprecision_allowance:
set_new_wander_target()
var direction_to_target = (wander_target - self.position).normalized()
velocity = direction_to_target * character_max_speed
func set_new_wander_target() -> void:
wander_target = get_viewport_rect().size
wander_target = Vector2(wander_target.x * randf(), wander_target.y* randf())
print(wander_target)