Tank works fine first shot but then becomes weird on second?

It was hard giving this a title because i am genuinely so confused on whats going on here.

I have a tank which i’ve made work and by me i mean chatgpt :skull: because i am not this advanced. Anyway whenever I test play, i can shoot once perfectly fine but then when i try to shoot twice the explosion just happens as if its hit something invisible.

I’ve tried disabling cancollide on all parts of the entire tank to see if that was causing it but thats not it.

Video example:
robloxapp-20250212-0301493.wmv (1.3 MB)

Full script:

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 config = script.Tank.Value.Seat.Configuration

local ammoLeft = config.AmmoLeft
local totalAmmo = config.TotalAmmo
local ammoType = config.AmmoType
local reloading = false

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 switchAmmoType = event.Parent.SwitchAmmoType

local ammoTypes = {
	AP = {name = "Armor-Piercing", damage = 0, speed = 300},
	HE = {name = "High-Explosive", damage = 0, speed = 200}
}

local startPart = script.Tank.Value.BodyKit.Turret.FirePart
local turret = script.Tank.Value.BodyKit.Turret  -- Assuming turret is a model with PrimaryPart set

local barrelPart = script.Tank.Value.BodyKit.Turret.BarrelPart

local function Shoot(mousePosition)
	-- Ensure turret has a PrimaryPart set
	if not turret.PrimaryPart then
		warn("Turret does not have a PrimaryPart set!")
		return
	end

	ammoLeft.Value = ammoLeft.Value - 1

	-- Recalculate the position of the FirePart (from the barrel) and the direction the turret is facing
	local turretPosition = startPart.Position  -- FirePart's current position
	local turretDirection = turret.PrimaryPart.CFrame.LookVector  -- Direction the turret is pointing

	-- Calculate the direction based on the mouse position (vertical angle adjustment)
	local camera = game.Workspace.CurrentCamera
	local mouseDirection = (mousePosition - camera.CFrame.Position).Unit  -- Mouse direction relative to camera
	local angle = math.asin(mouseDirection.Y)  -- Use mouse's Y position to adjust the vertical angle

	-- Apply this angle to adjust the turret's firing direction
	local upDownDirection = Vector3.new(turretDirection.X, math.sin(angle), turretDirection.Z).Unit

	-- Calculate the target position (shooting in the adjusted direction)
	local targetPosition = turretPosition + upDownDirection * 1000  -- Extend the direction for the shell to travel

	-- Create a shell (using MeshPart for better visuals)
	local shell = Instance.new("Part")
	shell.Size = Vector3.new(0.3, 0.3, 5)  -- Adjust size as needed (longer shell)
	shell.CFrame = CFrame.new(turretPosition, targetPosition)  -- Point shell in the turret's adjusted direction
	shell.BrickColor = BrickColor.new("New Yeller")  -- Yellow color for the shell
	shell.Material = Enum.Material.Metal  -- Make it look more realistic
	shell.CanCollide = true
	shell.Shape = Enum.PartType.Cylinder
	shell.Material = Enum.Material.Neon
	shell.Parent = game.Workspace
	shell.Transparency = 1

	-- Apply initial velocity for realistic trajectory (add gravity)
	local initialVelocity = upDownDirection * 1000  -- Consistent speed for the shell
	local gravity = Vector3.new(0, -9.8, 0)  -- Gravity pulling the shell down
	local velocity = initialVelocity + gravity  -- Combine initial velocity with gravity

	-- Apply LinearVelocity for constant speed with gravity
	local linearVelocity = Instance.new("LinearVelocity")
	linearVelocity.MaxForce = Vector3.new(5000, 5000, 5000)  -- High force to overcome gravity and keep the shell moving
	linearVelocity.VectorVelocity = velocity  -- Combined velocity with gravity
	linearVelocity.Parent = shell
	shell.AssemblyLinearVelocity = linearVelocity.VectorVelocity  -- Apply the velocity to the shell

	-- Create a fire trail effect (long and bright)
	local trail = Instance.new("Trail")
	trail.Parent = shell
	trail.Lifetime = NumberRange.new(0.3, 0.5)  -- Adjust trail length
	trail.Texture = "rbxassetid://123456789"  -- Replace with your desired texture
	trail.Color = ColorSequence.new(Color3.fromRGB(255, 255, 0), Color3.fromRGB(255, 100, 0))  -- Yellow to orange gradient
	trail.Enabled = true

	local att0 = Instance.new("Attachment")
	att0.Parent = shell
	att0.Position = Vector3.new(0,0,10)

	local att1 = Instance.new("Attachment")
	att1.Parent = shell
	att1.Position = Vector3.new(0,0,-10)

	trail.Attachment0 = att0
	trail.Attachment1 = att1


	-- Create a sound effect for firing the shell
	local fireSound = Instance.new("Sound")
	fireSound.SoundId = "rbxassetid://8213064126"  -- Replace with your sound ID
	fireSound.Volume = 0.75
	fireSound.Parent = barrelPart  -- Attach it to the barrel so it doesn't get removed with the shell
	fireSound:Play()

	-- Remove the sound only after it fully plays
	fireSound.Ended:Connect(function()
		fireSound:Destroy()
	end)


	-- Handle explosion effect when shell hits something
	local function createExplosionAtImpact(hitPosition)
		-- Create explosion at impact point
		local explosion = Instance.new("Explosion")
		explosion.Position = hitPosition
		explosion.BlastRadius = 50  -- Increased radius for a bigger explosion
		explosion.BlastPressure = 0  -- Increased pressure for a stronger explosion
		explosion.ExplosionType = Enum.ExplosionType.NoCraters
		explosion.Parent = game.Workspace
	end

	-- Shell collision detection and explosion trigger
	shell.Touched:Connect(function(hit)
		if hit and hit.CanCollide then
			-- Trigger explosion at impact location
			createExplosionAtImpact(shell.Position)

			-- Destroy shell after collision
			shell:Destroy()
		end
	end)


	game:GetService("Debris"):AddItem(shell, 5)
end


local function reload(ammoText)
	reloading = true
	local reloadSound = Instance.new("Sound")
	reloadSound.SoundId = "rbxassetid://2721754456"
	reloadSound.Volume = 0.75
	reloadSound.Parent = barrelPart
	reloadSound:Play()

	wait(3)
	ammoLeft.Value = ammoLeft.Value +1
	totalAmmo.Value = totalAmmo.Value -1
	reloading = false
end

event.Parent.FireShell.OnServerEvent:Connect(function(plr, mouseHitPosition)
	if ammoLeft.Value >= 1 and reloading == false then
		Shoot(mouseHitPosition)
	end
end)

ammoLeft:GetPropertyChangedSignal("Value"):Connect(function()
	if ammoLeft.Value <= 0 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.Position
	local goalC0CFrame = relativeToPart1 + c0Store.Position
	return goalC0CFrame
end

local rotationSpeed = .05  -- Adjust this value for faster or slower rotation

event.OnServerEvent:Connect(function(plr, mousePosition)
	-- Calculate the target position for the turret to look at
	local lookPos = Vector3.new(mousePosition.X, TurretUnion.CFrame.Position.Y, mousePosition.Z)
	local goalCF = CFrame.lookAt(TurretUnion.CFrame.Position, lookPos)

	-- Smoothly rotate the Turret to the goal CFrame using Lerp
	local currentCF = TurretUnion.Motor6D.C0
	local newCF = worldCFrameToC0ObjectSpace(TurretUnion.Motor6D, goalCF)
	TurretUnion.Motor6D.C0 = currentCF:Lerp(newCF, rotationSpeed)
end)

Please help :sob:

I would recommend just printing out what the shell touched in your function. You could have an issue with the bullet handing hanging around or something, but identifying what it’s hitting would be a good first step.

Figured out that somehow its hitting itself? I tried printing the name and the shell literally hits itself and explodes somehow… Im confused

I would make a folder for all of the bullets. So when a collision is detected, return if the colliding part is a descendant of that folder, or if it’s a descendant of the player who shot it.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.