Raycast not going in the right direction

So I’m making a bot that will shoot in whatever direction it’s facing and I want the bot’s weapon to have some small spread. I came up with the code below to calculate the spread, however, regardless of the spread values or which direction the bot was facing the ray ended up veering off to the top left of where the barrel was facing.

-- Not the whole script, just the parts that are relevant to the raycast --

local bot = script.Parent;
local raycastParams = RaycastParams.new();
raycastParams.FilterDescendantsInstances = {bot};
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist;
raycastParams.IgnoreWater = false;

local randomObject = Random.new();
local minSpread = bot:GetAttribute("BulletMinSpread");
local maxSpread = bot:GetAttribute("BulletMaxSpread");
local range = bot:GetAttribute("BulletRange");

local function getRandomNumber(mini, maxi)
	return randomObject:NextNumber(mini, maxi);
end
	
local directionCF = CFrame.new(Vector3.new(), barrel.CFrame.LookVector);
local spreadDirection = CFrame.fromOrientation(0, 0, getRandomNumber(0, math.pi * 2));
local spreadAngle = CFrame.fromOrientation(math.rad(getRandomNumber(minSpread, maxSpread)), 0, 0);
local direction = (directionCF * spreadDirection * spreadAngle).LookVector * range;
	
local result = workspace:Raycast(barrel.Position, direction, raycastParams);

I have a gut feeling it has something to do with directionCF and not having the right LookVector but I don’t know what else I should be using there instead.

Picture of what the ray looks like, highlighted part is the barrel:

Any help is appreciated, thanks.

What values do you have set for the following?:

local minSpread = bot:GetAttribute("BulletMinSpread");
local maxSpread = bot:GetAttribute("BulletMaxSpread");

Both values are 0. Although even with them not set to 0 (for example min is 1 and max is 15) the spread still doesn’t work.

does setting spreadDirection to CFrame.new() do anything at all?

Uh…

There was 100 “shots” fired each time (using 1 min and 15 max spread that you provided for example)
They’re really sporadic. I’m not too experienced in this field, so I can’t really be of much help; but they appear to just spread out far too wide too quickly.
If this is of any help I’ll be surprised, but yeah I’m not 100% sure what it is honestly.

Setting spreadDirection to CFrame.new() doesn’t make the ray appear at all.

The main issue I’m having is the ray is always going to the same spot regardless of spread. Also, in my demo I had a large wall in front of the barrel to ensure the ray would hit it.

image
This is with 0, 1 min/max spread; using your original code (only modified to use the green parts position/LookVector)
100 shots as before.

EDIT: Can you show the code that you used to visualize the ray?
EDIT 2: And what is the default range?

The default range is 500. Below is the code used to visualize the ray.

local function showRay(range, raycastResult)
	local beam = Instance.new("Part");
	beam.BrickColor = BrickColor.new("Daisy orange");
	beam.FormFactor = "Custom";
	beam.Material = "Neon";
	beam.Transparency = 0.45;
	beam.Anchored = true;
	beam.Locked = true;
	beam.CanCollide = false;
	beam.Size = Vector3.new(0.1, 0.1, range);
	beam.CFrame = CFrame.new(barrel.position, raycastResult.Instance.position) * CFrame.new(0, 0, -range / 2);
	beam.Parent = workspace;
	game.Debris:AddItem(beam, 1);
end

Uh. I found your issue.

beam.CFrame = CFrame.new(barrel.Position, raycastResult.Instance.position) * CFrame.new(0, 0, -range / 2);

raycastResult.Instance.position?!

no.

raycastResult.Position

yes.

also don’t use deprecated terms. .position is deprecated and should be replaced favoring .Position

It’s bad, no at this point “bad” doesn’t describe it well enough anymore; It’s awful practice, even if you’re the only person who will ever see it. Although it seems like this may be snippet code so I’m not sure if you made it.

EDIT: Also, -range/2? you also have range defined elsewhere, no? so change the range parameter to “hitMagnitude” and pass through (barrel.Position - result.Position).Magnitude as the argument.
Then change -range / 2 to -hitMagnitude / 2

Or, use this fixed function.

local beamTemplate = Instance.new("Part") -- good practice to avoid repetitive instancing
beamTemplate.BrickColor = BrickColor.new("Daisy orange")
beamTemplate.Material = "Neon"
beamTemplate.Transparency = 0.45
beamTemplate.Anchored = true
beamTemplate.CanTouch = false
beamTemplate.CanCollide = false

-- + all of these are constants, why set them for a new beam every single shot?

local function showRay(source, raycastResult)
	local distance = (source.Position - raycastResult.Position).Magnitude
	local beam = beamTemplate:Clone()
	beam.Size = Vector3.new(0.025, 0.025, distance);
	beam.CFrame = CFrame.new(source.Position, raycastResult.Position) * CFrame.new(0, 0, -distance/2);
	beam.Parent = bot; -- you want these to, uh, get ignored, yeah?
	game:GetService("Debris"):AddItem(beam, 1)
end

-- Changes: You pass the barrel as the first argument now, and results like before.

That should work. And properly.

This did the trick, thanks for the assistance.

1 Like