Godot Engine – Enemy Behavior Script

I have created a script for my “Enemy” scene, for an enemy NPC. Admittedly, I used AI to generate most of this, however, it is clearly far from perfect or I am doing something wrong.

Enemy Script:

extends CharacterBody2D

# Enemy movement and behavior settings
@export var speed = 100  # Enemy walking speed
@export var detection_range = 150  # Range within which the enemy can detect the player
@export var attack_range = 50  # Range within which the enemy can attack the player
@export var stop_chase_range = 300  # Range beyond which the enemy stops chasing the player
@export var idle_time = 1.0  # Time to spend in idle state
@export var rotation_speed = 5.0  # Speed of rotation for smooth turning

# State management
enum State {IDLE, WALK, CHASE, ATTACK}
var current_state = State.IDLE
var target_position = Vector2.ZERO

# References
@onready var animated_sprite = $AnimatedSprite2D
@onready var raycast = $RayCast2D

# Timer for idle state
var idle_timer = 0.0

# Player reference
var player = null

func _ready():
    # Initialize the player reference
    player = get_parent().get_node("Player")  # Adjust the path based on your scene structure
    _pick_new_target_position()  # Pick an initial target position for patrolling
    raycast.enabled = true  # Enable the RayCast2D
    raycast.target_position = Vector2(150, 0)  # Set the target position for the ray (150 pixels forward)
    raycast.add_exception(self)  # Avoid colliding with itself

func _physics_process(delta):
    # Check for player proximity using RayCast2D
    _check_player_proximity()

    # Handle enemy behavior based on the current state
    match current_state:
        State.IDLE:
            _handle_idle_state(delta)
        State.WALK:
            _handle_walk_state(delta)
        State.CHASE:
            _handle_chase_state(delta)
        State.ATTACK:
            _handle_attack_state(delta)

# State Handling Functions

func _handle_idle_state(delta):
    # Increment the idle timer and transition to walking state if time is up
    idle_timer += delta
    if idle_timer >= idle_time:
        current_state = State.WALK
        idle_timer = 0.0
        _pick_new_target_position()  # Choose a new position to walk towards

    animated_sprite.play("Idle")  # Play idle animation

func _handle_walk_state(delta):
    # Move the enemy towards the target position
    var direction = (target_position - global_position).normalized()
    velocity = direction * speed
    move_and_slide()  # Apply the velocity to move the enemy

    animated_sprite.play("Walk")  # Play walking animation

    # Rotate smoothly towards the target direction
    _rotate_towards_direction(direction, delta)

    # If the enemy reaches the target position, switch to idle state
    if global_position.distance_to(target_position) < 5:
        current_state = State.IDLE

func _handle_chase_state(delta):
    if player:
        # Move the enemy towards the player
        var direction = (player.global_position - global_position).normalized()
        velocity = direction * speed * 1.5  # Increase speed while chasing
        move_and_slide()  # Apply the velocity to move the enemy

        animated_sprite.play("Walk")  # Play walking animation

        # Rotate smoothly towards the player
        _rotate_towards_direction(direction, delta)

        # Transition to attack state if close enough to the player
        if global_position.distance_to(player.global_position) < attack_range:
            current_state = State.ATTACK

        # Stop chasing if the player is too far away or blocked
        if global_position.distance_to(player.global_position) > stop_chase_range or !_can_see_player():
            current_state = State.IDLE

func _handle_attack_state(_delta):
    animated_sprite.play("Idle")  # Play idle animation (could be replaced with attack animation)
    # Implement attack logic here (e.g., damage player)

    # If the player moves out of attack range, switch back to chase state
    if global_position.distance_to(player.global_position) > attack_range:
        current_state = State.CHASE

# Helper Functions

func _check_player_proximity():
    # Check if the player is within detection range and has line of sight
    if player:
        # Update the RayCast2D's target position to the player
        raycast.target_position = (player.global_position - global_position).normalized() * detection_range

        if _can_see_player():
            # Player detected, switch to chase state
            if current_state != State.CHASE:
                print("Chasing the player!")  # Debug: Print when starting the chase
            current_state = State.CHASE

func _can_see_player():
    return raycast.is_colliding() and raycast.get_collider() == player

func _pick_new_target_position():
    # Choose a random position nearby for the enemy to walk towards
    var random_distance = randf_range(50, 150)  # Random distance for wandering
    var random_angle = randf() * 2 * PI  # Random angle for direction
    target_position = global_position + Vector2(cos(random_angle), sin(random_angle)) * random_distance

func _rotate_towards_direction(direction: Vector2, delta: float):
    # Calculate the target angle from the direction
    var target_angle = direction.angle()

    # Smooth rotation using angular interpolation (lerp_angle)
    animated_sprite.rotation = lerp_angle(animated_sprite.rotation, target_angle + PI / 2, rotation_speed * delta)

Here are my scene setups:

“Main” Scene:
-Main_tscn (Node2D)
____-Player (CharacterBody2D): Instance: res://Player.tscn
____-ColorRect (ColorRect)
____TileMap (TileMap)
________-LightOccluder2D (LightOccluder2D)
________-LightOccluder2D2 (LightOccluder2D)
________-LightOccluder2D3 (LightOccluder2D)
____-Enemy (CharacterBody2D) res://Enemy.tscn
____-StaticBody2D (StaticBody2D)
________-CollisionPolygon2D (CollisionPolygon2D)
________-CollisionPolygon2D2 (CollisionPolygon2D)
________-CollisionPolygon2D3 (CollisionPolygon2D)

“Player” Scene:
-Player (CharacterBody2D)
____-AnimatedSprite2D (AnimatedSprite2D)
____-CollisionShape2D (CollisionShape2D)
____-Camera2D (Camera2D)
____-PointLight2D (PointLight2D)

“Enemy” Scene:
-Enemy (CharacterBody2D)
____-AnimatedSprite2D (AnimatedSprite2D)
____-CollisionShape2D (CollisionShape2D)
____-RayCast2D (RayCast2D)

The enemy seems to work fine, however, I have moments where the enemy will randomly start chasing the wall and will not stop. I cannot explain it.

The idea is that the enemy will wander about, until it sees the player then it will chase. If it loses line of sight due to a wall (Walls set by StaticDody2D and CollisionPolygon2D), then it should stop chasing.

Somebody help!

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật