I have a gun system that fires a raycast from a gun in the direction of the players lookvector, but because the gun is a few studs to the right of the player, projectiles do not line up with the center of the screen and subsequently the crosshair in the center of the screen.
I have been trying to adjust the direction component of the raycast to point towards positions along the players lookvector, but if the position is too close to the player, then the bullet will go way off course, and a position far away means you can still miss targets in front of you from the offset.
How should I go about fixing this?
You should fire two raycasts:
- First one from the player head’s lookvector (if you are using standard Roblox first person perspective), to find the target to hit.
- Second from the gun, adjusted to look at the first raycast’s result position. If the first raycast does not find anything, then simply shoot in the player’s look direction.
If I’m understanding you correctly, this is something that most FPS games actually run into.
The most conventional way most games solve it is by having 1 aesthetic based ray (that actually shoots from where your barrel is), and then one real raycast that shoots from the center of your camera and does the hit calculations.
This video may help The Slightly Odd Way Bullets Work In FPS Games - YouTube
This makes sense. Should I then move my bullet towards the real rays intersection?
Yes if you want it to line up with your crosshair the origin should be the center of your camera. Your trace markers origin should be the front of the barrel
If I am shooting 2 bullets, one visible and one not, wouldn’t the aesthetic bullet take longer than the real bullet? If so, than how can I compensate?
I did this in my FPS game before. What I did was I added the difference from the right hand to the head.
One possible solution is to calculate the point on the screen that the player is aiming at and use that point as the target for the raycast. This can be achieved using the ViewportPointToRay
method of the Camera
object.
Here’s an example implementation:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ShootEvent = ReplicatedStorage:WaitForChild("ShootEvent")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local gun = character:WaitForChild("Gun")
local camera = workspace.CurrentCamera
ShootEvent.OnClientEvent:Connect(function()
local screenPos = camera.ViewportSize / 2 -- center of the screen
local ray = camera:ViewportPointToRay(screenPos.X / camera.ViewportSize.X, screenPos.Y / camera.ViewportSize.Y)
local direction = (ray.Direction * 1000) + (gun.Position - character.Head.Position) -- add offset
local result = workspace:Raycast(gun.Position, direction, { humanoid.Parent })
if result then
local target = result.Instance
-- handle hit
end
end)
In this example, we first get the player’s character and the gun object, as well as the camera object. When the player shoots, we calculate the center point of the screen using the ViewportSize
property of the camera. We then use the ViewportPointToRay
method to calculate a ray from the camera to that point. We multiply the resulting direction vector by a large number to ensure it reaches far enough to hit something, and we add the offset between the gun and the center of the screen to align it correctly.
Finally, we cast the ray using the Raycast
method of the workspace, passing in the gun’s position as the origin, the adjusted direction vector as the direction, and an array of objects to ignore (in this case, everything except the player’s character). If we get a hit, we handle it appropriately.