C++ Instant Weapon Spread


This is how my Weapon works.
Now i want wo make some Weapon Spread.

void ASWeaponInstant::FireWeapon()
	const FVector AimDir = GetAdjustedAim();

	// Camera Possition is StartPos
	const FVector StartTrace = GetCameraDamageStartLocation(AimDir);
	const FVector EndTrace = StartTrace + (AimDir * WeaponRange);

	/* Check for impact by tracing from the camera position */
	FHitResult Impact = WeaponTrace(StartTrace, EndTrace);

Can someone tell me how to make a Spread ?

Thanks DarkSoe

You can offset your EndTrace by a few centimeters in a random direction. Obviously the centimeters have different results depending on how long WeaponRange is, but you get what I mean.
If you want the weapon spread to increase with rapid fire, let the random centimeter be a value that is incremented with each fire and then interpolated down back to zero or 1 depending on if you want the player to be fully accurate when not having fired for a while.

Also, when trying this out, make sure to make use of Unreal’s debug lines and points (DrawDebugLine, DrawDebugPoint) etc. Makes it a lot easier :slight_smile:

Thanks so far,

Can you post an example how this should look like ?
I dont have a idea how to do this.

My idea was to add a Random Vector to the EndPos Vector, but i dont know how to get the corect values to make the weapon range not wrong.

Not sure. Personally didn’t care if the range differed in a few centimeters. You’ll have to set the spread so that it’s somewhere in some circle around the direction vector, right? Take that vector, rotate it 90 degrees in yaw and/or pitch and you have a new vector pointing perpendicular to the shot direction. Add your offset using this rotated vector as a direction.

Currently i solved it like this

RandomX = FMath::RandRange(-100, 100);
RandomY = FMath::RandRange(-100, 100);
RandomZ = FMath::RandRange(-100, 100);

const FVector RandomVector = FVector(RandomX * 1.0f, RandomY * 1.0f, RandomZ * 1.0f);
const FVector AimDir = GetAdjustedAim();

const FVector StartTrace = GetCameraDamageStartLocation(AimDir);
const FVector EndTrace = (StartTrace + RandomVector) + (AimDir * WeaponRange);

I get a random vector from a cone using so I can control vertical and horizontal in degrees. The degree amount can then be adjusted over time during the firing duration however you want.
You feed in your initial adjusted aim direction.

That looks interesting

I noticed that this returns a uniformly distributed vector, which would make bullet spread look eratic. How would you go about normalizing this/changing this from uniform random to Gaussian random?

I’ve been trying to work out the same thing to more closely mimic the spread pattern of a shotgun. I haven’t tested this, so this could be way too slow for all I know.

I was thinking you could take in a vector as the cone direction (we’ll call this C), and get a vector that is the cross product of world up (0,0,1) and the cone direction vector (we’ll call this A). The resulting cross product vector A would be rotated around the cone direction vector C by a random integer between 0 and 360 (uniformly distributed). Then you would use either the Box-Muller transform or Ziggurat method to get a random normally distributed value between 0 and 1. This value multiplied by your max cone angle would give you your displacement from the center. You would rotate C around A by that amount.

Speaking from a gameplay perspective, you typically don’t want the spread to be entirely random. It’s frustrating for players, and you typically don’t want ‘randomness’ in a skill-based game (if that’s what you’re building). Additionally if you are trying to make a multiplayer game, then you need to use seeds for the random numbers because otherwise the spreads will be different on client/server.

‘Randomness’ and ‘Spread’ are two different things and you can have spread without randomness. Gears of War 3 actually specified the pattern of shots for it’s primary shotgun, you can see the pattern here:

In my opinion / experience, defining the spread as a constant value is far more satisfying than true randomness.

There’s a problem with how you solved it. You’re just moving the impact point, meaning the weapon range could end up being shorter or longer. The correct way would be to actually rotate the direction it’s firing in. You can do that easily by turing it into a Rotator, adding a random amount, and then back to a Vector.

//In tick
      SpreadAmount -= DeltaTime * 1;
      if(SpreadAmount < 0) SpreadAmount = 0;

//In shoot code
FVector AimDir = GetAdjustedAim();
FVector StartTrace = GetCameraDamageStartLocation(AimDir);

RandomX = FMath::RandRange(-20, 20);
RandomY = FMath::RandRange(-20, 20);
RandomZ = FMath::RandRange(-20, 20);

FRotator AimRot = AimDir.Rotator();
RandomAimRot += FRotator(RandomX, RandomY, RandomZ) * SpreadAmount;

FVector EndTrace = (StartTrace) + (RandomAimRot.Vector() * WeaponRange);

SpreadAmount += 0.3;
if(SpreadAmount .> 1) SpreadAmount = 1;

One of those Randoms isn’t needed, since you don’t need the bullet to twist in a barrel roll, I just don’t remember which. :slight_smile:

Bonus: I added a variable called SpreadAmount. It starts at 0% (no spread) and every time a bullet is fires the spread increases to 100%, then in the tick function it slowly goes back to 0%. Should help realism on a rapidfire weapon.