that’s because in functions like Heartbeat/RenderStepped that run every frame, if you have more frames per second, then it will run more times. That’s why you need to account the deltaTime (time passed between this and previous frame) property, which is the default argument for such functions. You need to pass the deltaTime to your function, and multiply by it.
event.OnServerEvent:Connect(function(plr, dt, mousePosition)
local turretPosition = TurretUnion.CFrame.Position
local lookAtDirection = (mousePosition - turretPosition).unit -- Direction to look at
-- Calculate the goal orientation
local goalLookAtCF = CFrame.lookAt(Vector3.new(), Vector3.new(lookAtDirection.X, 0, lookAtDirection.Z))
-- Convert to local CFrame relative to Motor6D
local goalCF = worldCFrameToC0ObjectSpace(TurretUnion.Motor6D, goalLookAtCF)
-- Extract Y rotation to maintain turret's current Y rotation
local _, y, _ = goalCF:ToOrientation()
goalCF = CFrame.new(goalCF.Position) * CFrame.Angles(0, y, 0)
-- Gradually rotate towards the goal
TurretUnion.Motor6D.C0 = TurretUnion.Motor6D.C0:Lerp(goalCF, rotationSpeed * dt)
end)
Once again you save my life. Dude genuinely thank you so much for helping me out these last couple days it means the world to me
Now idk if this is the kind of stuff you’re also really good at but for some odd reason it deducts 2 from the TotalAmmo intvalue when you reload. Im assuming its because the reload function is fired twice but i cant seem to figure out why. Can you help here? If no, no sweat you’ve already helped PLENTY. Thank you so much
local body = script.Tank.Value.BodyKit
local tool = script.Parent
local event = game.ReplicatedStorage.TankSystem.RemoteEvents.TankTurretRotation
local TurretUnion = script.Tank.Value.BodyKit.Turret.PrimaryPart
local fireShell = event.Parent.FireShell
local debris = game:GetService("Debris")
local config = script.Tank.Value.Seat.Configuration
local ammoLeft = config.AmmoLeft
local totalAmmo = config.TotalAmmo
local reloading = false
local turret = script.Tank.Value.BodyKit.Turret -- Assuming turret is a model with PrimaryPart set
local startPart = script.Tank.Value.BodyKit.Turret.FirePart
local muzzlePart = script.Tank.Value.BodyKit.Turret.MuzzlePart
local barrelPart = script.Tank.Value.BodyKit.Turret.BarrelPart
local function Shoot(mousePosition)
if not turret.PrimaryPart then
warn("Turret does not have a PrimaryPart set!")
return
end
local turretPosition = startPart.Position
-- Get direction from turret to mouse position
local direction = (mousePosition - turretPosition).Unit
-- Raycast to detect impact point
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = {body} -- Ignore the tank itself
rayParams.FilterType = Enum.RaycastFilterType.Exclude
local rayResult = game.Workspace:Raycast(turretPosition, direction * 1000, rayParams)
-- Fire sound
local fireSound = Instance.new("Sound")
fireSound.SoundId = "rbxassetid://8213064126"
fireSound.Volume = 0.75
fireSound.Parent = barrelPart
fireSound:Play()
if not fireSound.Playing then
fireSound:Play()
end
-- Explosion effect
local function createExplosionAtImpact(hitPosition)
local explosion = Instance.new("Explosion")
explosion.Position = hitPosition
explosion.BlastRadius = 100
explosion.BlastPressure = 0 -- Increased explosion impact
explosion.ExplosionType = Enum.ExplosionType.NoCraters
explosion.Parent = game.Workspace
end
-- If the ray hits something, create explosion at the correct position
if rayResult then
local hitPosition = rayResult.Position
local distance = (hitPosition - turretPosition).Magnitude
-- Adjust delay based on realistic shell speed
local shellSpeed = 500 -- Adjust shell velocity
local delayTime = distance / shellSpeed
task.delay(delayTime, function()
createExplosionAtImpact(hitPosition)
end)
end
end
local function reload()
-- Prevent reloading if already in the process or if there's ammo left
if reloading or ammoLeft.Value >= 1 or totalAmmo.Value <= 0 then
return
end
reloading = true
local reloadSound = Instance.new("Sound")
reloadSound.SoundId = "rbxassetid://2721754456"
reloadSound.Volume = 0.75
reloadSound.Parent = barrelPart
if not reloadSound.Playing then
reloadSound:Play()
end
wait(3) -- Wait for reload time
-- Only reload if totalAmmo is available
if totalAmmo.Value > 0 then
ammoLeft.Value = 1 -- Refill one ammo
totalAmmo.Value = totalAmmo.Value - 1 -- Decrease totalAmmo by 1
end
reloading = false
end
event.Parent.FireShell.OnServerEvent:Connect(function(plr, mouseHitPosition)
if ammoLeft.Value > 0 and not reloading then
ammoLeft.Value = ammoLeft.Value - 1
Shoot(mouseHitPosition)
end
end)
ammoLeft:GetPropertyChangedSignal("Value"):Connect(function()
if ammoLeft.Value <= 0 and totalAmmo.Value >= 1 and not reloading then
reload()
end
end)
-- Function to calculate C0 from the world CFrame
local function worldCFrameToC0ObjectSpace(motor6DJoint, worldCFrame)
local part1CF = motor6DJoint.Part1.CFrame
local c1Store = motor6DJoint.C1
local c0Store = motor6DJoint.C0
local relativeToPart1 = c0Store * c1Store:Inverse() * part1CF:Inverse() * worldCFrame * c1Store
relativeToPart1 = relativeToPart1 - relativeToPart1.Position
local goalC0CFrame = relativeToPart1 + c0Store.Position
return goalC0CFrame
end
local rotationSpeed = 1.3 -- Adjust the rotation speed as needed
event.OnServerEvent:Connect(function(plr, dt, mousePosition)
local turretPosition = TurretUnion.CFrame.Position
local lookAtDirection = (mousePosition - turretPosition).unit -- Direction to look at
-- Calculate the goal orientation
local goalLookAtCF = CFrame.lookAt(Vector3.new(), Vector3.new(lookAtDirection.X, 0, lookAtDirection.Z))
-- Convert to local CFrame relative to Motor6D
local goalCF = worldCFrameToC0ObjectSpace(TurretUnion.Motor6D, goalLookAtCF)
-- Extract Y rotation to maintain turret's current Y rotation
local _, y, _ = goalCF:ToOrientation()
goalCF = CFrame.new(goalCF.Position) * CFrame.Angles(0, y, 0)
-- Gradually rotate towards the goal
TurretUnion.Motor6D.C0 = TurretUnion.Motor6D.C0:Lerp(goalCF, rotationSpeed * dt)
end)
And i dont wanna sound needy so if u dont wanna help any more thats perfectly fine but do you know how to make it shoot a ray out? I had this feature but i was shooting a part out but it was messing up with the collission system and the explosions were happenening prematurely so i switched to this.
But absolutely no worries if u dont wanna help out with that
the GetPropertyChangedSignal is being called twice for some reason. But you don’t really need it, you should never use these unless no other choice. You can just move your reload code after shooting and it will work.
event.Parent.FireShell.OnServerEvent:Connect(function(plr, mouseHitPosition)
if ammoLeft.Value > 0 and not reloading then
ammoLeft.Value = ammoLeft.Value - 1
Shoot(mouseHitPosition)
if ammoLeft.Value <= 0 and totalAmmo.Value >= 1 then
reload()
end
end
end)
as for collision issues, you should print what part is your bullet colliding with, and disable their collisions if not needed, or add NoCollisionConstraint between your bullet and parts that you want to not collide. If they don’t collide but the touched function is being called, you can also disable “CanTouch” on those parts and it should work.