What do you want to achieve? Keep it simple and clear!
So basically while testing the game in both Studio and Roblox Player, I noticed that while driving a ship the memory jumps gradually. And so I suspect that there might be a memory leak inside of the script which I can’t seem to find and fix. I would be grateful if anybody could find where the leak might be coming from and offer a solution or alternative method of the script.
math.randomseed(tick())
local Players = game:GetService('Players')
local StarterPack = game:GetService('StarterPack')
local StarterGui = game:GetService('StarterGui')
local Lighting = game:GetService('Lighting')
local Debris = game:GetService('Debris')
local Teams = game:GetService('Teams')
local BadgeService = game:GetService('BadgeService')
local InsertService = game:GetService('InsertService')
local Terrain = workspace.Terrain
local VerifyArg
local function IsA(value, data_type)
data_type = VerifyArg(data_type, 'string', "data_type")
if type(value) == data_type then return true end -- Lua types
if pcall(function() assert(game.IsA(value, data_type)) end) then return true end -- Instance types
if pcall(function() assert(Enum[data_type]) end) then -- Enum types
for _, enum in next, Enum[data_type]:GetEnumItems() do
if value == enum then
return true
end
end
elseif pcall(Enum.Material.GetEnumItems, value) then
for _, enum in next, value:GetEnumItems() do
if value == enum then
return true
end
end
end
if data_type == 'Color3' and pcall(function() Instance.new('Color3Value').Value = value end) then return true -- Color3
elseif data_type == 'BrickColor' and pcall(function() Instance.new('BrickColorValue').Value = value end) then return true -- BrickColor
elseif data_type == 'Vector2' and pcall(function() return Vector2.new() + value end) then return true -- Vector2
elseif data_type == 'Vector3' and pcall(function() Instance.new('Vector3Value').Value = value end) then return true -- Vector3
elseif (data_type == 'CFrame' or data_type == 'CoordinateFrame') and pcall(function() Instance.new('CFrameValue').Value = value end) then return true -- CFrame
elseif data_type == 'UDim' and pcall(function() return UDim.new() + value end) then return true -- UDim
elseif data_type == 'UDim2' and pcall(function() Instance.new('Frame').Position = value end) then return true -- UDim2
elseif data_type == 'Ray' and pcall(function() Ray.new(Vector3.new(), Vector3.new()).Distance(value, Vector3.new()) end) then return true -- Ray
elseif data_type == 'Axes' and pcall(function() Instance.new('ArcHandles').Axes = value end) then return true -- Axes
elseif data_type == 'Faces' and pcall(function() Instance.new('Handles').Faces = value end) then return true -- Faces
elseif data_type == 'Enum' and pcall(Enum.Material.GetEnumItems, value) then return true -- Enum
elseif data_type == 'RBXScriptSignal' then
local _, connection = pcall(function() return game.AllowedGearTypeChanged.connect(value) end)
if _ and connection then
connection:disconnect()
return true
end
end
return false
end
local function CppIsA(value, data_type)
data_type = VerifyArg(data_type, 'string', "data_type")
if data_type == 'int' then
if pcall(function() Instance.new('IntValue').Value = value end) then
return true
end
elseif data_type == 'double' then
if pcall(function() Instance.new('NumberValue').Value = value end) then
return true
end
elseif data_type == 'bool' then
if pcall(function() Instance.new('BoolValue').Value = value end) then
return true
end
elseif data_type == 'string' then
if pcall(function() Instance.new('StringValue').Value = value end) then
return true
end
elseif data_type == 'float' then
if pcall(function() Instance.new('ClickDetector').MaxActivationDistance = value end) then
return true
end
end
return false
end
local function GetType(value)
if IsA(value, 'Instance') then return value.ClassName
elseif IsA(value, 'Enum') then return 'Enum'
elseif IsA(value, 'Color3') then return 'Color3'
elseif IsA(value, 'BrickColor') then return 'BrickColor'
elseif IsA(value, 'Vector2') then return 'Vector2'
elseif IsA(value, 'Vector3') then return 'Vector3'
elseif IsA(value, 'CFrame') then return 'CFrame'
elseif IsA(value, 'UDim') then return 'UDim'
elseif IsA(value, 'UDim2') then return 'UDim2'
elseif IsA(value, 'Ray') then return 'Ray'
elseif IsA(value, 'Axes') then return 'Axes'
elseif IsA(value, 'Faces') then return 'Faces'
elseif IsA(value, 'RBXScriptSignal') then return 'RBXScriptSignal'
else return type(value)
end
end
function VerifyArg(value, data_type, arg_name, optional)
if type(data_type) ~= 'string' then error("bad 'data_type' argument (string expected, got " .. GetType(data_type) .. ")", 2) end
if type(arg_name) ~= 'string' then error("bad 'arg_name' argument (string expected, got " .. GetType(arg_name) .. ")") end
if optional and value == nil then
return value
elseif type(value) == data_type then
return value
elseif IsA(value, data_type) or CppIsA(value, data_type) then
return value
elseif data_type == 'number' and tonumber(value) then
return tonumber(value)
elseif data_type == 'string' and type(value) == 'number' then
return tostring(value)
else
error("bad '" .. arg_name .. "'" .. (optional and " optional" or "") .. " argument (" .. data_type .. " expected, got " .. GetType(value) .. ")", 3)
end
end
local function Modify(instance, t)
instance = VerifyArg(instance, 'Instance', "instance")
t = VerifyArg(t, 'table', "t")
for key, value in next, t do
if type(key) == 'number' then
value.Parent = instance
else
instance[key] = value
end
end
return instance
end
local function WaitForChild(Parent, Name)
Parent = VerifyArg(Parent, 'Instance', "Parent")
Name = VerifyArg(Name, 'string', "Name")
local Item = Parent:FindFirstChild(Name)
if not Item then
repeat wait(0) print("Waiting for "..Name) Item = Parent:FindFirstChild(Name) until Item
end
return Item;
end
local function CallOnChildren(instance, func)
instance = VerifyArg(instance, 'Instance', "instance")
func = VerifyArg(func, 'function', "func")
func(instance)
for _, child in next, instance:GetChildren() do
CallOnChildren(child, func)
end
end
local function GetNearestParent(instance, class_name)
instance = VerifyArg(instance, 'Instance', "instance")
class_name = VerifyArg(class_name, 'string', "class_name")
local ancestor = instance
repeat
ancestor = ancestor.Parent
if ancestor == nil then
return nil
end
until ancestor:IsA(class_name)
return ancestor
end
local function GetCharacter(descendant)
descendant = VerifyArg(descendant, 'Instance', "descendant")
local character = descendant
repeat
if character.Parent then
character = character.Parent
else
return nil
end
until Players:GetPlayerFromCharacter(character)
return character, Players:GetPlayerFromCharacter(character)
end
-- Variables --
local ParentNamesNoDetect = {Water = true; Bodykit = true; Projectiles = true; Water = true; ["!Water"] = true; Wake = true;}
local ChildrenParentNoDetect = {"Humanoid"}
local NamesNoDetect = {Wake = true;}
local WaterLevel = 27
local ShipGui = WaitForChild(script, "ShipGui")
local function RoundNumber(Number, Divider)
Divider = Divider or 1
return (math.floor((Number/Divider)+0.5)*Divider)
end
local function ClampNumber(Number, High, Low)
if Number > High then
return High;
elseif Number < Low then
return Low;
end
return Number;
end
local function MPStoKPS(MPS) -- Meters per a econd to Kilometers per a second
return MPS * 3.6
end
local function SetupBoat(Boat, VehicleSeat, Configuration)
--local Boat = script.Parent
--local VehicleSeat = WaitForChild(Boat, "VehicleSeat")
--local Base = WaitForChild(Boat, "Base")
local EngineSound = WaitForChild(VehicleSeat, "EngineSound")
local BodyGyro = WaitForChild(VehicleSeat, "BodyGyro")
local BodyVelocity = WaitForChild(VehicleSeat, "BodyVelocity")
local BodyPosition = WaitForChild(VehicleSeat, "BodyPosition")
local BodyAngularVelocity = WaitForChild(VehicleSeat, "BodyAngularVelocity")
local Wake = Modify(Instance.new("Model", Boat), {Name="Wake"})
local CurrentHeight = VehicleSeat.Position.Y
local CannonReloadTime = 7
local CannonVelocity = 300
local CannonLifeTime = 60
local maxfiretime = 1
local lestfiretime = 0.1
local multiplier = 100
local function GetCharacter(descendant)
local character = descendant
repeat
if character.Parent then
character = character.Parent
else
return nil
end
until Players:GetPlayerFromCharacter(character)
return character, Players:GetPlayerFromCharacter(character)
end
local function SetCannonRow(TextButton, RowTag, Ship)
local debounce = false
local FireableRows = {}
local Smoke = Instance.new("Smoke")
Smoke.Name = "CannonSmoke"
Smoke.Color = Color3.new(1,1,1)
Smoke.Size = 3
Smoke.Enabled = true
Smoke.RiseVelocity = 6
Smoke.Opacity = .25
local Ball = Instance.new("Part")
Ball.Shape = "Ball"
Ball.Anchored = false
Ball.CanCollide = false
Ball.Locked = true
Ball.FormFactor = "Custom"
Ball.TopSurface = "Smooth"
Ball.BottomSurface = "Smooth"
Ball.BrickColor = BrickColor.new("Dark stone grey")
Ball.Material = "CorrodedMetal"
Ball.Size = Vector3.new(1.5, 1.5, 1.5)
Ball.Name = "CannonBall"
local function FireOffRow(row)
if row:isA("Model") then
for a, b in pairs(row:getChildren()) do
if b:isA("Model") and b.Name == "Cannon" and b:findFirstChild("Fire") and b:findFirstChild("SmokeHold") then
delay(math.random((lestfiretime*multiplier),(maxfiretime*multiplier))/multiplier, function()
local Smoke2 = Smoke:clone()
Smoke2.Parent = b.SmokeHold
Debris:AddItem(Smoke2, SmokeExistanceTime)
local Ball2 = Ball:clone()
Ball2.Parent = workspace
Debris:AddItem(Ball2, BallLifeTime)
Ball2.CFrame = b.Fire.CFrame * CFrame.new(0, 0,4)
Ball2.Velocity = b.Fire.CFrame.lookVector*(CannonVelocity*-1)
Ball2.Touched:connect(function(p)
if Ball2 and p and p.Parent then
local Character, Player = GetCharacter(p)
if Character and Character:FindFirstChild("Humanoid") and Character.Humanoid:IsA("Humanoid") then
Character.Humanoid.Health = Character.Humanoid.Health - 100;
end
local Explosion = Instance.new("Explosion",workspace)
Explosion.Name = "CannonExplosion"
Explosion.BlastRadius = 7
Explosion.Position = Ball2.Position
Ball2:Destroy()
end
end)
print("Cannon fired!")
end)
end
end
end
end
for a, b in pairs(Ship:GetChildren()) do
if b:IsA("Model") and b:FindFirstChild("Is_A_Cannon") and b:FindFirstChild("Is_A_Cannon").Value == RowTag then
table.insert(FireableRows, b)
end
end
TextButton.MouseButton1Down:connect(function()
if not debounce then
debounce = true
TextButton.Selected = true
TextButton.TextColor3 = Color3.new(1, 0, 0)
for a, b in pairs(FireableRows) do
FireOffRow(b)
end
local WaitTime = CannonReloadTime / 0.05
for i=0, 1, (1/WaitTime) do
wait(0.05)
TextButton.TextColor3 = Color3.new(1,i,i)
end
TextButton.TextColor3 = Color3.new(1,1,1)
TextButton.Selected = false
debounce = false
end
end)
end
local Config = Configuration
Config.NeutralColor = BrickColor.new("Dark stone grey");
local function SetupTouch(Part)
for _, Item in pairs(Part:GetChildren()) do
if Item:IsA("BasePart") then
local Name = string.lower(Item.Name)
if Name == "hitdetect" or Name == "hitdetectrecolor" then
Item.Touched:connect(function(NewPart)
print("Touch")
if NewPart and NewPart.Parent and NewPart:IsA("BasePart") and NewPart.CanCollide then
if not (ParentNamesNoDetect[NewPart.Parent.Name] or NamesNoDetect[NewPart.Name]) then
VehicleSeat.MaxSpeed = 0
print("Stop")
else
local Valid = true
for _, ChildName in pairs(ChildrenParentNoDetect) do
if NewPart.Parent:FindFirstChild(ChildName) then
Valid = false
end
end
if Valid then
print("Stop")
VehicleSeat.MaxSpeed = 0
end
end
end
end)
end
end
SetupTouch(Item)
end
end
local function Recolor(Part, Color)
--EnemyValue.Value = Color;
for _, Item in pairs(Part:GetChildren()) do
if Item:IsA("BasePart") then
local Name = string.lower(Item.Name)
if Name == "recolor" or Name == "hitdetectrecolor" then
Item.BrickColor = Color
end
end
Recolor(Item, Color)
end
end
Recolor(Boat, Config.NeutralColor)
SetupTouch(Boat)
BodyPosition.position = Vector3.new(0, CurrentHeight, 0)
VehicleSeat.ChildAdded:connect(function(Child)
spawn(function()
if Child:IsA("Weld") then
local Torso = Child.Part1
if Torso and Torso:IsA("BasePart") then
local Character, Player = GetCharacter(Torso)
if Character and Player then
for _, Item in pairs(Character:GetChildren()) do
if Item:IsA("Model") and Item ~= Boat then
--Item:Destroy(); -- Remove all other boats.
end
end
Boat.Parent = game.Workspace
VehicleSeat.Anchored = false
Recolor(Boat, Player.TeamColor)
repeat wait(0) until Player:FindFirstChild("PlayerGui")
local Gui = ShipGui:Clone()
local MainFrame = WaitForChild(Gui, "MainFrame")
local ShipName = WaitForChild(MainFrame, "ShipName")
local ShipSpeed = WaitForChild(MainFrame, "ShipSpeed")
local FireCannon = WaitForChild(MainFrame, "Fire")
--SetCannonRow(FireCannon, "ShipCannon", Boat.BodyKit)
ShipName.Text = Config.ShipName
ShipSpeed.Text = "Shipspeed: 0.000 m/ps";
local function UpdateHeight()
print("Updating ship height to "..CurrentHeight)
BodyPosition.position = Vector3.new(0, CurrentHeight, 0)
end
spawn(function()
while Gui and Gui.Parent do
wait(0.07)
ShipSpeed.Text = "Shipspeed: "..RoundNumber(MPStoKPS(VehicleSeat.Velocity.magnitude/20), 0.001).." KPH"
end
--for i,v in pairs(script.Parent.Parent:GetDescendants()) do
--if v.ClassName == "ParticleEmitter" then
--v.Enabled = false
--end
--end
Player:WaitForChild("canDash").Value = true
Player:WaitForChild("canRun").Value = true
--print("Connection disconnected")
end)
Player:WaitForChild("canDash").Value = false
Player:WaitForChild("canRun").Value = false
Gui.Parent = Player.PlayerGui
Child.AncestryChanged:connect(function(Child, Parent)
if not Parent then
if Gui then
Gui:Destroy()
end
Recolor(Boat, Config.NeutralColor)
VehicleSeat.TurnSpeed = 0
VehicleSeat.MaxSpeed = 0
end
end)
end
end
end
end)
end)
local RotationX, RotationY, RotationZ = VehicleSeat.CFrame:toEulerAnglesXYZ()
BodyGyro.cframe = CFrame.Angles(0, RotationY, 0)
Boat:MakeJoints()
while true do
local VehicleSeatThrottle = VehicleSeat.Throttle
local VehicleSeatMaxSpeed = VehicleSeat.MaxSpeed
local VehicleSeatSteer = VehicleSeat.Steer
if VehicleSeatThrottle == 1 then
if VehicleSeatMaxSpeed < Config.TopSpeed + 0.5 then
--for i,v in pairs(script.Parent.Parent:GetDescendants()) do
-- if v.ClassName == "ParticleEmitter" then
--v.Enabled = true
--end
--end
VehicleSeat.MaxSpeed = VehicleSeatMaxSpeed + VehicleSeat.Torque
end
elseif VehicleSeatThrottle == -1 then
if VehicleSeatMaxSpeed > -Config.TopSpeedReverse - 0.5 then
--for i,v in pairs(script.Parent.Parent:GetDescendants()) do
--if v.ClassName == "ParticleEmitter" then
--if v.Enabled == true then
--v.Enabled = false
--end
--end
--end
VehicleSeat.MaxSpeed = VehicleSeatMaxSpeed - VehicleSeat.Torque
end
end
if VehicleSeatSteer == 1 then
if VehicleSeat.TurnSpeed > -Config.MaxTurn then
VehicleSeat.TurnSpeed = VehicleSeat.TurnSpeed - Config.TurnSpeedAddition
end
elseif VehicleSeatSteer == -1 then
if VehicleSeat.TurnSpeed < Config.MaxTurn then
VehicleSeat.TurnSpeed = VehicleSeat.TurnSpeed + Config.TurnSpeedAddition
end
elseif VehicleSeatSteer == 0 then
if VehicleSeat.TurnSpeed < 0 then
VehicleSeat.TurnSpeed = VehicleSeat.TurnSpeed + Config.TurnSpeedAddition
elseif VehicleSeat.TurnSpeed > 0 then
VehicleSeat.TurnSpeed = VehicleSeat.TurnSpeed - Config.TurnSpeedAddition
end
if VehicleSeat.TurnSpeed <= Config.TurnStop and VehicleSeat.TurnSpeed >= -Config.TurnStop then
VehicleSeat.TurnSpeed = 0
end
end
local Pitch = math.abs(VehicleSeat.MaxSpeed) / 10 + 2.5
if VehicleSeatMaxSpeed > 0 then
if Config.PlayEngineSound then
EngineSound.Pitch = Pitch
EngineSound:Play()
end
elseif VehicleSeatMaxSpeed < 0 then
if Config.PlayEngineSound then
EngineSound.Pitch = Pitch
EngineSound:Play()
end
else
EngineSound:Stop()
end
--BodyGyro.cframe = CFrame.Angles(0, (AngleY) + VehicleSeat.TurnSpeed, 0) * CFrame.new(Direction.p+Vector3.new(0,0,-1))
--BodyGyro.cframe = VehicleSeat.CFrame * CFrame.Angles(0, VehicleSeat.TurnSpeed, 0) --BodyGyro.cframe * CFrame.Angles(0, VehicleSeat.TurnSpeed, 0) -- VehicleSeat.CFrame * CFrame.Angles(0, VehicleSeat.TurnSpeed, 0)
--BodyGyro.cframe = (VehicleSeat.CFrame.lookVector * CFrame.new(1, 0, 0)) * CFrame.Angles(0, VehicleSeat.TurnSpeed, 0)
--print("Ship to be angled at "..((AngleY) + VehicleSeat.TurnSpeed)*(180/math.pi).." with AngleY (Actual) at "..(AngleY*(180/math.pi)).." with an increase of "..VehicleSeat.TurnSpeed*(180/math.pi))
BodyAngularVelocity.angularvelocity = Vector3.new(0, VehicleSeat.TurnSpeed, 0)
--local Direction = VehicleSeat.CFrame
--local AngleX, AngleY, AngleZ = Direction:toEulerAnglesXYZ()
local Guide = VehicleSeat.CFrame * CFrame.new(-1, 0, 0)
BodyGyro.cframe = CFrame.new(VehicleSeat.Position, Vector3.new(Guide.X, VehicleSeat.CFrame.Y + (-Config.TiltFactor * (VehicleSeat.TurnSpeed/Config.MaxTurn)), Guide.Z))
BodyVelocity.velocity = VehicleSeat.CFrame.lookVector * VehicleSeat.MaxSpeed
wait(0.1)
end
end
-- Variables --
local Boat = script.Parent.Parent
local VehicleSeat = script.Parent
local Config = {
TopSpeed = 30; -- How fast it can go. (In studs)
TopSpeedReverse = 15; -- How fast is can go in reverse (In studs)
MaxTurn = 0.5; -- 1 = complete turn in 1 second 0.5 means complete turn (360) in 2 seconds.
TurnSpeedAddition = 0.05;
TurnStop = 0.3;
TiltFactor = 0.1; -- Amount it tilts.
ShipName = script.Parent.Parent.Name;
}
SetupBoat(Boat, VehicleSeat, Config)
Thanks in advance!