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