From 9e3f0fc34a77d9bf9bfd124d8a97bfb6a0fd5b6b Mon Sep 17 00:00:00 2001 From: snoweuph Date: Fri, 3 Feb 2023 15:17:51 +0100 Subject: [PATCH] Made Enemy AI Follow - added a Threshold of a Distance it Should keep --- Scenes/Test Scene.tscn | 49 +++++++++-------------- Scripts/Enemy/EnemyController.gd | 67 ++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 52 deletions(-) diff --git a/Scenes/Test Scene.tscn b/Scenes/Test Scene.tscn index cd09feb..d6f2edc 100644 --- a/Scenes/Test Scene.tscn +++ b/Scenes/Test Scene.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=8 format=3 uid="uid://yitiyfwr4txh"] +[gd_scene load_steps=6 format=3 uid="uid://yitiyfwr4txh"] [ext_resource type="TileSet" uid="uid://bf1eb4aogv8ru" path="res://Assets/Tilesets/colony.tres" id="2"] [ext_resource type="Texture2D" uid="uid://dp4tdg3fxe5bf" path="res://Assets/Textures/color_cube.png" id="2_0flm2"] @@ -6,27 +6,6 @@ [ext_resource type="Texture2D" uid="uid://dx5k5qa1pwbfl" path="res://Assets/Textures/basic_enemy.png" id="4_4sn7h"] [ext_resource type="Script" path="res://Scripts/Enemy/EnemyController.gd" id="5_5xgcv"] -[sub_resource type="RectangleShape2D" id="RectangleShape2D_m15tu"] -size = Vector2(5, 5) - -[sub_resource type="GDScript" id="GDScript_xkf0t"] -script/source = "extends Node -enum STATES { - Partroling, - Targeting -} -@export var sees := STATES.Partroling - -# Called when the node enters the scene tree for the first time. -func _ready(): - pass # Replace with function body. - - -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta): - pass -" - [node name="Test Scene" type="Node2D"] [node name="TileMap" type="TileMap" parent="."] @@ -46,6 +25,10 @@ speed = 100 [node name="Sprite2D" type="Sprite2D" parent="Player"] texture = ExtResource("2_0flm2") +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Player"] +position = Vector2(-2, -2) +polygon = PackedVector2Array(-1, 0, 0, -1, 4, -1, 5, 0, 5, 4, 4, 5, 0, 5, -1, 4) + [node name="Camera2D" type="Camera2D" parent="Player"] zoom = Vector2(8, 8) position_smoothing_enabled = true @@ -54,20 +37,24 @@ drag_vertical_enabled = true editor_draw_limits = true editor_draw_drag_margin = true -[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"] -shape = SubResource("RectangleShape2D_m15tu") - -[node name="Enemy" type="Sprite2D" parent="." node_paths=PackedStringArray("ray")] -z_index = 1 -position = Vector2(237, 46) -rotation = 2.04581 -texture = ExtResource("4_4sn7h") +[node name="Enemy" type="RigidBody2D" parent="." node_paths=PackedStringArray("ray")] +position = Vector2(298, 42) +rotation = 2.93722 +gravity_scale = 0.0 +linear_damp = 5.0 script = ExtResource("5_5xgcv") ray = NodePath("RayCast2D") debug_vision = true +[node name="Sprite2D" type="Sprite2D" parent="Enemy"] +z_index = 1 +texture = ExtResource("4_4sn7h") + +[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Enemy"] +position = Vector2(-2, -1.99998) +polygon = PackedVector2Array(-1, 0, 0, -1, 4, -1, 5, 0, 5, 4, 4, 5, 0, 5, -1, 4) + [node name="RayCast2D" type="RayCast2D" parent="Enemy"] target_position = Vector2(15, 0) collision_mask = 3 hit_from_inside = true -script = SubResource("GDScript_xkf0t") diff --git a/Scripts/Enemy/EnemyController.gd b/Scripts/Enemy/EnemyController.gd index 37167bc..287b1a4 100644 --- a/Scripts/Enemy/EnemyController.gd +++ b/Scripts/Enemy/EnemyController.gd @@ -1,33 +1,35 @@ -extends Node2D +extends RigidBody2D @export_group("Movement Properties") -@export var speed = 25 -@export var turn_speed = 25 +@export var speed := 100.0 +@export var turn_speed := 25.0 @export_group("Vision Properties") @export var ray : RayCast2D @export_flags_2d_physics var player_collision_layer := 2 -@export var max_view_distance := 50 -@export_range(0.0, 360.0) var angle_cone_of_vision : float = 120 -@export_range(0, 72) var sweeping_steps : int = 24 +@export var max_view_distance := 120.0 +@export_range(0.0, 360.0) var angle_cone_of_vision := 120.0 +@export_range(0, 72) var sweeping_steps := 34.0 @export var debug_vision := false +@export_group("Behaviour Properties") +@export var follow_keep_distance := 30.0 + enum STATES { IDLE, TARGETING } var state : STATES - -# Only used for Debugging purposes right now -var player_positions : Array +var target_positons : Array +var target_distance : float func _ready(): # Set Raycast into view Direction ray.target_position = Vector2(max_view_distance, 0) pass -func swipe_view(): +func swipe_view() -> Array: # Set Raycast to starting position ray.rotation_degrees = -angle_cone_of_vision / 2 @@ -35,7 +37,9 @@ func swipe_view(): var hit_angles : Array # Clear Player Positions Array - player_positions.clear() + target_positons.clear() + # Reset Targets distance to Infinity + target_distance = INF for step in sweeping_steps + 1: # Check Ray @@ -53,22 +57,27 @@ func swipe_view(): else: collision_layer = collider.get_collision_layer() - # Checking Collision Layer + # Break if No relevant Collision if collision_layer & player_collision_layer > 0: + # Checking Collision Layer hit_angles.append(ray.rotation_degrees) - player_positions.append(to_local(ray.get_collision_point())) + target_positons.append(to_local(ray.get_collision_point())) + + # Check distance + target_distance = min(target_distance, ray.get_collision_point().distance_to(self.global_position)) + # Rotate Ray ray.rotation_degrees += angle_cone_of_vision / sweeping_steps return hit_angles -func look_at_player(delta : float): +func look_at_player(delta : float) -> float: # Get All Angles at which the Player can be seen var hit_angles = swipe_view() # If The Player cant be seen, return and do nothing if hit_angles.size() <= 0: state = STATES.IDLE - return + return 0 state = STATES.TARGETING # Calculate Average Angle Of Player @@ -79,10 +88,27 @@ func look_at_player(delta : float): # Rotate towards Player, but limit it by rotation speed self.rotation_degrees += clampf(average_angle, -2 * PI * delta * turn_speed, 2 * PI * delta * turn_speed) + return average_angle + +func follow_player(angle : float): + if(target_distance > follow_keep_distance): + self.apply_central_force(Vector2.RIGHT.rotated(self.rotation).rotated(deg_to_rad(angle)) * speed) pass -func _physics_process(delta): - look_at_player(delta) + +func _physics_process(delta: float): + var angle := look_at_player(delta) + match state: + STATES.TARGETING: + follow_player(angle) + STATES.IDLE: + # Do Idle Stuff + print("Dam, Nice a pause, time for a Coffee") + pass + +func _process(delta: float): + if debug_vision: + queue_redraw() pass func _draw(): @@ -99,9 +125,8 @@ func _draw(): self.draw_arc(Vector2(), max_view_distance, deg_to_rad(-angle_cone_of_vision / 2), deg_to_rad(angle_cone_of_vision / 2), sweeping_steps + 1, Color.RED, 0.5, false) # Draw A Circle Around the Player if hes seen - if state == STATES.TARGETING: - for pos in player_positions: - self.draw_circle(pos, 4, Color.ORANGE_RED) - queue_redraw() + for pos in target_positons: + self.draw_circle(pos, 1, Color.RED) + pass