As you can see, when I throw the knife it freezes mid air and it bounces off the floor even after while I turned its CanCollide = false
GunModulescript:
local GunModule = {}
GunModule.Config = {
Damage = 10000,
FireCooldown = 3.065,
MaxRange = 500,
RateLimit = 20,
RateLimitWindow = 5,
FireCursorIcon = "rbxasset://textures/GunCursor.png",
ReloadCursorIcon = "rbxasset://textures/GunWaitCursor.png",
}
function GunModule.IsInRange(shooterPos: Vector3, targetPos: Vector3): boolean
return (shooterPos - targetPos).Magnitude <= GunModule.Config.MaxRange
end
return GunModule
GunService (serverscript)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local GunModule = require(ReplicatedStorage.Shared.Modules.GunModule)
local Remotes = ReplicatedStorage.Remotes
local FireGunRemote = Remotes.FireGun
local GunHitRemote = Remotes.GunHit
local PlayerEliminatedRemote = Remotes.PlayerEliminated
local Config = GunModule.Config
local playerFireCooldowns: {[number]: number} = {}
local playerRateLimitData: {[number]: {count: number, windowStart: number}} = {}
local roundActive: boolean = false
local function getRoundActive(): boolean
return roundActive
end
local function setRoundActive(state: boolean)
roundActive = state
if not state then
table.clear(playerFireCooldowns)
end
end
local function isOnCooldown(userId: number): boolean
local lastFire = playerFireCooldowns[userId]
if not lastFire then return false end
return (os.clock() - lastFire) < Config.FireCooldown
end
local function setCooldown(userId: number)
playerFireCooldowns[userId] = os.clock()
end
local function isRateLimited(userId: number): boolean
local now = os.clock()
local data = playerRateLimitData[userId]
if not data then
playerRateLimitData[userId] = { count = 1, windowStart = now }
return false
end
if (now - data.windowStart) >= Config.RateLimitWindow then
playerRateLimitData[userId] = { count = 1, windowStart = now }
return false
end
data.count += 1
if data.count > Config.RateLimit then
return true
end
return false
end
local function validatePlayerHasGun(player: Player): boolean
local character = player.Character
if not character then return false end
local tool = character:FindFirstChildOfClass("Tool")
if not tool then return false end
local toolType = tool:FindFirstChild("ToolType")
if not toolType or toolType.Value ~= "Gun" then return false end
return true
end
local function killPlayer(killer: Player, victim: Player)
local victimCharacter = victim.Character
if not victimCharacter then return end
local victimHumanoid = victimCharacter:FindFirstChildOfClass("Humanoid")
if not victimHumanoid then return end
if victimHumanoid.Health <= 0 then return end
victimHumanoid:TakeDamage(Config.Damage)
PlayerEliminatedRemote:FireAllClients(killer, victim)
end
local function processShot(player: Player, targetPosition: Vector3)
local userId = player.UserId
-- if not getRoundActive() then return end
if isRateLimited(userId) then return end
if isOnCooldown(userId) then return end
if not validatePlayerHasGun(player) then return end
local shooterCharacter = player.Character
if not shooterCharacter then return end
local shooterHRP = shooterCharacter:FindFirstChild("HumanoidRootPart")
if not shooterHRP then return end
local shooterHumanoid = shooterCharacter:FindFirstChildOfClass("Humanoid")
if not shooterHumanoid or shooterHumanoid.Health <= 0 then return end
if not GunModule.IsInRange(shooterHRP.Position, targetPosition) then return end
setCooldown(userId)
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {shooterCharacter}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local shootOrigin = shooterHRP.Position + Vector3.new(0, 1.5, 0)
local direction = (targetPosition - shootOrigin).Unit * Config.MaxRange
local result = workspace:Raycast(shootOrigin, direction, raycastParams)
if result and result.Instance then
local hitCharacter = result.Instance:FindFirstAncestorOfClass("Model")
if hitCharacter then
local victimPlayer = Players:GetPlayerFromCharacter(hitCharacter)
if victimPlayer and victimPlayer ~= player then
local victimHumanoid = hitCharacter:FindFirstChildOfClass("Humanoid")
if victimHumanoid and victimHumanoid.Health > 0 then
killPlayer(player, victimPlayer)
GunHitRemote:FireAllClients(player, result.Position)
end
end
end
end
end
FireGunRemote.OnServerEvent:Connect(function(player: Player, targetPosition: any)
if typeof(targetPosition) ~= "Vector3" then return end
processShot(player, targetPosition)
end)
Players.PlayerRemoving:Connect(function(player: Player)
local userId = player.UserId
playerFireCooldowns[userId] = nil
playerRateLimitData[userId] = nil
end)
local GunService = {}
function GunService.SetRoundActive(state: boolean)
setRoundActive(state)
end
function GunService.GetRoundActive(): boolean
return getRoundActive()
end
function GunService.ResetPlayer(player: Player)
local userId = player.UserId
playerFireCooldowns[userId] = nil
playerRateLimitData[userId] = nil
end
return GunService
Gun Client (local script)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Debris = game:GetService("Debris")
local GunModule = require(ReplicatedStorage.Shared.Modules.GunModule)
local Remotes = ReplicatedStorage.Remotes
local FireGunRemote = Remotes.FireGun
local GunHitRemote = Remotes.GunHit
local PlayerEliminatedRemote = Remotes.PlayerEliminated
local LocalPlayer = Players.LocalPlayer
local Camera = workspace.CurrentCamera
local Tool = script.Parent
local Config = GunModule.Config
local ShootSound = ReplicatedStorage.Assets.Sounds.Shoot
local FIRE_COOLDOWN = GunModule.Config.FireCooldown
local isEquipped = false
local canFire = true
local mouse = nil
local function updateCursor()
if not mouse then return end
if not canFire then
mouse.Icon = Config.ReloadCursorIcon
else
mouse.Icon = Config.FireCursorIcon
end
end
local function getTargetPosition(): Vector3
local mousePos = mouse and mouse.Hit and mouse.Hit.Position
if mousePos then
return mousePos
end
local viewportSize = Camera.ViewportSize
local ray = Camera:ViewportPointToRay(viewportSize.X / 2, viewportSize.Y / 2)
local raycastParams = RaycastParams.new()
local localCharacter = LocalPlayer.Character
if localCharacter then
raycastParams.FilterDescendantsInstances = {localCharacter}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
end
local result = workspace:Raycast(ray.Origin, ray.Direction * (Config.MaxRange or 500), raycastParams)
if result then
return result.Position
end
return ray.Origin + ray.Direction * (Config.MaxRange or 500)
end
local function playShootSound()
local sound = ShootSound:Clone()
sound.Parent = Tool.Handle
if not sound.IsLoaded then
sound.Loaded:Wait()
end
sound:Play()
Debris:AddItem(sound, sound.TimeLength + 0.1)
end
local function shootBulletEffect(startPos: Vector3, endPos: Vector3)
local attachment0 = Instance.new("Attachment")
attachment0.WorldCFrame = CFrame.new(startPos)
attachment0.Parent = workspace
local attachment1 = Instance.new("Attachment")
attachment1.WorldCFrame = CFrame.new(endPos)
attachment1.Parent = workspace
local beam = Instance.new("Beam")
beam.Attachment0 = attachment0
beam.Attachment1 = attachment1
beam.Width0 = 0.1
beam.Width1 = 0.1
beam.LightEmission = 1
beam.LightInfluence = 0
beam.FaceCamera = true
beam.Color = ColorSequence.new({
ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 255, 0)),
ColorSequenceKeypoint.new(1, Color3.fromRGB(255, 200, 100)),
})
beam.Parent = Camera
task.wait()
local tweenInfo = TweenInfo.new(0.05, Enum.EasingStyle.Linear)
local tween1 = TweenService:Create(beam, tweenInfo, { Width0 = 0 })
tween1:Play()
tween1.Completed:Wait()
local tween2 = TweenService:Create(beam, tweenInfo, { Width1 = 0 })
tween2:Play()
tween2.Completed:Wait()
beam:Destroy()
attachment0:Destroy()
attachment1:Destroy()
end
local function fire()
if not canFire then return end
if not isEquipped then return end
local localCharacter = LocalPlayer.Character
if not localCharacter then return end
local localHumanoid = localCharacter:FindFirstChildOfClass("Humanoid")
if not localHumanoid or localHumanoid.Health <= 0 then return end
canFire = false
updateCursor()
local targetPosition = getTargetPosition()
playShootSound()
FireGunRemote:FireServer(targetPosition)
local handle = Tool:FindFirstChild("Handle")
local startPos = handle and handle.Position or localCharacter.HumanoidRootPart.Position
task.spawn(shootBulletEffect, startPos, targetPosition)
task.delay(FIRE_COOLDOWN, function()
canFire = true
updateCursor()
end)
end
Tool.Equipped:Connect(function(m)
mouse = m
isEquipped = true
updateCursor()
end)
Tool.Unequipped:Connect(function()
isEquipped = false
if mouse then
mouse.Icon = ""
end
mouse = nil
end)
Tool.Activated:Connect(function()
fire()
end)
GunHitRemote.OnClientEvent:Connect(function()
end)
PlayerEliminatedRemote.OnClientEvent:Connect(function(killer: Player, victim: Player)
if victim == LocalPlayer then
canFire = false
isEquipped = false
end
end)
Any help is appreciated