I am stuck with the code for enemy rotate and follow the hero

my code to find the distance from the player to the enemy ship is this

private float FindDistance( Vector2 heroCenter, Vector2 spritePos)
 {
     var deltaX = Math.Pow((spritePos.X - heroCenter.X), 2);
     var deltaY = Math.Pow((spritePos.Y - heroCenter.Y), 2);
     float distance = (float)Math.Sqrt(deltaX + deltaY);
 
     return distance; // returns the distance between the two objects
 }

and the code to calculate the angle for the enemy ship to rotate is this.

distanceFromHero = FindDistance(Constants.heroCenter, spritePos);
 
if (distanceFromHero < Constants.HeroWithinRange)
{
heroClose = true;
VelocityX *= .985f; // enemy reduces vel X
VelocityY *= .985f; // enemy reduces vel Y
 
//atan2 for angle
var radians = Math.Atan2((spritePos.Y - Constants.heroCenter.Y), (spritePos.X - Constants.heroCenter.X));
 
//radians into degrees
rotationAngle = (float)(radians * (180 / Math.PI));
 
}
else
{
heroClose = false;
}
}

the problem is that though the enemy rotates towards the player it never locks on but has a kind of pendulum like awing and when the enmy comes up to the player it goes into a fast rotation. ANy help is appreciated.

For one it looks like your Atan2 values may be negated. It should be (target - current).

Now, are you trying to make the enemy rotate gradually or all at once? And what do you use rotationAngle for? Because it’s odd that you would ever need a value in degrees unless it’s just for debugging or you convert it back later.

i want the enemy ship slow down while rotating to gradually while moving towards the player ship.

Ok, so I think there are 2 common ways to control the angle and corresponding ways to stop overshoot when the angle reaches the desired value. The first is a more realistic acceleration controller that will have a nice ease-in-out effect, and the second is a quick solution with constant velocity that generally only works in software.

1. PID (Proportional, Integral, Derivative) controller. Real physical control systems use these kinds of controllers because you can’t just magically set a value. Instead, to turn a ship you affect angular acceleration by applying a force – usually a higher force the more you have to turn, so it doesn’t take too long. Thus your applied force is proportional to the difference in angle. To avoid overshoot, you can subtract a value that scales with your angular velocity, or the derivative of your motion, to counteract the inertia. Now in real systems there’s always friction which will cause a steady state error as you get really close to your target but can’t overcome the last bit of friction. So real controllers also add a value that scales with the integral – or the accumulation of error. Since you probably aren’t dealing with friction when turning your ships, you could use a PD controller and it would look quite realistic. Here is a sample:

double w = 0.075;
double kp = w * w;
double kd = 2 * w;

double angularAcc = kp * (radians - currentRadians) - kd * (currentRadians - lastRadians);
angularVel += angularAcc;

lastRadians = currentRadians;
currentRadians += angularVel;

// Draw sprite with angle "currentRadians"

Using kp = w^2 and kd = 2w is called “critical damping” and is generally the fastest way to get to the target without overshooting. I got w = 0.075 from testing, and it results in taking about 1.5 seconds to complete a turn (assuming 60 fps). Increasing kp will make it go faster, but overshoot, and increasing kd will add damping and reduce overshoot. Here’s a website where you can see a live example.

2. The other option is much simpler, but may look less realistic. The idea is that you can just compare your current angle and your previous angle to your desired angle every frame to see if you turned too far. After turning the ship as you are now, check if your new angle passed the desired angle: (prev < desired && desired < curr) || (prev > desired && desired > curr). If so then just set the angle to be the desired angle.

One last thing you should consider is that since angles can wrap around, you should compare abs(target - current), abs((target + 2 * Math.PI) - current), and abs((target - 2 * Math.PI) - current) to see which target angle is the closest, and use that as your desired angle. For example if you’re going from 5 degrees to 350 degrees, you should instead target -10 degrees because turning -15 is much faster than turning +345.

1 Like

Aint there a Vector2.Distance method instead of you FindDistance? Do not reinvent the wheel, you should avoid problems on these parts :wink:

2 Likes

This series may help you : https://gamedevelopment.tutsplus.com/series/understanding-steering-behaviors–gamedev-12732

yes. I am learning Monogame and C#. Thanks to you now I know that.

That sounds a bit complicated… :frowning:

It may sound complicated, but the 7 lines of code there should be all you need. I just wanted to give a full explanation if you wanted it.

Also the note at the bottom of that post may take another few lines of code, but you should have that regardless of how you’re turning the ship.

I can give more assistance with any method if you’d like.

There’s a neat trick to figuring out what direction gives the shortest turn. You need the unit vectors instead of rotation in radians. Consider the so-called 2D cross product of the vectors, the z component of the cross product of the vectors as if they were 3d: v1.X * v2.Y - v1.Y * v2.X. If that’s positive the shortest turn from v1 to v2 is in the positive direction and analogous for negative. Note that we’re rotating along the z-axis, which points into the screen in the coordinate system used by SpriteBatch (x is right, y is down). So positive rotation is clockwise, negative is counter clockwise.

To get some intuition for this method, you can check it with the right-hand rule because MG’s uses a right-handed coordinate system. With your right hand:
For the cross product (gives the vector perpendicular to two other vectors):

  1. Stretch your thumb along v1
  2. Stretch your index finger along v2
  3. Point your middle finger away from your palm
    => Your middle finger points along the cross product of v1 and v2

To check the direction of a rotation around a vector:

  1. Stretch your thumb along the direction of the vector
  2. Curl your fingers
    => Positive rotation is in the direction of your fingers
1 Like

check this kink out. I will study what you have written and try to understand [this] too.(https://bitbucket.org/diliupg/microsft_catmousetank_wanderchaseevade_updatedforvs2017/src/f570d6c8e4b4bb75c06416e24b858323e1ae02ea?at=default)

the original link which I cant find at this moment had a VS201 project which did not work in VS2017. I converted and saved it enter link description here

That’s true, but depending on what you’re doing, you might still need the target angle itself rather than just the direction. Because turning CCW from 0 to 10 is potentially different from turning CCW from 175 to -175.

Just to give a bit of insight, I believe these are the main differences in how each of these methods will appear to a player:

  • diliupg’s cat/mouse link is a great way for turning at constant angular velocity. If that’s all you need, I would recommend it. You can even modify the turn speed to try to give more interesting motion.
  • Maybeking’s tutorial series is a great way of moving with force control, which means the speed will appear more dynamic. Although its couples linear and angular force, which is more suited to cars, it also looks natural for ship AI. The one caveat is it looks like they don’t handle turning in place.
  • The PD force controller I mentioned is a bit of a combination. It is also a force controller, so you get dynamic speed, but it decouples linear and angular motion so you can turn in place if desired.

Sorry if I’m overcomplicating this. I got a couple degrees in AI and robotics so I really enjoy this stuff. :stuck_out_tongue:

1 Like

It’s not my code. The Original link is here
As it could not be opened with VS2017 I made completely new Project to work with Monogame using the same assets. It is a great tute unfortunately some of the code went right over my head… :smiley: :smiley:.
JNoyola, thanks for your offer to help. Much appreciated.

1 Like