If I perceive accurately, the targets transfer alongside a path outlined as a sequence of factors. So, successfully, it’s shifting alongside a sequence of straight segments, right?
Thus, you may:
- Clear up the time and place for the collision alongside the present section.
- Test if that place is past the top of the section.
- Whether it is, add a time offset for the time to achieve the top of the section, take the subsequent section as present, and repeat from step 1.
- For those who nonetheless haven’t discovered a viable interception after contemplating the final path section, then you definately can’t intercept this goal. Attempt a special goal, wait, or shoot to overlook.
Is sensible?
Okay, we now have:
- The shooter place. I will name it
s_pos
. - The bullet velocity. I will name it
b_speed
. - The goal preliminary place. I will name it
t_pos_0
. - The goal velocity. I will name it
t_vel
. - The time offset. I will name it
time_0
.
And we wish:
- Collision time.
- Collision place.
We all know that the gap the bullet would have traveled in operate of time is:
b_travel_dist(time) = b_speed * time_0 + b_speed * time
I will take the primary phrases to be computed earlier than hand:
b_travel_dist_0 = b_speed * time_0
And now we now have:
b_travel_dist(time) = b_travel_dist_0 + b_speed * time
If we are able to discover the operate of the gap of the goal to the shooter by way of time, the purpose the place these features cross is the answer.
We will begin with the place of the goal as a operate of time:
t_pos(time) = t_pos_0 + t_vel * time
After which the offset between goal and shooter as a operate of time:
ts_offset(time) = t_pos(time) - s_pos
After which their distance:
ts_dist(time) = size(ts_offset(time))
So we are able to equate the gap between goal and shooter and the gap the bullet traveled:
ts_dist(time) = b_travel_dist(time)
Changing:
size(t_pos_0 + t_vel * time - s_pos) = b_travel_dist_0 + b_speed * time
Truly, I need to reorganize it in order that the phrases that would not have time are collectively:
size(t_pos_0 - s_pos + t_vel * time) = b_speed * time
In reality, you’ll be able to take these to compute beforehand too:
ts_offset_0 = t_pos_0 - s_pos
And we now have rather less cognitive load:
size(ts_offset_0 + t_vel * time) = b_travel_dist_0 + b_speed * time
After which we clear up for time (we in fact know the time should be constructive)… Hmm…
Look, we are able to divide by time on either side (take your time to assume it by):
size(ts_offset_0/time + t_vel) = b_travel_dist_0/time + b_speed
Okay, allow us to separate the x and y parts:
sqrt
(
(ts_offset_0.x/time + t_vel.x)^2
+
(ts_offset_0.y/time + t_vel.y)^2
)
=
b_travel_dist_0/time + b_speed
So we are able to sq. either side:
(ts_offset_0.x/time + t_vel.x)^2
+
(ts_offset_0.y/time + t_vel.y)^2
=
(b_travel_dist_0/time + b_speed)^2
Allow us to develop these:
(ts_offset_0.x/time)^2 + 2*(ts_offset_0.x/time)(t_vel.x) + (t_vel.x)^2
+
(ts_offset_0.y/time)^2 + 2*(ts_offset_0.y/time)(t_vel.y) + (t_vel.y)^2
=
(b_travel_dist_0/time)^2 + 2*(b_travel_dist_0/time)(b_speed) + (b_speed)^2
Reorganize:
(ts_offset_0.x/time)^2
+ (ts_offset_0.y/time)^2
+ 2*(ts_offset_0.x/time)(t_vel.x)
+ 2*(ts_offset_0.y/time)(t_vel.y)
+ (t_vel.x)^2
+ (t_vel.y)^2
=
(b_travel_dist_0/time)^2
+ 2*(b_travel_dist_0/time)(b_speed)
+ (b_speed)^2
Reorganize more durable:
(ts_offset_0.x)^2/time^2
+ (ts_offset_0.y)^2/time^2
+ 2*(ts_offset_0.x)(t_vel.x)/time
+ 2*(ts_offset_0.y)(t_vel.y)/time
+ (t_vel.x)^2
+ (t_vel.y)^2
=
(b_travel_dist_0)^2/time^2
+ 2*(b_travel_dist_0)(b_speed)/time
+ (b_speed)^2
Reorganize more durable:
((ts_offset_0.x)^2 + (ts_offset_0.y)^2)/time^2
+ (2*(ts_offset_0.x)(t_vel.x) + 2*(ts_offset_0.y)(t_vel.y))/time
+ (t_vel.x)^2 + (t_vel.y)^2
=
(b_travel_dist_0)^2/time^2
+ 2*(b_travel_dist_0)(b_speed)/time
+ (b_speed)^2
Allow us to multiply every thing by time squared:
(ts_offset_0.x)^2 + (ts_offset_0.y)^2
+ time * (2*(ts_offset_0.x)(t_vel.x) + 2*(ts_offset_0.y)(t_vel.y))
+ time^2 * (t_vel.x)^2 + (t_vel.y)^2
=
(b_travel_dist_0)^2
+ time * 2*(b_travel_dist_0)(b_speed)
+ time^2 * (b_speed)^2
Reorganize once more:
time^2 * (t_vel.x)^2 + (t_vel.y)^2
+ time * (2*(ts_offset_0.x)(t_vel.x) + 2*(ts_offset_0.y)(t_vel.y))
+ (ts_offset_0.x)^2 + (ts_offset_0.y)^2
=
time^2 * (b_speed)^2
+ time * 2*(b_travel_dist_0)(b_speed)
+ (b_travel_dist_0)^2
Ah, a quadratic equation in canonical type:
time^2 * ((t_vel.x)^2 + (t_vel.y)^2 - (b_speed)^2)
+ time * ((2*(ts_offset_0.x)(t_vel.x) + 2*(ts_offset_0.y)(t_vel.y)) - 2*(b_travel_dist_0)(b_speed))
+ (ts_offset_0.x)^2 + (ts_offset_0.y)^2 - (b_travel_dist_0)^2
=
0
Allow us to take the elements out:
a = (t_vel.x)^2 + (t_vel.y)^2 - (b_speed)^2
b = (2*(ts_offset_0.x)(t_vel.x) + 2*(ts_offset_0.y)(t_vel.y)) - 2*(b_travel_dist_0)(b_speed)
c = (ts_offset_0.x)^2 + (ts_offset_0.y)^2 - (b_travel_dist_0)^2
Wait, I need to write these one other approach:
a = t_vel.dot(t_vel) - b_speed * b_speed
b = 2 * ts_offset_0.dot(t_vel) - 2 * b_travel_dist_0 * b_speed
c = ts_offset_0.dot(ts_offset_0) - b_travel_dist_0 * b_travel_dist_0
And we now have:
a * time^2 + b * time + c = 0
Allow us to lower to it, and use the quadratic system. Now we have two options:
time = (-b + sqrt(b^2 - 4ac))/2a
And
time = (-b - sqrt(b^2 - 4ac))/2a
We wish the smaller constructive one.
To recap we compute these beforehand:
b_travel_dist_0 = b_speed * time_0
ts_offset_0 = t_pos_0 - s_pos
Then these:
a = t_vel.dot(t_vel) - b_speed * b_speed
b = 2 * ts_offset_0.dot(t_vel) - 2 * b_travel_dist_0 * b_speed
c = ts_offset_0.dot(ts_offset_0) - b_travel_dist_0 * b_travel_dist_0
And eventually these:
instances = [
(-b + sqrt(b^2 - 4ac))/2a,
(-b - sqrt(b^2 - 4ac))/2a
]
That’s, in fact, riddled with pitfalls. Particularly division by zero and sq. root of damaging numbers.
That’s as a result of we’re searching for an answer when the shooter shoots at time zero. So the answer is easy: if computing that is invalid… Do not shoot. Skip the section. For those who attain the top of the trail, test once more subsequent body.
To ease computing the instances, I will do that as an alternative:
bb = b * b
a2 = 2 * a
ac4 = 4 * a * c
After which we are able to do that:
if bb >= ac4:
r = sqrt(bb - ac4)
instances = [
(-b + r)/a2,
(-b - r)/a2
]
Allow us to discover if there’s a legitimate time:
time = INF
for candidate_time in instances:
if candidate_time < 0.0:
proceed
if candidate_time < time:
time = candidate_time
if not is_inf(time):
move
You may compute the purpose to purpose merely like this:
t_pos_0 + t_vel * time
Alright, however we have to test whether it is inside this section, in any other case we now have to loop, proper? proper. So we do one thing like this:
t_index = index
whereas t_index + 1 < t_points.measurement():
next_point = t_points[t_index + 1]
t_vel = (next_point - t_pos_0).normalized() * t_speed
time_to_next_point = (next_point - t_pos_0).size() / t_speed
# OTHER STUFF SHOWN BEFORE GOES HERE
if not is_inf(time):
if time <= time_to_next_point:
# INSERT SHOOT CODE HERE
return
time_0 += time_to_next_point
t_pos_0 = next_point
t_index += 1
Sure, I’ve examined this. In Godot with GDScript. Which is what I’ve been writing right here within the final elements of the reply. It isn’t Python, but it surely has very related syntax. So I hope it isn’t exhausting to adapt.