164 lines
5.6 KiB
GDScript
164 lines
5.6 KiB
GDScript
extends Actor
|
|
const PhysicsFunc = preload("res://src/Utilities/Physic/PhysicsFunc.gd")
|
|
|
|
onready var players = get_tree().get_nodes_in_group("player")
|
|
|
|
onready var vision_raycast: RayCast2D = $VisionRayCast
|
|
onready var orientation: RayCast2D = $Orientation
|
|
onready var feeler_raycast: RayCast2D = $FeelerRayCast
|
|
onready var nav_agent: NavigationAgent2D = $NavigationAgent2D
|
|
onready var tilemap: TileMap = $"../%TileMap"
|
|
onready var target_lost_timer: Timer
|
|
onready var update_navigation_timer: Timer
|
|
onready var rng = RandomNumberGenerator.new()
|
|
|
|
# Is given in blocks
|
|
export var vision_distance := 6.0
|
|
export var blindspot_angle := 20
|
|
export var loose_target_seconds := 3.0
|
|
export var patrolling := false
|
|
export var aggressive := true
|
|
export var acceleration := 50
|
|
export var patrolling_slowdown := 0.80
|
|
export var max_speed := 90
|
|
export var weight := 0.15
|
|
|
|
var path_direction: Vector2 = Vector2()
|
|
var previous_direction := Vector2()
|
|
var target: Object = null
|
|
var patrol_waypoints := []
|
|
var patrol_waypoint_index := 0
|
|
var next_waypoint: Vector2
|
|
var is_hurt := false
|
|
var has_reversed := false
|
|
var avoidance_raycasts := []
|
|
var slow_down_factor := 1.0
|
|
|
|
var detect_timer := 0.0
|
|
|
|
|
|
func _ready():
|
|
spawn_avoidance_raycasts(16, 20)
|
|
target_lost_timer = Timer.new()
|
|
target_lost_timer.set_one_shot(true)
|
|
target_lost_timer.connect("timeout", self, "lose_target")
|
|
add_child(target_lost_timer)
|
|
update_navigation_timer = Timer.new()
|
|
update_navigation_timer.connect("timeout", self, "update_navigation")
|
|
add_child(update_navigation_timer)
|
|
update_navigation_timer.start(0.3)
|
|
# TODO Hat immer den Spawn im Patrolpath
|
|
patrol_waypoints.append(global_position)
|
|
for waypoint in $PatrolPath.get_children():
|
|
patrol_waypoints.append(waypoint.global_position)
|
|
pass
|
|
|
|
func searching() -> Vector2:
|
|
slow_down_factor = patrolling_slowdown
|
|
if(aggressive && detect_timer > 0.33):
|
|
detect_player()
|
|
detect_timer = 0.0
|
|
if(patrolling && nav_agent.is_target_reached()):
|
|
next_waypoint = get_next_patrol_target()
|
|
update_navigation()
|
|
elif(patrolling):
|
|
next_waypoint = patrol_waypoints[patrol_waypoint_index]
|
|
else:
|
|
# Spawn location
|
|
return patrol_waypoints[0]
|
|
return nav_agent.get_next_location()
|
|
|
|
func get_next_patrol_target() -> Vector2:
|
|
var waypoint_count = patrol_waypoints.size()
|
|
for wp in patrol_waypoints:
|
|
if next_waypoint == wp:
|
|
patrol_waypoint_index = patrol_waypoint_index + 1 if patrol_waypoint_index < waypoint_count - 1 else 0
|
|
return patrol_waypoints[patrol_waypoint_index]
|
|
patrol_waypoint_index = 0
|
|
return patrol_waypoints[0]
|
|
|
|
func hunting() -> Vector2:
|
|
slow_down_factor = 1.0
|
|
if(detect_timer > 0.33):
|
|
detect_player()
|
|
detect_timer = 0.0
|
|
next_waypoint = players[0].global_position - Vector2(0,9)
|
|
return nav_agent.get_next_location()
|
|
|
|
func detect_player() -> void:
|
|
var player
|
|
if(players.empty()):
|
|
# print("no player found")
|
|
return
|
|
player = players[0]
|
|
#TODO Depends on height of blobby sprite since blobbys bottom and not his middle is on y=0
|
|
vision_raycast.cast_to = (player.global_position - global_position - Vector2(0,9)).normalized() * 24 * vision_distance
|
|
var ray_angle_to_facing = vision_raycast.cast_to.angle_to(orientation.cast_to)
|
|
vision_raycast.force_raycast_update()
|
|
var collider = vision_raycast.get_collider()
|
|
if(abs(ray_angle_to_facing) < PI/2-deg2rad(blindspot_angle) && collider != null && collider.is_in_group("player")):
|
|
target_lost_timer.stop()
|
|
target = collider
|
|
# print("target found")
|
|
elif(target != null && target_lost_timer.is_stopped()):
|
|
target_lost_timer.start(loose_target_seconds)
|
|
|
|
func execute_movement(delta: float) -> void:
|
|
detect_timer += delta
|
|
var next_direction = lerp(previous_direction, path_direction - global_position, 0.5)
|
|
previous_direction = next_direction
|
|
orientation.cast_to = Vector2(sign(next_direction.x),0)*50
|
|
var avoidance_obstacle_distance = average_collision_vector(avoidance_raycasts)
|
|
next_direction = next_direction.normalized() + avoidance_obstacle_distance.rotated(PI).normalized()
|
|
# TODO Make parameters more tunable
|
|
velocity = move_and_slide(PhysicsFunc.two_step_euler_vec(velocity, next_direction.normalized() * acceleration * slow_down_factor, weight, delta)
|
|
,FLOOR_NORMAL, false, 4, 0.785398,false)
|
|
velocity = velocity/max((velocity.length()/(max_speed*slow_down_factor)),1)
|
|
|
|
func average_collision_vector(var raycasts: Array) -> Vector2:
|
|
var total_distances = Vector2()
|
|
for raycast in raycasts:
|
|
if !raycast.is_colliding():
|
|
continue
|
|
var collision_point = self.to_local(raycast.get_collision_point())
|
|
total_distances += collision_point
|
|
return total_distances/raycasts.size()
|
|
|
|
func spawn_avoidance_raycasts(var raycount: int, var length: float = 24) -> void:
|
|
var direction: float = 0
|
|
while direction <= 2*PI:
|
|
var raycast: RayCast2D = RayCast2D.new()
|
|
raycast.enabled = true
|
|
raycast.exclude_parent = true
|
|
raycast.collide_with_areas = true
|
|
raycast.collide_with_bodies = true
|
|
# Layers 4, 5 & 6
|
|
raycast.collision_mask = 56
|
|
raycast.cast_to = Vector2(length, 0).rotated(direction)
|
|
add_child(raycast)
|
|
avoidance_raycasts.append(raycast)
|
|
direction += (2*PI)/raycount
|
|
|
|
# Checks the feeler ray for collisions and returns collision or null
|
|
func check_feeler(v: Vector2, _offset = Vector2(0,0)) -> Object:
|
|
var prev_position = feeler_raycast.position
|
|
feeler_raycast.position += _offset
|
|
feeler_raycast.cast_to = v
|
|
feeler_raycast.force_raycast_update()
|
|
feeler_raycast.position = prev_position
|
|
return feeler_raycast.get_collider()
|
|
|
|
func lose_target() -> void:
|
|
# print("flyer target lost")
|
|
target = null
|
|
|
|
func update_navigation() -> void:
|
|
nav_agent.set_target_location(next_waypoint)
|
|
|
|
func die() -> void:
|
|
levelState.kills += 1
|
|
queue_free()
|
|
|
|
func get_facing_direction() -> float:
|
|
return orientation.cast_to.x
|