How to make enemy ambushing player

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By lucasfazzi

I was wondering a way to make a enemy that “ambushes” the player. Is not a real ambush that make a lot of decisions based on player behavior to proper tricks him, just a AI that follows the player by the back besides the front or global position.

I already have a default enemy that follows player with this basic AI:

extends KinematicBody2D

var ENEMY_1_LIFE = 100
var RAND_SPEED = 0

onready var player = get_parent().get_node("player")
onready var enemy_1_FOV = false

func _ready():
	get_node("fov_enemy_1").add_to_group("fov_enemies")
	get_node("enemy_1_hit").add_to_group("enemy_1_hit")
	RAND_SPEED = randi()%320+100

func _on_fov_enemy_1_body_entered(body):
	if body == player:
		enemy_1_FOV = true
	else:
		null

func _physics_process(delta):
	if enemy_1_FOV == true:
		var vec_to_player = player.global_position - global_position
		vec_to_player = vec_to_player.normalized()
		move_and_collide(vec_to_player * RAND_SPEED * delta)
	else:
		null
   
func _on_enemy_1_hit_area_entered(area):
	if area.is_in_group("bullet_1_hit_group"):
		ENEMY_1_LIFE -= 50
	else:
		null
	if ENEMY_1_LIFE == 0:
		destroy_enemy_1()

func destroy_enemy_1():
	queue_free()

You can see that enemy follows player with a global position in relation with player. I was wondering if it’s possible to adapt this to make enemy following the player by the back when it approachs by certain distance.
I make some sketch to exemplify:

example

thanks guys

I make some tests, it’s a bit amateur but it works.

I will put here to share, so anybody can test or refine.

  1. I put two areas attached to player on a triangular angle:

player area

  1. then i re-write the code with two behaviors: first step, when player go to enemy FOV, enemy walks with one of this areas (randi); second when enemy colides with this areas, then the movement changes and he start to follow player by global position; code:
    extends KinematicBody2D

onready var player = get_parent().get_node("player")
onready var player_ambush_1 = get_parent().get_node("player/player_catch1")
onready var player_ambush_2 = get_parent().get_node("player/player_catch2")
var ENEMY_4_LIFE = 150
var RAND_SPEED = 0
var vec_to_player_ambush_1
var vec_to_player_ambush_2
var randi_ambush = 0
var enemy_4_FOV = false
var enemy_4_get_position = false

func _ready():
	global.enemy_4 = self
	get_node("enemy_4_fov").add_to_group("fov_enemies")
	get_node("enemy_4_hit").add_to_group("enemy_4_hit")
	RAND_SPEED = randi()%280+200

func _on_enemy_4_fov_body_entered(body):
	if body == player:
		enemy_4_get_position = true
		randi_ambush = randi()%2+1
	else:
		null

func _physics_process(delta):
	if randi_ambush == 1 and enemy_4_get_position == true:
		vec_to_player_ambush_1 = player_ambush_1.global_position - global_position
		vec_to_player_ambush_1 = vec_to_player_ambush_1.normalized()
		move_and_collide(vec_to_player_ambush_1 * RAND_SPEED * delta)
	if randi_ambush == 2 and enemy_4_get_position == true:
		vec_to_player_ambush_2 = player_ambush_2.global_position - global_position
		vec_to_player_ambush_2 = vec_to_player_ambush_2.normalized()
		move_and_collide(vec_to_player_ambush_2 * RAND_SPEED * delta)
	else:
		null
	if randi_ambush == 1 and enemy_4_get_position == false:
		var vec_to_player = player.global_position - global_position
		vec_to_player = vec_to_player.normalized()
		move_and_collide(vec_to_player * RAND_SPEED * delta)
	if randi_ambush == 2 and enemy_4_get_position == false:
		var vec_to_player = player.global_position - global_position
		vec_to_player = vec_to_player.normalized()
		move_and_collide(vec_to_player * RAND_SPEED * delta)

func _on_enemy_4_area_entered_player_position_area_entered(area):
	if area.is_in_group("player_catches"):
		enemy_4_get_position = false
	else:
		null

func _on_enemy_4_fov_body_exited(body):
	if body == player:
		enemy_4_get_position = true
		randi_ambush = randi()%2+1

	else:
		null

func _on_enemy_4_hit_area_entered(area):
	if area.is_in_group("bullet_1_hit_group"):
		ENEMY_4_LIFE -= 50
		check_enemy_4_life()

	if area.is_in_group("player_hit"):
		enemy_4_get_position = true
		randi_ambush = randi()%2+1
	else:
		null

func check_enemy_4_life():
	if ENEMY_4_LIFE == 0:
		destroy_enemy_4()
	else:
		null

func destroy_enemy_4():
	queue_free()

With this way, the enemy can make something like this:

https://youtu.be/Bgk3GP0Ue_M

I’m still have problems when enemy hit player by the front and get stuck, but is a huge progress.

lucasfazzi | 2019-02-09 16:57