Hello forum, today i decided to make a isometric gun system for my game. Basically, the gun will shoot straight in front of the player and damage humanoid if the bullet hit any character. I did that by using raycasting and check if the hit instance is a humanoid then damages them. The problem is, the gun only damages character from far away but work completely well in cqc. How can i fix this and what is the problem to this?
here’s the script:
local tool = script.Parent
local module = require(tool:WaitForChild("GunSettingsModule"))
local ShootEvent = tool:WaitForChild("ShootEvent")
local function createMuzzleFlash(handle)
local attachment = handle:FindFirstChild("MuzzleAttachment")
if attachment then
local muzzleFlash = attachment:FindFirstChild("Muzzle")
if muzzleFlash then
muzzleFlash:Emit(2)
else
warn("Muzzle particle emitter not found in attachment")
end
else
warn("MuzzleAttachment not found in handle")
end
end
local function playSound(handle)
local sound = handle:FindFirstChild("Fire")
if sound then
sound:Play()
else
warn("GunSound not found in handle")
end
end
local function onShoot(player)
if not player then
warn("Invalid player")
return
end
local character = player.Character
if not character then return end
local handle = tool:FindFirstChild("Handle")
if handle then
local camera = workspace.CurrentCamera
local direction = camera.CFrame.LookVector
createMuzzleFlash(handle)
playSound(handle)
tool.Handle.PointLight.Enabled = true
task.wait(0.05)
tool.Handle.PointLight.Enabled = false
local startPos = handle.Position
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
local raycastResult = workspace:Raycast(startPos, direction * 2000, raycastParams)
if raycastResult then
local hitPart = raycastResult.Instance
local humanoid = hitPart.Parent:FindFirstChildOfClass("Humanoid") or hitPart.Parent.Parent:FindFirstChildOfClass("Humanoid")
if humanoid then
humanoid:TakeDamage(module.Settings.Damage)
print("Damage dealt to:", humanoid.Parent.Name)
end
end
else
warn("Handle not found in tool")
return
end
end
ShootEvent.OnServerEvent:Connect(onShoot)
Judging by the code, the casting direction is based on the camera’s forward direction, not determined from the gun’s tip (or source of the bullets) to the cursor’s 3D space. In other words, your gun is shooting at the ground with a limited radius.
You’ll have to do a little more maths and an extra raycast by using the camera’s ViewportPointToRay(), which returns a Ray (not to be confused with RaycastResults).
When retrieving the resulting Ray, use its Direction property and use it to cast from the position of the cursor towards the direction of the Ray. From the RaycastResults, you can cast from the handle to the 3D position of the mouse.
Do note that solving for the 3D mouse position should be done on the client side, and received by the server to calculate the projectile’s direction. Also, the code below was not tested, so let me know if there are issues with it that you need some assistance with.
-- from the client (note that this implementation is just an example.
-- you may have to tweak this client-side code to fit yours)
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local tool = script.Parent
local shootEvent = tool:WaitForChild("ShootEvent") :: RemoteEvent
local raycastParams = RaycastParams.new()
local function shoot()
local camera = workspace.CurrentCamera
-- we need to find a hit position from the mouse, so solve for the cursor's direction
-- from the camera.
local mouseScreenPosition = UserInputService:GetMouseLocation()
local mouseWorldRay = workspace.CurrentCamera:ViewportPointToRay(
mouseScreenPosition.x, mouseScreenPosition.Y,
0
)
raycastParams = {Players.LocalPlayer.Character}
local mouseWorldPosition = workspace:Raycast(
mouseWorldRay.Origin,
mouseWorldRay.Direction * 2000,
raycastParams
)
-- get the position of the hit. we'll use this for finding the direction from the
-- handle to the expected direction of the bullet.
local mouseHitPosition
if (mouseWorldPosition ~= nil) then
mouseHitPosition = mouseWorldPosition.Position
else
-- recover from lack of results by using the max distance instead.
mouseHitPosition = mouseWorldRay.Origin + mouseWorldRay.Direction * 2000
end
-- send the mouse's 3D position.
shootEvent:FireServer(mouseHitPosition)
end
-- from the server script (specifically the function "onShoot")
local function onShoot(player : Player, mousePosition : Vector3)
-- the RemoteEvent is guaranteed to return a player when calling FireServer from the client.
if not mousePosition then return end
local character = player.Character
if not character then return end
local handle = tool:FindFirstChild("Handle")
if handle then
createMuzzleFlash(handle)
playSound(handle)
tool.Handle.PointLight.Enabled = true
task.wait(0.05)
tool.Handle.PointLight.Enabled = false
local startPos = handle.Position
local directionFromHandle = (mousePosition - startPos).Unit
local raycastFromHandle = workspace:Raycast(
startPos,
directionFromHandle * 2000,
raycastParams
)
-- finally, we can check if the hit is a humanoid.
if (raycastFromHandle ~= nil) then
local hitHasHumanoid = raycastFromHandle.Instance.Parent:FindFirstChildWhichIsA("Humanoid")
if (hitHasHumanoid) then
hitHasHumanoid:TakeDamage(module.Settings.Damage)
print("Damage dealt to:", hitHasHumanoid.Parent.Name)
end
end
else
warn("Handle not found in tool")
return
end
end