#Enemy not working

19 messages · Page 1 of 1 (latest)

torn basalt
#

Hi im trying to get the enemy to lock onto my player and chase him but he always stops running and then keeps playing the attack animation. heres a video of it

native stone
torn basalt
#

extends CharacterBody2D

Movement

@export var speed := 150
var player_chase := false
var player : Node2D = null

Combat

@export var attack_cooldown := 1.0
@export var attack_range := 80.0
@export var attack_damage := 10
@export var detection_range := 300.0

Animation States

enum AnimState {IDLE, RUN, ATTACK}
var current_anim := AnimState.IDLE
var can_attack := true
var is_attacking := false

Nodes

@onready var sprite := $AnimatedSprite2D
@onready var detection_area := $DetectionArea
@onready var attack_hitbox := $AttackHitbox
@onready var cooldown_timer := $AttackCooldownTimer

func _ready():
add_to_group("enemies")

# Configure collision shapes
if detection_area.get_child_count() > 0:
    var shape = detection_area.get_child(0)
    if shape is CollisionShape2D and shape.shape is CircleShape2D:
        shape.shape.radius = detection_range / 2

# Signal connections
detection_area.body_entered.connect(_on_player_detected)
detection_area.body_exited.connect(_on_player_lost)
attack_hitbox.body_entered.connect(_on_attack_connected)
sprite.animation_finished.connect(_on_anim_finished)
cooldown_timer.timeout.connect(_on_cooldown_ended)
#

func _physics_process(delta):
if is_attacking:
return # Freeze during attack

handle_movement()
handle_attack()
move_and_slide()

func handle_movement():
if not player_chase or not is_instance_valid(player):
velocity = Vector2.ZERO
set_animation(AnimState.IDLE)
return

var direction = (player.global_position - global_position).normalized()
velocity = direction * speed

# Flip sprite based on direction
sprite.flip_h = direction.x < 0 if direction.x != 0 else sprite.flip_h

# Only set run animation if not attacking
if not is_attacking:
    set_animation(AnimState.RUN if velocity.length() > 5 else AnimState.IDLE)

func handle_attack():
if not player_chase or not can_attack or not is_instance_valid(player):
return

var distance = global_position.distance_to(player.global_position)
if distance <= attack_range:
    start_attack()

func start_attack():
is_attacking = true
can_attack = false
velocity = Vector2.ZERO
set_animation(AnimState.ATTACK)

# Play attack sound if available
if has_node("AttackSound"):
    $AttackSound.play()

func set_animation(state: AnimState):
if current_anim == state:
return

current_anim = state

match state:
    AnimState.IDLE:
        sprite.play("idle")
    AnimState.RUN:
        sprite.play("run")
    AnimState.ATTACK:
        sprite.play("attack")
#

func _on_player_detected(body: Node2D):
if body.is_in_group("player"):
player = body
player_chase = true
print("Player detected!")

func _on_player_lost(body: Node2D):
if body.is_in_group("player"):
player_chase = false
player = null
print("Player lost")

func _on_attack_connected(body: Node2D):
if is_attacking and body.is_in_group("player"):
if body.has_method("take_damage"):
body.take_damage(attack_damage)
print("Hit player for ", attack_damage, " damage")

func _on_anim_finished():
if sprite.animation == "attack":
is_attacking = false
cooldown_timer.start(attack_cooldown)

    # Return to chasing if player still in range
    if player_chase and) is_instance_valid(player):
        var distance = global_position.distance_to(player.global_position)
        if distance <= attack_range:
            start_attack()
        else:
            set_animation(AnimState.RUN)

func _on_cooldown_ended():
can_attack = true
print("Attack ready"

native stone
#

The enemy is getting stuck in the attack state because once is_attacking is set to true, there's no mechanism to set it back to false after the attack animation finishes.

torn basalt
#

ah so how should i fix it

native stone
#

nevermind; its this:

func _physics_process(delta):
    if is_attacking:
        return  # Freeze during attack```

this returns true always
#

replace with this:

func _physics_process(delta):
    # Always handle movement and attacks
    handle_movement()
    if not is_attacking:  # Only check for new attacks if not already attacking
        handle_attack()
    move_and_slide()  # Always call this for proper physics```
#

probably change handle_movement() to this aswell:

func handle_movement():
    if is_attacking:
        # Stop moving during attack but don't return
        velocity = Vector2.ZERO
        return
        
    if not player_chase or not is_instance_valid(player):
        velocity = Vector2.ZERO
        set_animation(AnimState.IDLE)
        return```
torn basalt
#

thank you it finally works

native stone
#

no problem.

torn basalt
#

hi sorry small issue he wont stop attacking even when he should be runnignm do u know how to fix

native stone
torn basalt
#

hes attacking and moving at the same time and he kidn ajust bypasses the laws of physics and flys

native stone
#

Make sure your enemy scene has:

A CollisionShape2D for the body
The enemy is on a floor/ground with collision
The DetectionArea and AttackHitbox are properly configured

One moment, Ill just give you the full script.

#

I changed handle_attack() to only be called when not attacking, horizontal movement should be stopped but not gravity.

Seperated horizontal and vertical velocity so the enemy stops flying

Changed the state flow so it wont try to move and attack.