How to make animated tank tracks?

I’m trying to make tank treads that match the speed of the roadwheels, but I am failing miserably. I named each track link in order with integer, the one next to it being the next integer.
I’ve tried to set one track link’s CFrame to the next one, which actually works quite well:
https://gyazo.com/4cb844523e05a7d75aaa6a77ad9a9d27 (the tracks are anchored)
The script I used for the above ^

local TS = game:GetService("TweenService")
local Model = script.Parent
local Speed = 0.65 -- How much time each tracklink will take to move to the next one

local tweenInfo = TweenInfo.new(Speed, Enum.EasingStyle.Linear)
-------

while true do
	task.spawn(function()
		for i = 1, #Model:GetChildren() - 1 do -- substracting 1 because the script is in there
			local nextTrackNum = i + 1

			if nextTrackNum > #Model:GetChildren() - 1 then nextTrackNum = 1 end

			local tween = TS:Create(Model[tostring(i)], info, {CFrame = Model[tostring(nextTrackNum)].CFrame})

			tween:Play()
		end
	end)
	task.wait(Speed)
end

However it doesn’t work when the tracks are welded to the tank’s base part (Where all the welds are), or the whole tank is gonna fling, due to weld logic and the CFrame being constantly updated by TweenService.

I’ve looked around in the devforum but there was no luck. How can I correctly place the treads around the roadwheels and prevent them from falling off, and react to the suspension? I don’t want to make physics-based tracks, as that will lag the game a lot. Thanks a lot in advance

EDIT: Changed plans. Didn’t delete the above script in case someone needs it. New problem is the title. I am using hinges to rotate the wheels for the part, but since they have custom acceleration, and there is no CurrentSpeed property in the hinge, there is a problem.

You can do the same thing, just use Weld.C0 to change the CFrame of the weld.

The tracks aren’t welded to each other (they are currently anchored, when I unanchor them and weld them to tank’s structure they fling off the entire tank)

In that case, you need to switch to normal welds. You should automatically create them using a script.

tbh I never tried auto-weld scripts, could you explain me how they work?

They simply set the C0 and C1 of the weld they create for each part to the inverse CFrame of Part0 subtracted from Part1's CFrame.

Part0 is usually the root of the model, or the Model.PrimaryPart.

Sorry for late reply. I was trying to think for a solution and I thought of animating the tracks with a texture. But in order to get the correct speed based on wheels, I needed the rotations per second of the wheel. Could you help?

local RunService = game:GetService("RunService")
local SetupTracksEvent = game.ReplicatedStorage:WaitForChild("SetupTracks")

local function sign(x: number)
	if x > 0 then return 1 end
	if x < 0 then return -1 end
	
	return 1
end

-- This is an event sent from the server, once the whole tank is loaded.
local function RenderTracks(data: {
	L: CylindricalConstraint,
	R: CylindricalConstraint,
	LTextures: Model,
	RTextures: Model,
	})
	local LSprocket: BasePart = data.L.Attachment1.Parent -- Left side roadwheel, for reference.
	local RSprocket: BasePart = data.R.Attachment1.Parent -- Right side roadwheel, for reference.
	
	local LeftDeltaMagnitude = nil
	local RightDeltaMagnitude = nil
	
	local InitialL = LSprocket.Orientation.X 
	local InitialR = RSprocket.Orientation.X
	
	while true do
		LeftDeltaMagnitude = math.abs(LSprocket.Orientation.X - InitialL)
		RightDeltaMagnitude = math.abs(RSprocket.Orientation.X - InitialR)
		
		InitialL = LSprocket.Orientation.X -- Update the X oriention variables to the new ones.
		InitialR = RSprocket.Orientation.X
		
		for i,v: Texture in ipairs(data.LTextures:GetDescendants()) do
			if v:IsA("Texture") then
				if v.Name == "SideL" then -- The side textures (one facing left Normal face) need different calculations.
					v.OffsetStudsU += LeftDeltaMagnitude * sign(data.L.AngularVelocity) / 60
				elseif v.Name == "SideR" then
					v.OffsetStudsU -= LeftDeltaMagnitude * sign(data.L.AngularVelocity) / 60
				else
					v.OffsetStudsV -= LeftDeltaMagnitude * sign(data.L.AngularVelocity) / 60
				end
			end
		end
		
		for i,v: Texture in ipairs(data.RTextures:GetDescendants()) do
			if v:IsA("Texture") then
				if v.Name == "SideL" then
					v.OffsetStudsU += RightDeltaMagnitude * sign(data.R.AngularVelocity) / 60
				elseif v.Name == "SideR" then
					v.OffsetStudsU -= RightDeltaMagnitude * sign(data.R.AngularVelocity) / 60
				else
					v.OffsetStudsV -= RightDeltaMagnitude * sign(data.R.AngularVelocity) / 60
				end
			end
		end
		RunService.RenderStepped:Wait()
	end
end
SetupTracks.OnClientEvent:Connect(RenderTracks)

EXTRA INFO:
HOW THE TRACKS WERE BUILT
They were placed one by one, in this shape, and put textures on the Top, Bottom, Left and Right faces. The bottom, bigger parts, is multiple-piece Unioned tracklinks that have the potential to interact with suspension.

HOW ONE TRACKLINK LOOKS LIKE
image

END RESULT


The textures don’t look very good, but if anyone’s trying to implement this and know how to correctly place the textures (correct offsets and studs per tile), please @ me. Above script is essentially an accurate way to move the tracks per RenderStep.

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