extends KinematicBody export(NodePath) var player_node onready var player = get_node(player_node) export(NodePath) var solar_system_node onready var solar_system = get_node(solar_system_node) var bullet_scene = preload("res://Bullet.tscn") var bullet_velocity = 40.0 var target var velocity := Vector3(0.0, 1.0, 1.0) func _ready(): $ShotTimer.connect("timeout", self, "shoot_bullet") func _physics_process(delta): # Project the player's position into the future target = _get_future_position( player.get_center(), player.velocity - velocity ) if target: var gravity = solar_system.get_gravitation_acceleration(global_transform.origin) look_at(target, gravity) global_transform.origin += velocity * delta func shoot_bullet(): if not target: # Player can't be hit right now, abort return var instance = bullet_scene.instance() get_tree().get_root().add_child(instance) instance.global_transform.origin = global_transform.origin - global_transform.basis.z instance.velocity = velocity + (target - global_transform.origin).normalized() * bullet_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) + velocity.z * (position.z - global_transform.origin.z)) var c = pow(position.x - global_transform.origin.x, 2.0) \ + pow(position.y - global_transform.origin.y, 2.0) \ + pow(position.z - global_transform.origin.z, 2.0) var discriminant = pow(b, 2) - 4 * a * c if (discriminant < 0): return null # Can't hit the target :( var t1 = (-b + sqrt(discriminant)) / (2 * a) var t2 = (-b - sqrt(discriminant)) / (2 * a) # Choose the smallest positive t value var t = min(t1, t2) if t < 0: t = max(t1, t2) return position + t * velocity