Ray does not hit where the mouse is, in third person

Here is a pic of what I mean.

Ray

As you can see the ray is casted way off.

By the way, the ray casts perfectly well when my camera is close to the character or in first person.

Script with casting ray and CFraming the bullet trail via PartCache module:

local AmmoFolder = workspace:WaitForChild("AmmoFolder")

local BulletTemplate = Instance.new("Part")
BulletTemplate.Anchored = true
BulletTemplate.CanCollide = false
BulletTemplate.Color = Color3.new(1, 0.835294, 0)
BulletTemplate.Transparency = 0.1
BulletTemplate.Shape = Enum.PartType.Cylinder
BulletTemplate.Material = Enum.Material.Neon

local BulletCache = ClientPartCach.new(BulletTemplate, 3, AmmoFolder)

function ShootBullet(ViewRay, Muzzle)
	local MuzzlePosition = Muzzle.Position
	if Ammo > 0 and Reloading == false then
		local CachedBullet = BulletCache:GetPart()
		local ray = workspace:Raycast(MuzzlePosition, ViewRay.Direction * 300)
		if ray ~= nil then
			local RayPosition = ray.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 the ray hit maximum range
			CachedBullet.CFrame = CFrame.lookAt(MuzzlePosition + (ViewRay.Direction * 300)/2, MuzzlePosition + ViewRay.Direction * 300) * CFrame.Angles(0, math.rad(90), 0)
			CachedBullet.Size = Vector3.new(300, 0.15, 0)
		end
		
		Ammo -= 1
		AmmoGui.Text = Ammo
		task.wait(0.1)
		BulletCache:ReturnPart(CachedBullet)
	elseif Ammo <= 0 and Reloading == false then
		Reload(nil)
	end
end

I get ViewRay like this:

local MouseLocation = UserInputService:GetMouseLocation()
local ViewRay = workspace.Camera:ViewportPointToRay(MouseLocation.X, MouseLocation.Y, 0)
ShootBullet(ViewRay, Muzzle)

This is likely an issue with whatever the parameter “ViewRay” is set to. Can you show code where you are calling ShootBullet?

1 Like

Try this

@TheDoom_Boy

local AmmoFolder = workspace:WaitForChild("AmmoFolder")

local BulletTemplate = Instance.new("Part")
BulletTemplate.Anchored = true
BulletTemplate.CanCollide = false
BulletTemplate.Color = Color3.new(1, 0.835294, 0)
BulletTemplate.Transparency = 0.1
BulletTemplate.Shape = Enum.PartType.Cylinder
BulletTemplate.Material = Enum.Material.Neon

local BulletCache = ClientPartCach.new(BulletTemplate, 3, AmmoFolder)

function ShootBullet(ViewRay, Muzzle, Spread)
	local MuzzlePosition = Muzzle.Position
	if Ammo > 0 and Reloading == false then
		local CachedBullet = BulletCache:GetPart()
      local unitRay = camera:ScreenPointToRay(mouse.X, mouse.Y, 1)
		local ray = workspace:Raycast(MuzzlePosition, unitRay.Direction * 300)
		if ray ~= nil then
			local RayPosition = ray.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 the ray hit maximum range
			CachedBullet.CFrame = CFrame.lookAt(MuzzlePosition + (ViewRay.Direction * 300)/2, MuzzlePosition + ViewRay.Direction * 300) * CFrame.Angles(0, math.rad(90), 0)
			CachedBullet.Size = Vector3.new(300, 0.15, 0)
		end
		
		Ammo -= 1
		AmmoGui.Text = Ammo
		task.wait(0.1)
		BulletCache:ReturnPart(CachedBullet)
	elseif Ammo <= 0 and Reloading == false then
		Reload(nil)
	end
end
1 Like

Here is how I get ViewRay:

local MouseLocation = UserInputService:GetMouseLocation()
local ViewRay = workspace.Camera:ViewportPointToRay(MouseLocation.X, MouseLocation.Y, 0)
ShootBullet(ViewRay, Muzzle)
1 Like

Changing :ViewportPointToRay to :ScreenPointToRay didn’t help, the ray is still in the wrong place

1 Like

The issue is on what the ViewRay.Direction is. It works when the camera is close because the direction is for the camera. When you shoot it from the same direction but offset, it won’t land on the cursor. Replace the ViewRay.Direction with (MuzzlePosition - ViewRay.Position).Unit. This way, you now have the direction from the muzzle to the cursor point.

I did this (There is no such thing as ViewRay.Position so I did ViewRay.Origin)

local ray = workspace:Raycast(MuzzlePosition, (MuzzlePosition - ViewRay.Origin).Unit * 300)

Now it behaves even more strangely, I put my mouse on the top of my screen and it shoots down.

1 Like

Oh right my bad, ViewRay needs to be Raycasted into the world, and then you use the RaycastResult

1 Like

Not sure what you mean, like cast another ray? Could you please provide a brief scetch?

Yeah cast another ray.

local ViewRay = workspace:Raycast(ViewRay.Origin, ViewRay.Direction * 100) -- You might not need the distance not 100% sure
-- Check if viewray succeeded

local newDirection = (MuzzlePosition - ViewRay.Position).Unit
ViewRay = workspace:Raycast(MuzzlePosition, newDirection* 300)
1 Like

Here’s my raycast module, which accounts for that. Just call rayCast.rayCastToInput, and pass in the inputObject.

local RaycastModule = {}

-- Constants
local RAYCAST_DISTANCE = 1000

local Params = RaycastParams.new()
Params.FilterDescendantsInstances = {workspace.CurrentCamera}

local function rayCast(origin, direction,passed_Params)
	local raycastParam = passed_Params or Params
	local worldRay = Ray.new(origin, direction.Unit * RAYCAST_DISTANCE)
	local raycastResult = workspace:Raycast(worldRay.Origin, worldRay.Direction * RAYCAST_DISTANCE, raycastParam)

	-- Optional beam visualization
	if raycastResult then
		local size = Vector3.new(0.2, 0.2, (worldRay.Origin - raycastResult.Position).Magnitude-2)
		local cframe = CFrame.lookAt(worldRay.Origin, raycastResult.Position) * CFrame.new(0, 0, -(size.Z/2)-2)
	else
		print("no hit")
	end

	return raycastResult
end

function RaycastModule.rayCastInDirection(origin, direction,passed_Params)
	return rayCast(origin, direction,passed_Params)
end

function RaycastModule.rayCastToPoint(origin, goalPos,passed_Params)
	local direction = goalPos - origin
	return rayCast(origin, direction,passed_Params)
end

function RaycastModule.rayCastToInput(origin, inputObject,passed_Params)
	local Camera = workspace.CurrentCamera
	local worldRay = Camera:ScreenPointToRay(inputObject.Position.X, inputObject.Position.Y)
	return rayCast(origin, worldRay.Direction,passed_Params)
end

return RaycastModule
1 Like

I am confused on where to place these and whether I need to cast my original ray or the two rays that we cast from your code sketch is enough.

function ShootBullet(ViewRay, Muzzle, Spread)
	local MuzzlePosition = Muzzle.Position
	if Ammo > 0 and Reloading == false then
		local CachedBullet = BulletCache:GetPart()
        --Your code goes here?
         local ViewRay = workspace:Raycast(ViewRay.Origin, ViewRay.Direction * 100) -- You might not need the distance not 100% sure
        -- Check if viewray succeeded

        local newDirection = (MuzzlePosition - ViewRay.Position).Unit
        ViewRay = workspace:Raycast(MuzzlePosition, newDirection* 300)
      
		local ray = workspace:Raycast(MuzzlePosition, ViewRay.Direction * 300)--Do I need this?
		if ray ~= nil then
		else--if the ray hit maximum range
		end
--Some code blah blah

I see you use here Ray.new() which is not recommended use. Can you use here workspace:Raycast() or it won’t work properly?

1 Like

But … it does work properly. If you want to change it feel free. This code fixes your problem, though

1 Like

Here is the code that I have got with the use of your Module. I basically changed :ViewportToRay to :ScreenPointToRay and changed additional 2 line, it seems like this is how your module works but the result is that it does not work.

Did I miss something? Here is the script:

function ShootBullet(ViewRay, Muzzle, Spread)
	local MuzzlePosition = Muzzle.Position
	if Ammo > 0 and Reloading == false then
		local CachedBullet = BulletCache:GetPart()	

		local worldRay = Ray.new(Muzzle.Position, ViewRay.Direction.Unit * 300)--I added this
		local ray = workspace:Raycast(worldRay.Origin, worldRay.Direction * 300)--And this
        --It seems like this is just like your module does it, but it still doesn't work. Did I miss something?
		
if ray ~= nil then
              --Rest of the code

Here is how I get the ViewRay:

local MouseLocation = UserInputService:GetMouseLocation()
local ViewRay = workspace.Camera:ScreenPointToRay(MouseLocation.X, MouseLocation.Y)
ShootBullet(ViewRay, Muzzle)--Call the Shoot function

The rest of the code is identical to the one I have posted in the post.

Pic of the result I got:

ray2

1 Like

Pretty sure the issue is that the ray is casted from the gun. If the ray was casted form the camera then it would work correctly

Now, you want the ray to start from the gun, so you have to calculate the direction vector yourself, you can’t use the one from the camera
To get this, you just have to substract Mouse.Hit with the guns position (the destination of the ray - the origin of the ray)
This does require 2 raycasts but I don’t think there is a way around it

1 Like

I believe Mouse.Hit is using :GetMouse which is not recommended by Roblox, this is why I am using the recommended one, UserInputService:GetMouseLocation. Is there a way to do this with this method?

1 Like

Ray.new() ins’t a raycast, it’s simply a data type to represent a ray
It has some nice methods, but that is basically it
Though it is a neat object to use when dealing with raycasts

1 Like

Yeah, basically, you want to raycast a first ray to find Mouse.Hit, where the mouse intersects with the world, this can either be done using :GetMouse() or casting a ray yourself using ScreenPointToRay() or ViewportPointToRay (always forget which one to use). Then, using this value, you are able to find where the ray coming from the weapon would end up at. You can then raycast a second ray from the weapon to Mouse.Hit (where direction is Mouse.Hit.Position - Origin) and use that ray for your gun’s code

Imo, :GetMouse() is totally fine. The ease of use makes it really appealing as opposed to doing raycasting yourself. I did make a module that replicates Player:GetMouse() but uses the newer alternatives, if you are interested.

2 Likes

If you don’t want to use Mouse.Hit to calculate the mouse position I recommend:
image

5:10 - Is where he shows the line of code I sent as a image.

2 Likes