Skip to main content
4 of 5
added 2 characters in body
Merivo
  • 153
  • 6

I've done this before. The easiest method is to simulate the projectile, record points along its trajectory and note the closest point to the target. What I then do is get the target's location + (target velocity * time taken to reach closest point*) to get the location it would be by the time the projectile reached it. All you need to do then is Math.atan2 the new coordinate with your ship's coordinate to get the angle you need to be at to hit it (or you could draw a marker on the HUD at the new location if you prefer).

For my purposes, this is efficient enough, and can deal with multiple targets at once without any performance hits. If you want it to be more efficient, simply multiply the projectile's velocity and put less points along its trajectory.

*note that the time taken to reach the closest point is that point's index in the array.

Edit: As requested, below is a rough pseudo-code for what I did, note that the way I simulate my projectile will probably be different to how you have to simulate yours.

Also note that the functions below belong to the ship and 'this' is a reference to the ship instance. Also, this is some kind of modified java :P

list<Point> targetPoints = new list<Point>(); list<Double> targetRotations = new list<Double>(); //the function you call in your update step: public void doTargetting(list<Asteroid> targets, int targettingRange) { targetPoints.clear(); //reset the list of targets targetRotations.clear(); if(targets.size() == 0) return; int maxPoints = 50, stepsPerPoint = 3; list<Point> mypoints = simulateCurve(maxPoints, stepsPerPoint, myProjectile); for(Asteroid a in targets) { if(distance(a, this) < targettingRange) { list<Point> apoints = simulateCurve(maxPoints, stepsPerPoint, a); doTargettingFor(a, this, mypoints, apoints); } } } //physics stuff: public list<Point> simulateCurve(int maxPoints, int stepsPerPoint, GameObject obj) { list<Point> points = new list<Point>(); double velx = obj.velx, vely = obj.vely; double accellx = obj.accellx, accelly = obj.accelly; double maxSpeed = obj.maxSpeed; //if you want a max speed double burnout = obj.burnout; //a point at which the projectile runs out of thruster juice double loss = 1 - obj.friction; //velocity loss in each step, because space dust or something? double x = 0, y = 0; points.add({x, y}); int spl = 0; //counter for steps per line for(int i=0; i<maxPoints*stepsPerPoint; i++) { if(burnout != 0 && i < burnout) { velx += accellx; vely += accelly; } velx *= loss; vely *= loss; double mag = Math.hypot(velx, vely); if(maxSpeed != 0 && mag > maxSpeed) { double mul = maxSpeed/mag; velx *= mul; vely *= mul; } x += velx; y += vely; spl++; if(spl > stepsPerLine) { spl = 0; points.add({x, y}); } } return points; } //targetting stuff: public void doTargettingFor(GameObject a, Ship me, list<Point> mypoints, list<Point> apoints) { int closestIndex = 0; double closest = MAX_VALUE; //a really really big number for(int i=0; i<points.size(); i++) { double distance = Math.hypot((apoints[i].x+a.x) - (mypoints[i].x+me.x), (apoints[i].y+a.y) - (mypoints[i].y+me.y)); if(distance < closest) { closest = distance; closestIndex = i; } } if(closest < a.radius) { //this bit looks complicated but it really isn't. I'm taking the simulated points of the asteroid and adding it to the asteroid's current coordinates, then doing the same for the projectile targetPoints.add({apoints[closestIndex].x + a.x, apoints[closestIndex].y + a.y}); targetRotations.add(Math.atan2((apoints[closestIndex].y + a.y) - (mypoints[closestIndex].y + me.y), (apoints[closestIndex].x + a.x) - (mypoints[closestIndex].x + me.x))); } } 
Merivo
  • 153
  • 6