Attention |
Topic was automatically imported from the old Question2Answer platform. | |

Asked By |
equus |

Hello! I’m trying to implement a **Proportional Navigation** (https://en.wikipedia.org/wiki/Proportional_navigation) and I found this formula:

**Required Acceleration = LOS * LOS_Rate * NC + APN_bias**

I want to create a homing missile in 2D but it is not working as I expected and also I don’t know the formula for 2D.

I don’t need to use precisely the same formula as above. I just want to create a homing missile that moves elliptical and misses the target if it moves.

Here is the code:

```
export(float) var speed = 600
export(float) var navigation_const = 3
var _time_to_use_pn = 0.5
var current_velocity = Vector2()
var enemy_target
var _last_los = 0
func set_proportional_navigation(delta):
_time_to_use_pn -= delta
if _time_to_use_pn > 0:
var cur_rot = get_global_rot()
var forward_dir = Vector2(sin(cur_rot), cos(cur_rot))
current_velocity = forward_dir.normalized() * speed * (-1)
return
if enemy_target != null:
var my_pos = get_global_pos()
var target_pos = enemy_target.get_global_pos()
var cur_rot = get_global_rot()
var los = atan2(my_pos.y - target_pos.y, my_pos.x - target_pos.x)
var los_rate = los - _last_los
_last_los = los
var angle = los_rate * navigation_const
rotate(angle)
var forward_dir = Vector2(sin(cur_rot), cos(cur_rot))
current_velocity = forward_dir.normalized() * speed * (-1)
```

**Edit:** I’m using Godot 2.1.4.

**Edit 2:** The code above contains another formula for 2d.

**Edit 3:** I found this link: https://gamemechanicexplorer.com/#homingmissiles-1, and I tried to translate the code to Godot but it doesn’t work. My code:

```
var my_pos = parent_weapon.get_global_pos()
var target_pos = enemy_target.get_global_pos()
var cur_rot = parent_weapon.get_global_rot()
var rotation_vel = deg2rad(5)
var angle = angle_between(target_pos, my_pos)
# Gradually (rotation_vel) aim the missile towards the target angle
if cur_rot != angle:
# Calculate difference between the current angle and targetAngle
var delta = angle - cur_rot
# Keep it in range from -180 to 180 to make the most efficient turns.
if delta > PI: delta -= PI * 2
if delta < -PI: delta += PI * 2
if delta > 0:
# Turn clockwise
cur_rot += rotation_vel
else:
# Turn counter-clockwise
cur_rot -= rotation_vel
# Just set angle to target angle if they are close
if abs(delta) < rotation_vel:
cur_rot = angle
parent_weapon.set_global_rot(cur_rot)
var forward_dir = Vector2(sin(cur_rot), cos(cur_rot))
current_velocity = forward_dir.normalized() * parent_weapon.w_speed
missile_shot.parent_weapon.global_translate(missile_shot.current_velocity * p_delta)
```

The maths in the linked articles is annoyingly wrong.

For example in the stackoverflow-answer it says `Required Acceleration = LOS * LOS_Rate * NC + APN_bias`

and `APN_bias = LOS_Rate/delta_T * ( NC/2 )`

. So since LOS is a vector and all the other terms are scalars that would mean adding a vector and a scalar.

And in the article on moddb it says

```
# Now, calculate the final lateral acceleration required for our missile
# to home into our target.
latax = RTM_new * N * Vc * LOS_Rate + LOS_Delta * Nt * ( 0.5 * N )
```

So the formula is supposed to result in a LATERAL acceleration - but the second part of the addition contains the factor Nt which is supposed to describe the relative acceleartion of the target - so if the target moves without acceleration it’s 0. (The article talks about flying missiles and therefore factors in gravity, but let’s talk about the special case of movement in a 2D plane first to check the formula - after all it should work just as well in that special case.

So this leaves us with

```
latax = RTM_new * N * Vc * LOS_Rate
```

and again RTM_new is a vector and all the other terms are scalars. So the result will have the same direction as RTM_new, and that vector is pointing directly at the target, so we end up accelerating at the target, not at a point in front of the target.

I’ll try to find the time and test it myself, but these two sources seem too faulty to simply copy and modify.

Warlaan | 2018-04-01 09:45

And how about the code above? I used another formula for 2D. I forgot to mention it. I tried to rotate using only LOS rate and navigation constant but it doesn’t work.

equus | 2018-04-02 18:13

I have written something like this:

https://github.com/JohnMeadow1/GodotGeometryElements/blob/master/final/targeting/scripts/rocket.gd

This will work in Godot 2.1.4

JohnMeadow1 | 2018-06-04 11:00

Thank you! I found you repository very interesting. The rocket script is very cool but I need something more similar to the link in my 3rd edit on this question. The code in the link worked but when I translated to Godot, something gone wrong and it not worked.

I ran your code downloaded from github. For some reason it didn’t work in my game. It worked only when I changed the orientation initial value to **90 degrees** and set the object rotation to **orientation - 90 degrees**. I have no idea why.

equus | 2018-06-04 21:39

The problem might be related to where 0 degree is.

In math 0 degrees is RIGHT. But different math library implementations sometimes implement 0 degrees as UP. In my project, all sprites are oriented right so i do not need any ±90 degrees. Although I had this problem when changing to Godot 3.

I have uploaded Godot 3 version of the targeting project.

https://github.com/JohnMeadow1/GodotGeometryElements/tree/master/godot_3/final/targeting

If you can share your project I can look into it.

JohnMeadow1 | 2018-06-10 02:35