0 votes

I recently making AI behaviour for my FPS project, and I managed to make my enemy to chase my player character if player got too far away from enemy AI, and enemy AI will take cover by moving to the specific cover area if my player character move close enough to any of those enemies.

But I only managed to make them to use one cover area by moving toward it. I can make more individual cover area in the same scene and refer them separately in enemy AI script, but this will be inconvenient and may not work as I intended, as I want my enemy only choose to move to nearby cover.

Is there a way to group cover area and refers that group in enemy AI script?

Btw, here is my enemy AI code:

enum {IDLE, ALERT, CHASE, COVER}
var state = IDLE
var target = null
onready var cover_area = get_node("../CoverPoint") # get node called coverpoint

func _physics_process(delta: float) -> void:
    ...
    change_states(delta)

func _on_DetectionArea_body_entered(body):
    if body.name == "Player":
        target = body
        state = COVER

func _on_DetectionArea_body_exited(body):
    if body.name == "Player":
        if body.is_queued_for_deletion():
            target = null
            state = IDLE

func change_states(delta : float) -> void:
match state:
    ...
    CHASE:
        Chase(delta)
    COVER:
        Covering(delta)

func Chase(delta : float) -> void: # Chase player once get far away from enemy
    look_at(target.global_transform.origin, Vector3.UP)
    direction = (target.global_transform.origin - global_transform.origin).normalized()
    Gravity_velocity(delta)

func Covering(delta : float) -> void: # Will seek for cover and shoot at player if close enough
    if global_transform.origin.distance_to(cover_area.global_transform.origin) > 1:
        direction = (cover_area.global_transform.origin - global_transform.origin).normalized()
    else:
        direction = Vector3()
    look_at(target.global_transform.origin, Vector3.UP)
    Gravity_velocity(delta)

func Gravity_velocity(delta : float) -> void:
...
    elif state == CHASE:
    velocity = velocity.linear_interpolate(direction * acrobatics.mov_spd,
    acrobatics.accel * delta)
    if !attack_timer.is_stopped():
        attack_timer.stop()
    if global_transform.origin.distance_to(target.global_transform.origin) < rush_dist:
        state = COVER

elif state == COVER:
    velocity = velocity.linear_interpolate(direction * acrobatics.mov_spd,
    acrobatics.accel * delta) # direction towards nearby cover instead of target
    if attack_timer.is_stopped():
        attack_timer.start()
    if global_transform.origin.distance_to(target.global_transform.origin) > rush_dist:
        state = CHASE
Godot version Godot 3.2.3 stable
in Engine by (119 points)

1 Answer

+1 vote
Best answer

If your cover_area nodes are instanced through code

func ready():
    add_to_group("COVER")

if not for each cover_area node In the Node Dock on the groups tab type COVER then add

In your code
remove

onready var cover_area = get_node("../CoverPoint") # get node called coverpoint

change covering func to

# Will seek for cover and shoot at player if close enough
func Covering(delta : float) -> void: 
    var cover_areas = get_tree().get_nodes_in_group("COVER")
    var nearest_cover = cover_areas[0] #select first cover_area
    var nearest_pos = nearest_cover.global_transform.origin
    var position = global_transform.origin

    #find the nearest cover to this Ai's position
    for cover in cover_areas:
        var cover_pos = cover.global_transform.origin
        if position.distance_to(cover_pos) < position.distance_to(nearest_pos):
            nearest_cover = cover
            nearest_pos = cover_pos

    if position.distance_to(nearest_pos) > 1:
        direction = (nearest_pos - position).normalized()
    else:
        direction = Vector3()
    look_at(target.global_transform.origin, Vector3.UP)
    Gravity_velocity(delta)
by (4,972 points)
selected by

Good, now my enemy AI will always seek for a nearest cover from multiple cover points, thanks for responding with such a working method!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.