Skip to content

Commit

Permalink
Better AI infinite world size
Browse files Browse the repository at this point in the history
  • Loading branch information
Trey2k committed Oct 16, 2023
1 parent 0ef62cd commit c14fb5d
Show file tree
Hide file tree
Showing 18 changed files with 338 additions and 124 deletions.
7 changes: 7 additions & 0 deletions project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ spaceship_weapons_down={
]
}

[layer_names]

2d_physics/layer_1="Player"
2d_physics/layer_2="Enemy"
2d_physics/layer_3="Items"
2d_physics/layer_4="Vision"

[rendering]

textures/canvas_textures/default_texture_filter=0
Expand Down
4 changes: 3 additions & 1 deletion scenes/projectiles/projectile.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ enum ProjectileType {PHASER, MISSILE}

var velocity: Vector2 = Vector2.ZERO
var origin: Ship
var origin_position: Vector2

func _ready() -> void:
var timer = Timer.new()
Expand All @@ -20,6 +21,7 @@ func _ready() -> void:
add_child(timer)
timer.start(life_span)
body_entered.connect(self._on_body_entered)
origin_position = position

func _physics_process(delta: float) -> void:
if GameState.paused:
Expand All @@ -30,7 +32,7 @@ func _physics_process(delta: float) -> void:

func _on_body_entered(body: Node2D) -> void:
if body is Ship && body != origin:
body.apply_damage(damage)
body.apply_damage(origin_position, damage)
queue_free()

func _on_area_entered(area: Area2D) -> void:
Expand Down
163 changes: 125 additions & 38 deletions scenes/ships/enemy/enemy.gd
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
class_name Enemy
extends Ship

@export var vision_cone: VisionCone
@export var attack_cooldown: float = 1
@export var patrol_distance: int = 250

enum EnemyAIState { PATROL, SEARCH, ATTACK_PLAYER }
var ai_state: EnemyAIState = EnemyAIState.PATROL

var _world: World
var _player: Player
var _home: Vector2

var patrol_point: Vector2
var patrol_home_set: bool
var patrol_point_set: bool

var search_point_of_interest: Vector2
var search_looking_around: bool
var search_original_rotation: float
var search_halfway: bool
var search_direction: int

enum EnemyAIState { MOVE_TO_PLAYER, AIM_AT_PLAYER, FIRE_AT_PLAYER }
var ai_state: EnemyAIState = EnemyAIState.MOVE_TO_PLAYER
var attack_cooldown_timer: Timer

func _ship_ready() -> void:
_world = GameState.world
Expand All @@ -14,54 +31,124 @@ func _ship_ready() -> void:
_player = GameState.player
if _player == null:
_player = await EventBus.player_ready

_home = position
vision_cone.body_entered.connect(self._on_vision_cone_body_enter)
vision_cone.body_exited.connect(self._on_vision_cone_body_exited)

attack_cooldown_timer = Timer.new()
attack_cooldown_timer.one_shot = true
add_child(attack_cooldown_timer)

func _on_vision_cone_body_enter(body: Node2D):
if body is Player:
ai_state = EnemyAIState.ATTACK_PLAYER

func _on_vision_cone_body_exited(body: Node2D):
if body is Player:
ai_state = EnemyAIState.SEARCH
search_point_of_interest = body.position
search_looking_around = false

func ship_destroyed() -> void:
EventBus.enemy_destroyed.emit(self)
queue_free()

func damage_from(origin: Vector2) -> void:
if ai_state == EnemyAIState.PATROL || ai_state == EnemyAIState.SEARCH:
ai_state = EnemyAIState.SEARCH
search_point_of_interest = origin
search_looking_around = false

func update_input():
if GameState.paused:
return

# all input values are floats from -1 to 1
yaw = 0
thrust = 0
strafe = 0

#var target_yaw: float = position.angle_to(_player.position)
var angle_to_player: float = find_player_angle()
var angle_difference: float = angle_to_player - rotation
if abs(angle_difference) > deg_to_rad(10):
ai_state = EnemyAIState.AIM_AT_PLAYER

match ai_state:
EnemyAIState.MOVE_TO_PLAYER:
var input_vector: Vector2 = Vector2(0, -1).rotated(angle_difference)
EnemyAIState.PATROL:
if abs(position.distance_to(_home)) > 250 && !patrol_home_set:
patrol_point = _home
patrol_home_set = true
patrol_point_set = false
elif abs(position.distance_to(_home)) < 2 && !patrol_point_set:
var dir: int = randi_range(0, 3)
match dir:
0:
patrol_point = Vector2(_home.x + patrol_distance, _home.y)
1:
patrol_point = Vector2(_home.x - patrol_distance, _home.y)
2:
patrol_point = Vector2(_home.x, _home.y + patrol_distance)
3:
patrol_point = Vector2(_home.x, _home.y - patrol_distance)

thrust = input_vector.y
strafe = input_vector.x
patrol_point_set = true
patrol_home_set = false

var patrol_angle: float = position.angle_to_point(patrol_point)
aim_at(patrol_angle)
thrust_towards(patrol_angle)

EnemyAIState.AIM_AT_PLAYER:
if abs(angle_difference) > deg_to_rad(1):
if angle_difference > 1 && rotation < 0:
yaw = -1
elif angle_difference < -1 && rotation > 0:
yaw = 1
elif angle_difference > 0:
yaw = 1
else:
yaw = -1
EnemyAIState.SEARCH:
var poi_angle: float = position.angle_to_point(search_point_of_interest)
var poi_distance: float = abs(position.distance_to(search_point_of_interest))

if abs(angle_difference) < deg_to_rad(5):
# Check if the player is within firing range
if position.distance_to(_player.position) < 100:
ai_state = EnemyAIState.FIRE_AT_PLAYER
else:
ai_state = EnemyAIState.MOVE_TO_PLAYER

EnemyAIState.FIRE_AT_PLAYER:
pass

func find_player_angle() -> float:
var angle = position.angle_to_point(_player.position)
angle += PI/2
if angle > PI:
angle -= PI*2
return angle
if poi_distance > 1:
thrust_towards(poi_angle)
aim_at(poi_angle)
else:
if !search_looking_around:
search_original_rotation = rotation
search_looking_around = true
search_halfway = false
search_direction = randi_range(0, 1)
if search_direction == 0: search_direction = -1
elif abs(rotation-(search_original_rotation * -1)) > deg_to_rad(2) && !search_halfway:
yaw = search_direction
elif abs(rotation-(search_original_rotation * -1)) < deg_to_rad(2) && !search_halfway:
yaw = search_direction
search_halfway = true
elif abs(rotation-search_original_rotation) > deg_to_rad(2) && search_halfway:
yaw = search_direction
elif abs(rotation-search_original_rotation) < deg_to_rad(2) && search_halfway:
ai_state = EnemyAIState.PATROL
search_looking_around = false

EnemyAIState.ATTACK_PLAYER:
var player_angle: float = get_player_angle()
var player_distance: float = abs(position.distance_to(_player.position))
if player_distance > 100:
thrust_towards(player_angle, 0.5)
aim_at(player_angle)
if attack_cooldown_timer.time_left == 0 && abs(player_angle - rotation) < deg_to_rad(2):
fire()
attack_cooldown_timer.start(attack_cooldown)

func get_player_angle() -> float:
return position.angle_to_point(_player.position)

func thrust_towards(angle: float, by: float = 1) -> void:
var input_vector: Vector2 = Vector2(by, 0).rotated(angle - rotation)
thrust = input_vector.x

func aim_at(angle: float) -> void:
var angle_diff: float = angle - rotation
if abs(angle_diff) > deg_to_rad(2):
yaw = find_fastest_yaw(angle_diff)

func find_fastest_yaw(angle_diff: float) -> float:
if angle_diff > 0 && angle_diff < PI:
return 1
elif angle_diff > 0 && angle_diff > PI:
return -1
elif angle_diff < 0 && angle_diff > -PI:
return -1
elif angle_diff < 0 && angle_diff < -PI:
return 1
else:
return 0
34 changes: 24 additions & 10 deletions scenes/ships/enemy/enemy.tscn
Original file line number Diff line number Diff line change
@@ -1,37 +1,51 @@
[gd_scene load_steps=6 format=3 uid="uid://cqfgwqqpwrg51"]
[gd_scene load_steps=7 format=3 uid="uid://cqfgwqqpwrg51"]

[ext_resource type="Script" path="res://scenes/ships/enemy/enemy.gd" id="1_w35kq"]
[ext_resource type="Texture2D" uid="uid://dua5c2gcufo14" path="res://assets/images/ships/enemy/enemy_ship.webp" id="2_fsep2"]
[ext_resource type="PackedScene" uid="uid://de3ymp8rbho6h" path="res://scenes/ui/ui_elements/health_bar/health_bar.tscn" id="3_rgjex"]
[ext_resource type="PackedScene" uid="uid://dsg7rv0et4eym" path="res://scenes/ships/hardpoint.tscn" id="4_asdpv"]
[ext_resource type="PackedScene" uid="uid://dvamksc1tkhj1" path="res://scenes/ships/enemy/vision_cone.tscn" id="5_2jwbw"]

[sub_resource type="RectangleShape2D" id="RectangleShape2D_n63kb"]
size = Vector2(33, 39)
size = Vector2(39, 33)

[node name="Enemy" type="CharacterBody2D" node_paths=PackedStringArray("health_bar", "sprite")]
[node name="Enemy" type="CharacterBody2D" node_paths=PackedStringArray("vision_cone", "health_bar", "sprite", "weapon_hardpoints")]
z_index = 10
collision_layer = 3
collision_mask = 2
script = ExtResource("1_w35kq")
vision_cone = NodePath("VisionCone")
attack_cooldown = 1.5
patrol_distance = 500
health_bar = NodePath("HealthBar")
sprite = NodePath("Sprite2D")
max_speed = 50
max_speed = 300
yaw_max_speed = 2.0
weapon_hardpoints = [NodePath("LeftPhaser"), NodePath("CenterMissile"), NodePath("RightPhaser")]

[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("RectangleShape2D_n63kb")

[node name="Sprite2D" type="Sprite2D" parent="."]
rotation = 1.5708
texture = ExtResource("2_fsep2")

[node name="HealthBar" parent="." instance=ExtResource("3_rgjex")]
offset_left = -13.0
offset_top = -22.0
offset_bottom = -20.0
offset_left = -18.0
offset_top = -13.0
offset_right = 8.0
offset_bottom = -11.0
rotation = 1.5708

[node name="LeftPhaser" parent="." instance=ExtResource("4_asdpv")]
position = Vector2(-8, 0)
position = Vector2(0, -8)

[node name="RightPhaser" parent="." instance=ExtResource("4_asdpv")]
position = Vector2(8, 0)
position = Vector2(0, 8)

[node name="CenterMissile" parent="." instance=ExtResource("4_asdpv")]
position = Vector2(0, 2.5)
hardpoint_type = 1

[node name="VisionCone" parent="." instance=ExtResource("5_2jwbw")]
position = Vector2(19, 0)
peripheral_radious = 250
65 changes: 65 additions & 0 deletions scenes/ships/enemy/vision_cone.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@tool

class_name VisionCone
extends Area2D

@export var width: int :
set(value):
width = value
change_size()

@export var height: int :
set(value):
height = value
change_size()

@export var peripheral_radious: int :
set(value):
peripheral_radious = value
change_size()

@export var peripheral_indicator_points: int :
set(value):
peripheral_indicator_points = value
change_size()

@export var collision_polygon: CollisionPolygon2D :
set(value):
collision_polygon = value
change_size()

@export var collision_shape: CollisionShape2D :
set(value):
collision_shape = value
change_size()

@export var color: Color = Color(1, 1, 1, 0.5) :
set(value):
color = value
queue_redraw()

func _ready() -> void:
change_size()

func change_size() -> void:
if collision_polygon == null:
return

collision_polygon.polygon = [
Vector2(0, 0),
Vector2(height, width / 2.0),
Vector2(height, -(width / 2.0)),
]

if collision_shape == null:
return

collision_shape.shape.radius = peripheral_radious

queue_redraw()

func _draw() -> void:
draw_line(Vector2(0, 0), Vector2(height, width / 2.0), color, -1)
draw_line(Vector2(0, 0), Vector2(height, -(width / 2.0)), color, -1)
draw_line(Vector2(height, width / 2.0), Vector2(height, -(width / 2.0)), color, -1)
draw_arc(Vector2(0, 0), peripheral_radious, 0, TAU, peripheral_indicator_points, color)
24 changes: 24 additions & 0 deletions scenes/ships/enemy/vision_cone.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[gd_scene load_steps=3 format=3 uid="uid://dvamksc1tkhj1"]

[ext_resource type="Script" path="res://scenes/ships/enemy/vision_cone.gd" id="1_uj4p1"]

[sub_resource type="CircleShape2D" id="CircleShape2D_y6307"]
radius = 250.0

[node name="VisionCone" type="Area2D" node_paths=PackedStringArray("collision_polygon", "collision_shape")]
collision_layer = 3
collision_mask = 8
script = ExtResource("1_uj4p1")
width = 600
height = 600
peripheral_radious = 60
peripheral_indicator_points = 64
collision_polygon = NodePath("CollisionPolygon2D")
collision_shape = NodePath("CollisionShape2D")
color = Color(1, 0.172549, 0.12549, 1)

[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="."]
polygon = PackedVector2Array(0, 0, 600, 300, 600, -300)

[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_y6307")
2 changes: 1 addition & 1 deletion scenes/ships/hardpoint.gd
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func fire(ship: Ship) -> float:
return 0

projectile.position = get_global_transform().origin
projectile.velocity = Vector2(0, -projectile.speed).rotated(ship.rotation) + ship.velocity
projectile.velocity = Vector2(projectile.speed, 0).rotated(ship.rotation) + ship.velocity
projectile.origin = ship
GameState.world.add_object(projectile)
return projectile.cooldown*0.01
Loading

0 comments on commit c14fb5d

Please sign in to comment.