However, when the Ray doesn’t hit anything, I don’t have a RayPosition. So, is there a way I can get around this and still be able to have a bullet trail?
But now the bullets go only in one direction on one of the axis once the ray goes out of range.
Also, I use :GetMouseLocation with ViewportPointToRay to get the RayDirection. Maybe it doesn’t work because of that.
local MouseLocation = UserInputService:GetMouseLocation()
local ViewRay = workspace.Camera:ViewportPointToRay(MouseLocation.X, MouseLocation.Y, 0)
local ray = workspace:Raycast(MuzzlePosition, ViewRay.Direction * 300)
Bullet.CFrame = CFrame.lookAt(
origin + (origin + direction * LENGTH - origin)/2,
origin + direction * LENGTH
)
-- or --
Bullet.CFrame = CFrame.lookAt(
origin + (direction * LENGTH)/2, origin + direction * LENGTH
)
Old reply
I see, you’re close.
If I recall correctly, ViewRay is a unit vector (length of 1). That’s why you’re multiplying it by 300. If the ray doesn’t hit anything, we can use the point ray reaches starting at the origin and reaching toward the point in the given direction 300 studs away.
I haven’t got a chance to test this, but the following should get you the correct CFrame for the visualizer. It’s the same as if the ray does hit something, but replaces the intersection point with the point where the ray ends.
Hey there. After you gave me those equations I have worked on something else for some time. Now I have returned to making guns but realized that the bullet trail is actually off when you are not in first person.
Code:
I now cast two rays, first one from the mouse position in the 3D space (using ViewportPointToRay) and second one from the Muzzle to where the first ray hit. I also added the third number (0.15) when changing the size of the bullet, otherwise it was very very very thin, nearly undetectable.
local mouseRay = workspace:Raycast(ViewRay.Origin, ViewRay.Direction * 1000)
if mouseRay then
local gunRay = workspace:Raycast(MuzzlePosition, (mouseRay.Position - MuzzlePosition).Unit * 600)
if gunRay ~= nil then
local RayPosition = gunRay.Position
CachedBullet.Size = Vector3.new((MuzzlePosition - RayPosition).Magnitude, 0.15, 0.15)
CachedBullet.CFrame = CFrame.lookAt(MuzzlePosition + (RayPosition - MuzzlePosition)/2, RayPosition) * CFrame.Angles(0, math.rad(90), 0)
else--If ray is out of range
CachedBullet.CFrame = CFrame.lookAt(MuzzlePosition + (ViewRay.Direction * 600)/2, MuzzlePosition + ViewRay.Direction * 600) * CFrame.Angles(0, math.rad(90), 0)
CachedBullet.Size = Vector3.new(600, 0.15, 0.15)
end
end
Oh yes, I see the issue. The equations are correct, but it’s not the view ray (camera ray) that is to be used. We need the direction we were casting towards from the muzzle. Missed that detail.
With the current code, if the ray is cast correctly and the gunRay doesn’t hit anything, the visualised bullet trail and an imaginary ray originating from our eyes directed towards the mouse should be parallel.
Great, I was just about to say that ScreenPointToRay() together with UIS:GetMouseLocation() can be the cause of an undesired offset because it depends on the gui inset.
Here is the code I quickly put together to see what properly works. It’s just a local script in a basic tool with a part called Handle which acts as the “Muzzle”.
Code
local UIS = game:GetService("UserInputService")
local gun = script.Parent
local muzzle = gun.Handle
local player = game:GetService("Players").LocalPlayer
local camera = workspace.CurrentCamera
gun.Activated:Connect(function()
local mouseLocation = UIS:GetMouseLocation()
local cameraRay = camera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
local mouseRay = workspace:Raycast(cameraRay.Origin, cameraRay.Direction * 1000)
if mouseRay then
local gunRay = workspace:Raycast(
muzzle.Position, (mouseRay.Position - muzzle.Position).Unit * 600
)
local trail = Instance.new("Part")
trail.Anchored = true
trail.CanCollide = false
trail.BrickColor = BrickColor.new("Bright yellow")
if gunRay ~= nil then
trail.Size = Vector3.new((muzzle.Position - gunRay.Position).Magnitude, .15, .15)
trail.CFrame = CFrame.lookAt(
muzzle.Position + (gunRay.Position - muzzle.Position)/2, gunRay.Position
) * CFrame.Angles(0, math.rad(90), 0)
else
trail.Size = Vector3.new(600, .15, .15)
trail.CFrame = CFrame.lookAt(
muzzle.Position + ((mouseRay.Position - muzzle.Position).Unit * 600)/2,
muzzle.Position + (mouseRay.Position - muzzle.Position).Unit * 600
) * CFrame.Angles(0, math.rad(90), 0)
end
trail.Parent = workspace
end
end)