How to create the building mechanic from Lego games

So say i have a model of for example a simple house. How would I have it so when the player joins the game, that model is broken into bits and they can just hold on a proximity prompt to see their character build the model the same way as in those classic lego games.

3 Likes

Are you talking about something like this?
https://gyazo.com/b9adc2bd9ffa8aa7f8aab111353cd700

Very basic, it just allows Roblox physics to scatter the pieces and stores each part as well as CFrame of the part to later build it back when the ProximityPrompt is triggered – let me know if you’re looking for something more in-depth. :slight_smile:

BrokenHomeOfRobloxia.rbxl (47.4 KB)

2 Likes

Pretty much that but it builds one piece at a time and happens during the holdDuration of the proximity prompt.

You have some events to work with:

PromptButtonHoldBegan(playerWhoTriggered: Player)

PromptButtonHoldEnded(playerWhoTriggered: Player)

You can check holdbegan to start the construction and holdended to like explode it again or something.

Do @WrollingYou ‘s method but every (TotalTime/AmountOfParts) second you tween the part into the original position.

1 Like

I modified @WrollingYou 's script a bit but am not sure how id get the for loop go one part at a time as currently it does them all at once.

local function BuildHouse()
	for i,v in ipairs(HouseData) do
		task.spawn(function()
			v.Part.Anchored = true
			local Tween = TweenService:Create(v.Part, TweenInfo.new(holdDuration/amountOfParts), {CFrame = v.CF})
			Tween:Play()
		end)
	end
end
local WaitTime = holdDuration / amountOfParts
local function BuildHouse()
	for i,v in ipairs(HouseData) do
			v.Part.Anchored = true
			local Tween = TweenService:Create(v.Part, TweenInfo.new(0.1), {CFrame = v.CF})
			Tween:Play()
wait(WaitTime)
	end
end

Tweens aren’t yielding so there’s no need for spawn

1 Like

This works!
I was wondering, is there a way so if the player lets go of the proximity prompt before its completed, the building tween reverses and puts the parts back how they were destroyed.
Heres @WrollingYou 's modified code so far:

local TweenService = game:GetService('TweenService')

local model = game.Workspace.legobuilderik.House
local modelData = {}
local amountOfParts = 0

local proximityPrompt = script.Parent.ProximityPrompt
local holdDuration = script.Parent.ProximityPrompt.HoldDuration

local buildCompleted = false

for i,v in ipairs(model:GetChildren()) do
	if v:IsA('BasePart') then
		table.insert(modelData,{
			Part = v,
			CF = v.CFrame
		})
		v.Anchored = false
		v.CFrame = v.CFrame*CFrame.Angles(math.rad(math.random(0,180)),math.rad(math.random(0,180)),math.rad(math.random(0,180)))
	end
	amountOfParts += 1
end

proximityPrompt.PromptButtonHoldBegan:Connect(function()
	for i,v in ipairs(modelData) do
		v.Part.Anchored = true
		local Tween = TweenService:Create(v.Part, TweenInfo.new(0.1), {CFrame = v.CF})
		Tween:Play()
		wait(holdDuration / amountOfParts)
	end
	buildCompleted = true
end)

proximityPrompt.PromptButtonHoldEnded:Connect(function()
	if buildCompleted == false then
		--somehow reverse the tween
	end
end)

Wouldn’t it be more realistic if the parts were scattered using the physics engine? Also including a way to re-scatter it if you stop holding?

Hint: a bomb :slight_smile:

1 Like

:slight_smile: Awesome to see y’all expanded on the lil code I wrote, here’s some code that allows for reversing when the player hasn’t fully built the building:

local TweenService = game:GetService('TweenService')
local RunService = game:GetService('RunService')

local model = game.Workspace.legobuilderik.House
local modelData = {}
local amountOfParts = 0

local proximityPrompt = script.Parent.ProximityPrompt
local holdDuration = script.Parent.ProximityPrompt.HoldDuration
local TimestampHeld = 0
local BuildTweens = {}
local ReverseTweens = {}
local Connections = {}
local count = 0
local Building = false
local Debounce = false

local buildCompleted = false

Connections[model] = {} -- We use model as key so we can clear connections just for that specific model in the future when there's multiple buildings you want to build 

for i,v in ipairs(model:GetChildren()) do
	if v:IsA('BasePart') then
		if not BuildTweens[model] then
			BuildTweens[model] = {}
		end
		table.insert(BuildTweens[model], TweenService:Create(v, TweenInfo.new(0.1), {CFrame = v.CFrame}))
		v.Anchored = false
		v.CFrame = v.CFrame*CFrame.Angles(math.rad(math.random(0,180)),math.rad(math.random(0,180)),math.rad(math.random(0,180)))
	end
	amountOfParts += 1
end

local DisconnectConnections = function()
	for i,v in ipairs(Connections[model]) do
		v:Disconnect()
		Connections[model][i] = nil
	end
	Connections[model] = {}
end

local GetReverseTweens = function()
	for i,v in ipairs(model:GetChildren()) do
		if not ReverseTweens[model] then
			ReverseTweens[model] = {}
		end
		table.insert(ReverseTweens[model],TweenService:Create(v, TweenInfo.new(0.1), {CFrame = v.CFrame}))
		v.Anchored = true
	end
end

-- we use a really long wait to rather ensure the parts have all fallen into place, I would probably recommend presetting the dictionaries containing the tweens
-- by letting the parts fall into a position in studio, then grab the CFrames of where they fell, that way you don't have to wait and hope they've fallen correctly
task.wait(5)

GetReverseTweens()

proximityPrompt.PromptButtonHoldBegan:Connect(function()
	TimestampHeld = os.clock()
	Building = true
	table.insert(Connections[model],RunService.Heartbeat:Connect(function()
		if not Debounce then
			Debounce = true
			count = count+1
			local BuildTween = BuildTweens[model][count]
			
			if not BuildTween then 
				DisconnectConnections()
			else
				BuildTween:Play()
				wait(holdDuration / amountOfParts)
			end
			
			Debounce = false
		end
	end))
end)

proximityPrompt.PromptButtonHoldEnded:Connect(function()
	if holdDuration-(os.clock()-TimestampHeld) <= .01 then -- this is to account for floating point inaccuracies, if there's less than .01 second left, we assume it's built
		buildCompleted = true
	end
	if buildCompleted == false then
		Building = false
		count = 0
		DisconnectConnections()
		
		for i,v in ipairs(ReverseTweens[model]) do
			v:Play()
		end
	end
end)

If you have more questions, feel free to ask. :slight_smile:

1 Like

Yes this works well thank you!!
I simple modified the timing to happen a bit slower and it works great!

Awesome! :slight_smile: Glad I could help!

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