Hello, I’m doing a game where I have some slimes as enemies, but when I hit them, their lifes are connected and all instances get hit. Here’s the code for the spawn and the slime, in that order.
extends Node3D
@onready var spawns = $map/Spawns
@onready var navigation_region = $map/NavigationRegion3D
var slime = load("res://scenes/slime.tscn")
var instance
# Called when the node enters the scene tree for the first time.
func _ready():
randomize()
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
func _get_random_child(parent_node):
var random_id = randi() % parent_node.get_child_count()
return parent_node.get_child(random_id)
func _on_slime_spawner_timer_timeout():
var spawn_point = _get_random_child(spawns).global_position
instance = slime.instantiate()
instance.position = spawn_point
navigation_region.add_child(instance)
print(instance, ": ", instance.health)
extends CharacterBody3D
var player = null
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
var state_machine
var health = 100
const SPEED = 2.0
const ATTACK_RANGE = 2.5
@export var player_path := "/root/World/map/NavigationRegion3D/Player"
@onready var health_bar = $Node/slime/SubViewport/HealthBar3D
@onready var nav_agent = $NavigationAgent3D
@onready var anim_tree = $AnimationTree
func _ready():
player = get_node(player_path)
player.connect("attacking", _take_damage)
state_machine = anim_tree.get("parameters/playback")
func _physics_process(delta):
health_bar.value = health
if health <= 0:
queue_free()
if not is_on_floor():
velocity.y -= gravity * delta
func _process(delta):
velocity = Vector3.ZERO
match state_machine.get_current_node():
"walk":
# Navigation
nav_agent.set_target_position(player.global_transform.origin)
var nex_nav_point = nav_agent.get_next_path_position()
velocity = (nex_nav_point - global_transform.origin).normalized() * SPEED
# Rotation
#velocity.y = lerp_angle(rotation.y, atan2(-velocity.x, -velocity.z), delta * 10)
look_at(Vector3(global_position.x + velocity.x, global_position.y, global_position.z + velocity.z), Vector3.UP)
"Attack":
# Rotation
look_at(Vector3(player.global_position.x, player.global_position.y, player.global_position.z), Vector3.UP)
# Conditions
anim_tree.set("parameters/conditions/attack", _target_in_range())
anim_tree.set("parameters/conditions/run", !_target_in_range())
move_and_slide()
func _target_in_range():
return global_position.distance_to(player.global_position) < ATTACK_RANGE
func _hit_finished():
if global_position.distance_to(player.global_position) < ATTACK_RANGE + 1.0:
var dir = global_position.direction_to(player.global_position)
player.hit(dir)
func _take_damage():
health -= 10
print(health)
Don’t connect signal like this, otherwise all instance connected same time, try use Area2D Node to detect the enemy who needs take damage then connect signal when entered in area2d and disconnect when exit
The area2d(in my case is 3d) that you are talking is the collision for the attack? If it is, how do i connect them? my player is in a different scene. But thank you for your help!
to deal damage to the enemy try this:
create a ray cast if you don’t have one for attack range
inside if Input.is_action_just_pressed("attack"): add this few lines
var enemy := [YOUR_ATTACK_RAY_CAST].get_collider() as Enemy
if enemy:
enemy._take_damage()
also, add class_name Enemy in the first line of your enemy script so you can detect it from your player script