# 2d starship combat, hit chances based on bearing and speed (vector)?

Thinking about a 2d strategy game, where you move your starships turn by turn and fire guns at each other.

Instead of the traditional approach of "range" lowering hit chances, im thinking about some sort of system that throws vectors at each other to calculate relative bearing and speed to calculate hit chances.

I.e. a fast, small ship is harder to hit than a slow, big chip, but in addition the relative bearing (im thinking: is the target flying straight towards your X/Y = good hitchance, or is it strafing very narrowly, low hitchances depending on speed).

Getting the relative the bearing (angle) on an approaching vessel would be easy using atan2, but how could this be translated it into a hitchance that goes up if the angle is like 330 to 30 degree and goes down if its different (as an example) ?

• Try creating an equation that calculates the hit chance based on the angle, the distance and the speed difference. Dec 2, 2016 at 13:14

You simply need a parametrical equation.

A good way to get how different the 2 ship's angle is is to use dot product on the ship's direction vector and the normalised version of the vector pointing from the current ship to the other ship. This'll return 1 if the ship is looking right at the other ship and -1 if it's looking in the other direction. We should normalize this value by addibg 1 to it and then dividing the sum by 2. In equation this looks like this:

angleParam := (dot(direction, normalize(vec2(otherX - currentX, otherY - currentY))) + 1) / 2


Now the speed: You should have a max speed of a ship, and the speed of the 2 spaceships (currentSpeed and otherSpeed). To get a value between 0 and 1:

speedParam := (currentSpeed - otherSpeed) / maxSpeed / 2;


I don't know how you calculate the size, but let's assume it's a value between 0 and 1. If it's not between 0 and 1, then you need to somehow map it between these 2 values.

To get a chance from these, you can use the following equation:

chance := (angleParam * ⅓ + speedParam * ⅓ + sizeParam * ⅓)


This is a value between 0 and 1.

You can change the ⅓s to any value you want based on how you want the chance to be calculated (like when size has a bigger impact on aiming than speed, then you should make size have a bigger multiplier than speed), but they should add up to 1.

• Why do you suggest to add 1 and divide by 2 on the dot product, what exactly are the ramifications compared to doing a "normal" +1/-1 range dot product ? Dec 4, 2016 at 15:11
• @user431806 Because I try to put every value between 0 and 1 Dec 4, 2016 at 16:23
• I see, thanks. Im still looking further into it. thanks so far. Dec 4, 2016 at 16:26

Using the angles you provided as example, I took the liberty of assuming a few other data / scenarios.

Let's say you want a 100% hit chance when the angle difference is 0, and have the "good extremes" to be 75% at 330º and 30º, with intervals between those.

The first thing you should do is check if the angle is between 0 and 180, or between 180 and 360. If it's in the second bracket, you'll want to subtract 360 to its value. In either case, you'll then divide the angle by 30, to obtain a range of values that will go from -1 at 330, to 1 at 30.

You'll then want to divide that desired dispersion (in this case, 25%) by the inverse of the absolute value of this multiplier, in order to know how much to reduce from the accuracy.

Example code for Unity in C# (untested):

if(angleDiff >= 180 && angleDiff <= 360)
{
angleDiff -= 360;
}

precisionMultiplier = angleDiff / 30;

if(precisionMultiplier != 0)
{
accuracyReduction = dispersion / (1 / Mathf.Abs(precisionMultiplier));
}

chanceToHit = 100 - accuracyReduction;


There are many things you can do with this, and there is room for several more variables / improvements. For instance, you can have each ship start with a default precision, different to 100%, and have that number be at its maximum when the angle difference is 0 by using its precision instead of the hard-coded "100".

Also, keep in mind that the precision multiplier, if divided by 30, will vary from -6 to 6 when accounting all 360 degrees, so you can have a separate logic, indicating a different accuracy decay, by contemplating the cases in which its value is greater beyond the -1 to 1 range.