diff --git a/ShootyEnemy.gd b/ShootyEnemy.gd index b1f794f..89173fe 100644 --- a/ShootyEnemy.gd +++ b/ShootyEnemy.gd @@ -1,5 +1,8 @@ extends KinematicBody +# An enemy which shoots at the future player position and moves between two targets within a given +# amount of time. + export(NodePath) var player_node onready var player = get_node(player_node) @@ -7,46 +10,83 @@ onready var player = get_node(player_node) export(NodePath) var solar_system_node onready var solar_system = get_node(solar_system_node) +export(Array, NodePath) var target_paths + +export var target_fly_time := 5.0 +var time_passed_since_fly_start := 0.0 +var current_target_index = 0 + var bullet_scene = preload("res://Bullet.tscn") var bullet_velocity = 40.0 -var target -var velocity := Vector3(0.0, 1.0, 1.0) +var shoot_target +var velocity := Vector3.ZERO func _ready(): + # Shoot everytime the timer times out $ShotTimer.connect("timeout", self, "shoot_bullet") + + # Set up pathing: Start at the first target + global_transform.origin = get_node(target_paths[0]).global_transform.origin + _set_velocity_to_fly_towards_next_target() + + +# Picks the next target position from the `target_paths` list and set the `velocity` appropriately +# so that the target will be reached after `target_fly_time`. +func _set_velocity_to_fly_towards_next_target(): + current_target_index = (current_target_index + 1) % target_paths.size() + + # Vector from here to the new target + var vector_to_next = (get_node(target_paths[current_target_index]).global_transform.origin + - global_transform.origin) + + # s = v * t --> v = s / t + velocity = vector_to_next / target_fly_time + time_passed_since_fly_start = 0.0 func _physics_process(delta): # Project the player's position into the future - target = _get_future_position( + shoot_target = _get_future_position( player.get_center(), player.velocity - velocity ) - if target: + # Look at the target that will be shot at, with the gravity as the down vector + if shoot_target: var gravity = solar_system.get_gravity_acceleration(global_transform.origin) - look_at(target, gravity) + look_at(shoot_target, gravity) + # Have we rearched the target? + time_passed_since_fly_start += delta + if time_passed_since_fly_start >= target_fly_time: + # If so, fly towards the next target + _set_velocity_to_fly_towards_next_target() + + # Apply velocity global_transform.origin += velocity * delta func shoot_bullet(): - if not target: + if not shoot_target: # Player can't be hit right now, abort return + # Add a bullet var instance = bullet_scene.instance() get_tree().get_root().add_child(instance) + # Make the bullet start at the current position of this object and fly towards the target. + # The own velocity is added because of galilean relativity. instance.global_transform.origin = global_transform.origin - global_transform.basis.z - instance.velocity = velocity + (target - global_transform.origin).normalized() * bullet_velocity + instance.velocity = velocity + (shoot_target - global_transform.origin).normalized() * bullet_velocity +# Return the position at which a bullet fired forwards and with the velocity `bullet_velocity` would +# intersect with the object that is at `position` and moving with the given `velocity` func _get_future_position(position, velocity): # Solution to the quadratic formula gives us the time at which the player would be hit - # TODO: Take acceleration into account as well! var a = pow(velocity.x, 2) + pow(velocity.y, 2) + pow(velocity.z, 2) - pow(bullet_velocity, 2) var b = 2 * (velocity.x * (position.x - global_transform.origin.x) + velocity.y * (position.y - global_transform.origin.y) @@ -67,4 +107,5 @@ func _get_future_position(position, velocity): var t = min(t1, t2) if t < 0: t = max(t1, t2) + # Return the position given by the time we calculated return position + t * velocity diff --git a/World.tscn b/World.tscn index 37e7f8c..78075d6 100644 --- a/World.tscn +++ b/World.tscn @@ -190,10 +190,17 @@ environment = SubResource( 11 ) transform = Transform( 0.866025, -0.353553, 0.353553, 0, 0.707107, 0.707107, -0.5, -0.612372, 0.612372, 0, 10, 0 ) shadow_enabled = true +[node name="EnemyPos1" type="Position3D" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 8, 20 ) + +[node name="EnemyPos2" type="Position3D" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -46.5073, 54.1815, 76.6368 ) + [node name="ShootyEnemy" parent="." instance=ExtResource( 6 )] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 8, 20 ) player_node = NodePath("../Player") solar_system_node = NodePath("../Planets") +target_paths = [ NodePath("../EnemyPos1"), NodePath("../EnemyPos2") ] [node name="Player" parent="." instance=ExtResource( 1 )] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0 )