Skip to content

Commit

Permalink
Implement missile guidance
Browse files Browse the repository at this point in the history
The missile knows where it is.
  • Loading branch information
arda-guler committed Jan 1, 2024
1 parent 80a5167 commit 7b23e05
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 50 deletions.
38 changes: 24 additions & 14 deletions auto_dogfight.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ def window_resize(window, width, height):

# READ INDUSTRY DATA
airframes, engines = read_industry()
player_airframe = airframes["LM Bombcat"]
player_engine = engines["APS 7K"]
player_airframe = airframes["OSB Serce"]
player_engine = engines["SE 7000"]

# INIT VESSELS
print("Initializing vessels...")
Expand Down Expand Up @@ -361,6 +361,7 @@ def rotate_cam(rotation):
altitude_conversion_factor = 3.28084 # feet

# AUTOPILOT
ctrl_state = [0,0,0]

# pull up!
AP.engine.throttle = 1
Expand All @@ -371,11 +372,14 @@ def rotate_cam(rotation):
if np.dot(AP.orient[1], np.array([0, 1, 0])) < max_orient * 0.8:
if np.dot(AP.orient[0], np.array([0, 1, 0])) < 0:
AP.aileron(-0.8)
ctrl_state[0] = -0.8
else:
AP.aileron(0.8)
ctrl_state[0] = 0.8

if np.dot(AP.orient[1], np.array([0, 1, 0])) > 0:
AP.elevator(0.8)
ctrl_state[1] = 0.8

# dogfight
elif current_encounter:
Expand All @@ -385,21 +389,23 @@ def rotate_cam(rotation):
enemy_actual_rel_pos = (enemy.pos - player.pos)
enemy_actual_dist = np.linalg.norm(enemy_actual_rel_pos)

enemy_rel_pos = (enemy.pos - player.pos) + enemy.vel * enemy_actual_dist / 500
enemy_rel_pos = (enemy.pos - player.pos) + enemy.vel * enemy_actual_dist / 600
enemy_dist = np.linalg.norm(enemy_rel_pos)
enemy_dir = enemy_rel_pos / enemy_dist

max_orient_1 = np.linalg.norm( enemy_dir - np.dot(player.orient[2], enemy_dir) * player.orient[2] )
# lift vector not aligned with player?
if np.dot(player.orient[1], enemy_dir) < max_orient_1 * 0.8:
if np.dot(player.orient[1], enemy_dir) < max_orient_1 * 0.94:

# should I roll clockwise?
if np.dot(player.orient[0], enemy_dir) > 0:
aileron_amount = np.dot(player.orient[0], enemy_dir)
player.aileron(0.8 * aileron_amount)
ctrl_state[0] = 0.8 * aileron_amount
else:
aileron_amount = -np.dot(player.orient[0], enemy_dir)
player.aileron(-0.8 * aileron_amount)
ctrl_state[0] = -0.8 * aileron_amount

# should I pitch?
if np.linalg.norm(player.vel) < 100:
Expand All @@ -412,15 +418,18 @@ def rotate_cam(rotation):
if np.dot(player.orient[1], enemy_dir) > 0:
if np.dot(player.orient[2], enemy_dir) < 0.98:
player.elevator(0.8)
ctrl_state[1] = 0.8

else:
player.elevator(0.3)
player.elevator(0.3 * (np.dot(player.orient[2], enemy_dir) - 0.98) / 0.02 + 0.5)
ctrl_state[1] = 0.3 * (np.dot(player.orient[2], enemy_dir) - 0.98) / 0.02 + 0.5
player.weapons[0].shoot(bodies)

# PHYSICS

for b in bodies:
if isinstance(b, Rocket):
b.guidance(dt)
b.apply_accel(gravity)
b.apply_drag()
b.apply_aero_torque()
Expand Down Expand Up @@ -480,16 +489,17 @@ def rotate_cam(rotation):
bodies.remove(current_encounter.enemy)
current_encounter = None

if AP_city == None:
play_bgm("pluvious")
else:
play_bgm(AP_city.bgm)
## if AP_city == None:
## play_bgm("pluvious")
## else:
## play_bgm(AP_city.bgm)

if rwr_snd and not get_channel_busy(6):
if not (rwr_snd == "rwr_new" or rwr_snd == "rwr_lost"):
play_sfx(rwr_snd, -1, 6)
else:
play_sfx(rwr_snd, 0, 6)
if rwr_snd and (not (rwr_snd == "rwr_new" or rwr_snd == "rwr_lost")) and not get_channel_busy(6):
play_sfx(rwr_snd, -1, 6)

if rwr_snd and (rwr_snd == "rwr_new" or rwr_snd == "rwr_lost"):
play_sfx(rwr_snd, 0, 8)

elif not rwr_snd or rwr_snd == "rwr_new" or rwr_snd == "rwr_lost":
stop_channel(6)

Expand Down
40 changes: 26 additions & 14 deletions auto_dogfight_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@ def rotate_cam(rotation):
velocity_conversion_factor = 1.943844 # knots
altitude_conversion_factor = 3.28084 # feet

# AUTOPILOT
# AUTOPILOT
ctrl_state = [0,0,0]

# pull up!
AP.engine.throttle = 1
Expand All @@ -374,11 +375,14 @@ def rotate_cam(rotation):
if np.dot(AP.orient[1], np.array([0, 1, 0])) < max_orient * 0.8:
if np.dot(AP.orient[0], np.array([0, 1, 0])) < 0:
AP.aileron(-0.8)
ctrl_state[0] = -0.8
else:
AP.aileron(0.8)
ctrl_state[0] = 0.8

if np.dot(AP.orient[1], np.array([0, 1, 0])) > 0:
AP.elevator(0.8)
ctrl_state[1] = 0.8

# dogfight
elif current_encounter:
Expand All @@ -388,21 +392,23 @@ def rotate_cam(rotation):
enemy_actual_rel_pos = (enemy.pos - player.pos)
enemy_actual_dist = np.linalg.norm(enemy_actual_rel_pos)

enemy_rel_pos = (enemy.pos - player.pos) + enemy.vel * enemy_actual_dist / 500
enemy_rel_pos = (enemy.pos - player.pos) + enemy.vel * enemy_actual_dist / 600
enemy_dist = np.linalg.norm(enemy_rel_pos)
enemy_dir = enemy_rel_pos / enemy_dist

max_orient_1 = np.linalg.norm( enemy_dir - np.dot(player.orient[2], enemy_dir) * player.orient[2] )
# lift vector not aligned with player?
if np.dot(player.orient[1], enemy_dir) < max_orient_1 * 0.8:
if np.dot(player.orient[1], enemy_dir) < max_orient_1 * 0.94:

# should I roll clockwise?
if np.dot(player.orient[0], enemy_dir) > 0:
aileron_amount = np.dot(player.orient[0], enemy_dir)
player.aileron(0.8 * aileron_amount)
ctrl_state[0] = 0.8 * aileron_amount
else:
aileron_amount = -np.dot(player.orient[0], enemy_dir)
player.aileron(-0.8 * aileron_amount)
ctrl_state[0] = -0.8 * aileron_amount

# should I pitch?
if np.linalg.norm(player.vel) < 100:
Expand All @@ -415,15 +421,20 @@ def rotate_cam(rotation):
if np.dot(player.orient[1], enemy_dir) > 0:
if np.dot(player.orient[2], enemy_dir) < 0.98:
player.elevator(0.8)
ctrl_state[1] = 0.8

else:
player.elevator(0.3)
player.weapons[0].shoot(bodies)
player.elevator(0.3 * (np.dot(player.orient[2], enemy_dir) - 0.98) / 0.02 + 0.5)
ctrl_state[1] = 0.3 * (np.dot(player.orient[2], enemy_dir) - 0.98) / 0.02 + 0.5

if np.dot(player.orient[2], enemy_dir) > 0.92:
player.weapons[0].shoot(bodies)

# PHYSICS

for b in bodies:
if isinstance(b, Rocket):
b.guidance(dt)
b.apply_accel(gravity)
b.apply_drag()
b.apply_aero_torque()
Expand Down Expand Up @@ -483,16 +494,17 @@ def rotate_cam(rotation):
bodies.remove(current_encounter.enemy)
current_encounter = None

if AP_city == None:
play_bgm("pluvious")
else:
play_bgm(AP_city.bgm)
## if AP_city == None:
## play_bgm("pluvious")
## else:
## play_bgm(AP_city.bgm)

if rwr_snd and not get_channel_busy(6):
if not (rwr_snd == "rwr_new" or rwr_snd == "rwr_lost"):
play_sfx(rwr_snd, -1, 6)
else:
play_sfx(rwr_snd, 0, 6)
if rwr_snd and (not (rwr_snd == "rwr_new" or rwr_snd == "rwr_lost")) and not get_channel_busy(6):
play_sfx(rwr_snd, -1, 6)

if rwr_snd and (rwr_snd == "rwr_new" or rwr_snd == "rwr_lost"):
play_sfx(rwr_snd, 0, 8)

elif not rwr_snd or rwr_snd == "rwr_new" or rwr_snd == "rwr_lost":
stop_channel(6)

Expand Down
34 changes: 19 additions & 15 deletions data/models/rocket.mdl
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
V|0, 0, 1
V|0, 0, 0
V|0.5, 0, 0
V|-0.5, 0, 0
V|0, 0.5, 0
V|0, -0.5, 0
L|1, 2
L|2, 3
L|2, 4
L|2, 5
L|2, 6
L|3, 5
L|5, 4
L|4, 6
L|6, 3
V|0,0,-0.10
V|0,0,0.10
V|0.2,0,0.7
V|-0.2,0,0.7
V|0,0.2,0.7
V|0,-0.2,0.7
V|0.4,0,-1.0
V|-0.4,0,-1.0
V|0,0.4,-1.0
V|0,-0.4,-1.0
L|1,2
L|2,3
L|2,4
L|2,5
L|2,6
L|1,7
L|1,8
L|1,9
L|1,10
8 changes: 4 additions & 4 deletions encounter.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def update(self, gravity, bodies, dt):
player_actual_dist = np.linalg.norm(player.pos - self.enemy.pos)

# aimpoint position
player_rel_pos = (player.pos - self.enemy.pos) + player.vel * player_actual_dist / 1000
player_rel_pos = (player.pos - self.enemy.pos) + player.vel * player_actual_dist / 600
player_dist = np.linalg.norm(player_rel_pos)
player_dir = player_rel_pos / player_dist

Expand All @@ -120,7 +120,7 @@ def update(self, gravity, bodies, dt):
else:
max_orient_1 = np.linalg.norm( player_dir - np.dot(self.enemy.orient[2], player_dir) * self.enemy.orient[2] )
# lift vector not aligned with player?
if np.dot(self.enemy.orient[1], player_dir) < max_orient_1 * 0.8:
if np.dot(self.enemy.orient[1], player_dir) < max_orient_1 * 0.94:

# should I roll clockwise?
if np.dot(self.enemy.orient[0], player_dir) > 0:
Expand All @@ -139,11 +139,11 @@ def update(self, gravity, bodies, dt):
self.enemy.elevator(elevator_amount)

if np.dot(self.enemy.orient[1], player_dir) > 0:
if np.dot(self.enemy.orient[2], player_dir) < 0.94:
if np.dot(self.enemy.orient[2], player_dir) < 0.98:
self.enemy.elevator(0.8)

else:
self.enemy.elevator(0.3)
self.enemy.elevator(0.3 * (np.dot(self.enemy.orient[2], player_dir) - 0.98) / 0.02 + 0.5)
self.enemy.weapons[0].shoot(bodies, self.player)

self.enemy.engine.intake.air_intake_vector = -self.enemy.orient[2]
Expand Down
1 change: 1 addition & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ def rotate_cam(rotation):

for b in bodies:
if isinstance(b, Rocket):
b.guidance(dt)
b.apply_accel(gravity)
b.apply_drag()
b.apply_aero_torque()
Expand Down
7 changes: 4 additions & 3 deletions quick_dogfight.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ def window_resize(window, width, height):

# READ INDUSTRY DATA
airframes, engines = read_industry()
player_airframe = airframes["LM Bombcat"]
player_engine = engines["SE 7000"]
player_airframe = airframes["OSB Kirlangic"]
player_engine = engines["APS 7K"]

# INIT VESSELS
print("Initializing vessels...")
init_pos = np.array([0.0, 1000, 0.0]) # m
init_vel = np.array([0.0, 0.0, 100.0]) # m s-1
init_vel = np.array([0.0, 0.0, 150.0]) # m s-1
init_accel = np.array([0.0, 0.0, 0.0]) # m s-2
init_orient = np.array([[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
Expand Down Expand Up @@ -426,6 +426,7 @@ def rotate_cam(rotation):

for b in bodies:
if isinstance(b, Rocket):
b.guidance(dt)
b.apply_accel(gravity)
b.apply_drag()
b.apply_aero_torque()
Expand Down
19 changes: 19 additions & 0 deletions rigidbody.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import math
import numpy as np
from scipy.spatial.transform import Rotation

Expand Down Expand Up @@ -96,6 +97,24 @@ def check_target(self, bodies):
play_sfx("explosion", channel=6)
del self

def guidance(self, dt):
if (not self.target) or np.linalg.norm(self.vel) == 0:
return

t = self.target
m = self

if np.dot(t.pos - m.pos, self.orient[2]) < 0.1:
return

K_p = 0.001

aimpoint = t.pos + t.vel * K_p * np.linalg.norm(t.pos - m.pos)
aimpoint_dir = aimpoint - m.pos
aimpoint_dir /= np.linalg.norm(aimpoint_dir)

m.vel = m.vel * (1 - dt * 2) + (aimpoint_dir * np.linalg.norm(m.vel)) * dt * 2

def drain_fuel(self, dt):
self.update_mass(-self.mass_flow * self.throttle / 100, dt)

Expand Down

0 comments on commit 7b23e05

Please sign in to comment.