Shotgun spread problem

Currently I’m working on a shotgun. However i’m countering a problem:

The shotgun spread is created by 3 random values, which can be explained by the following code:

local R1= math.random(-ShotgunConfigs.Radius.Value, ShotgunConfigs.Radius.value)
local R2= math.random(-ShotgunConfigs.Radius.Value, ShotgunConfigs.Radius.value)
local R3= math.random(-ShotgunConfigs.Radius.Value, ShotgunConfigs.Radius.value)
								
local ray = Ray.new(ShootPart.CFrame.p, (mouse.Hit.p - ShootPart.CFrame.p).unit * ShotgunConfigs.Range.Value + Vector3.new(R1,R2,R3))

Radius will be a value that defined by integer, in this case, the radius is 5.

However, seems that there’s a relationship between ShotgunConfigs.Range.Value and the spread, the shorter the range is, the more spread it is, the longer the range is, the less spread it is, for instance, take a look on this picture which I did in MS paint

Orange line represents the spread when the range is 70 studs, Red line represents the range when it is 700 studs, as you can see the spread is different, and this is what I anticipate:

These 2 cases in game represented by bullet holes, in these 2 screenshots, I changed nothing except the range value:

image

image

How do I fix this? I know I have to do something with the range when creating a ray but exactly how?
Please do let me know if you are confused or have any questions.
Thanks :pray:

3 Likes

There was a similar post about this that I responded to already.

This CFrame construction uses an angle (in radians) to make the spread you’re looking for.

Edit: So as to why what you did doesn’t work, you should try to visualize where you shoot as a cone. The nature of cones is that the further you get away from the point, the wider the base needs to be. If you’re only adding the base vector3, it wont account for the end of the cone widening (because you’re adding instead of multiplying), so you’ll get less accurate results the futher away you are.

A naive solution would be to multiply the R1,R2,R3 with range, but now you’re over-complicating a variable that should be one dimension up to three dimensions (a vector3).

You seem to be using a sphere to calculate offset instead of a circle. This could lead to it not actually going the right range. (In this example + or - 5 studs)


Here is a rough sketch of why that occurs.
Notice how the angle offset from the shot going towards your mouse gets smaller with greater distance.
This is what causes it to shoot more accurately at a distance (as Vector3.new(R1, R2, R3) does not change with distance).

You could use what @Locard suggested (within the similar post linked), however, this suffers from one minor problem (if what you want is even spread), Disk Point Picking -- from Wolfram MathWorld. You’ll end up with the spread pattern on the left, rather than the one on the right.

If you want a spread pattern similar to what is shown on the right, use this instead

local rng_v = Random.new()

function RandomVectorOffset(v, maxAngle) --returns uniformly-distributed random unit vector no more than maxAngle radians away from v
    return (CFrame.new(Vector3.new(), v)*CFrame.Angles(0, 0, rng_v:NextNumber(0, 2*math.pi))*CFrame.Angles(math.acos(rng_v:NextNumber(math.cos(maxAngle), 1)), 0, 0)).LookVector
end 

maxAngle just represents the maximum angular offset between the accurately shot vector and the spread-away vector.

Putting this all together with a max angular offset of about 30 deg, you get,

local dir = RandomVectorOffset((mouse.Hit.p - ShootPart.CFrame.p).Unit, math.rad(30)) 
local ray = Ray.new(ShootPart.CFrame.p, dir * ShotgunConfigs.Range.Value)
14 Likes

Why did it throw an error when I remove mouse.Hit.P?
local dir = RandomVectorOffset(ShootPart.CFrame.p).Unit, math.rad(ShotgunConfigs.Radius.Value)

I want the raycasting go straight direct from the ShootPart, despite and ignoring the mouse Position.

Radius.Value,hmmmmm.why not just find the position usally

try just doing(code below) ,but you can try

ShotgunConfigs = script.Parent -- or something else if this script is not shotgunconfigs,if you know what i mean,make sure Radius is a InValue or a variable of some sort
math.rad(ShotgunConfigs.Radius.Value)