Working On Some Ideas For Physics Puzzle Mechanics

I’ve been working on a grab mechanic for a future game where players can pick up and throw props around and interact with the environment/solve puzzles using physics. It’s pretty bare-bones at this point, but I’ve thrown together a few clips of my progress so far.


I put an attachment inside of each grabbable part, and an AlignPosition is applied to them to place them in front of the player’s camera when they pick them up:

-- LocalScript Magic
local grabParams = function() : RaycastParams
	local newParams = RaycastParams.new()
	newParams.FilterType = Enum.RaycastFilterType.Include
	newParams.FilterDescendantsInstances = CollectionSVC:GetTagged("PhysObject")
	return newParams
end

local function GrabCast(camCF : CFrame)
	return workspace:Raycast(camCF.Position, camCF.LookVector*6.5, grabParams())
end

mouse.Button1Down:Connect(function()
	local camCF = camera.CFrame
	local grab = GrabCast(camCF)
	
	if not grabObj and not grab then return end
	-- grabObj is whatever part is being held, if any
	
	Events.GrabEvent:FireServer(grabObj or grab.Instance, grabObj and 1 or 0)
	-- allows the server to change NetworkOwnership of picked up/dropped parts
	
	grabObj = (grab and not grabObj) and grab.Instance or nil
	-- determines whether the click was to pick up a part or drop a held one
	
	grabber.Parent = grabObj or ReplicatedStorage
	
	grabber.Attachment0 = grabObj and grabObj:FindFirstChild("GrabAttach") or nil
	
end)

local NewHighlighter = function() : Highlight
	local highlight = Instance.new("Highlight", ReplicatedStorage)
	highlight.Name = "GrabHighlight"
	return highlight
end

local highlighter = NewHighlighter()

RunSVC.Heartbeat:Connect(function(delta)
	local camCF = camera.CFrame

	grabber.Position = camCF.Position + (camCF.LookVector*6)

	local grab = GrabCast(camCF)

	if not highlighter then
		highlighter = NewHighlighter()
	end
	 -- In case a held part gets deleted along with the highlight for whatever reason

	highlighter.Parent = (grab and not grabObj) and grab.Instance or ReplicatedStorage
	highlighter.Adornee = (grab and not grabObj) and grab.Instance or nil

end)
-- ServerScript
grabEvent.OnServerEvent:Connect(function(player, grabObject : BasePart, state : number)
	grabObject:SetAttribute("CanGrab", state == 1)
	-- makes sure no other player can grab a part while it's being held
	grabObject:SetNetworkOwner(state == 0 and player or nil)
	-- decides ownership based on whether part is being picked up or dropped
end)

Players can also grab parts attached to others, like this turning gear:

-- How the display numbers are calculated [ServerScript]
local RunSVC = game:GetService("RunService")

local demoModel = script.Parent
local displayGui = demoModel.TV.Screen:WaitForChild("Display", 5)
local gear = demoModel:WaitForChild("Gear1", 5)

RunSVC.Heartbeat:Connect(function(delta)
	for i,label : TextLabel in ipairs(displayGui:GetChildren()) do
		label.Text = math.floor(math.deg(-gear.CFrame.UpVector.Z)%360).."°"
	end
end)

I also made a light that checks the length of the spring attached to the switch to turn the bulb on and off:

-- How the bulb works [ServerScript]
local bulb = script.Parent
local spring = bulb:FindFirstChild("SpringConstraint") :: SpringConstraint
local light = bulb:FindFirstChild("PointLight") :: PointLight

local on = false

while task.wait(.1) do
	if spring.CurrentLength < 10 then continue end
	on = not on
	bulb.BrickColor = BrickColor.new(on and "Cool yellow" or "Really black")
	light.Enabled = on
	repeat task.wait(.1) until spring.CurrentLength < 10
end

As well as this scale that’s held up by a few different constraints:


There’s no script attached to it, it’s just the constraints at this point. I could use the length of the spring to come up with some numbers for a weight puzzle in the future.

I thought these were neat little things to do with some of the constraints Roblox has available. I’ll keep fiddling with this, and maybe provide some updates on what I come up with in the future.

If anyone has any ideas for what to do with this stuff, let me know, I’d appreciate it

6 Likes

Looks good! I would recommend making the cog smoother.

All of the other issues (the scale stuttering) I’m pretty sure is a Roblox issue.

2 Likes

Yeah, I figured I’d have to do some tweaking with the cog, haha

Maybe add a different constraint to it, or lock the player in position.

Other than that, yeah, the scale is just a spring and AlignPosition applied to the X and Z of the platform. I’ve tried increasing the damping, but I think that’s just the Roblox jank

2 Likes

This is fire! I really would like to play a game like that. I ope it will work this smooth in real game. And i like how simple the code looks! I personally like to overcomplicate things.

If it is a puzzle game, I have some ideas in mind:

  • add magnets (maybe with + and -)
  • add bouncy walls, objects.
  • maybe add glue, so objects glue to glued surface on collision
  • add objects that can be separated by collision, like if it collides with something hardly, then it becomes shattered.
2 Likes

These are all really neat ideas, especially the magnets. I’ll definitely have to look into that

1 Like