Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Part shaking when I move my mouse (for placement system)?

I am trying to create a smooth placement system (like theme park tycoon 2) that glides smoothly to the mouse position. I am using the Lerp() function and it's working except for the fact that it is shaking (or appears to be). I think this has to do with the code updating too fast so when I move my mouse it is trying to move to multiple positions resulting in a shaking effect. I have tried adding waits in places to lower the update time but nothing helps. The script is located in StarterGui later replicated to PlayerGui. It is also a LocalScript. This is a test world and script so nothing else is in the place (other than the baseplate). Here is my code:

-- Creates the part and sets properties
local part = Instance.new("Part")

part.Anchored = true
part.CanCollide = false
part.Parent = game.Workspace

-- Mouse and player
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

-- Position variables that are set below
local PosX, PosY, PosZ

-- Don't worry about this function
local function Snap()
	PosX, PosY, PosZ =  math.floor(mouse.Hit.X / 2 + 0.5) * 2, 0.5, math.floor(mouse.Hit.Z / 2 + 0.5) * 2 -- Math
	
	return PosX, PosY, PosZ
end

-- Here is where the lerping starts
local function Lerp()
	mouse.TargetFilter = part -- Ignores the part
	
	Snap()
	
	-- Lerping
	if mouse.Target and mouse.Target.Name == "Baseplate" then
		for i = 0, 1, 0.001 do
			-- This lerps the part to the mouse position
			local mousePos = part.CFrame:Lerp(CFrame.new(PosX, PosY, PosZ), i)
			
			wait(0) -- simple wait
			
			part.CFrame = mousePos -- Sets the CFrame
		end
	end
end

mouse.Move:Connect(Lerp) -- Event

Thanks for any help in advance!

2 comments

0

The Move event is being fired each time the mouse moves, resulting in tons of lerps. A debounce may be what you're looking for.

0

Thanks I will try that!

1 answer

✓ Accepted answer

#Explanation

  1. To make this work properly, you have to disentangle the lerping and the mouse position book-keeping. The code below does just that: The Mouse.Move event only tracks the mouse position, while the RenderStepped event interpolates the final position, and it will move at constant speed (set in variable of same name).
  2. In order to also snap to grid, you need to keep track of the realPosition in continuous space. Without tracking `realPosition, the position will never change if movement is not fast enough because the part would never make the jump between two grid cells in a single render step.
  3. Feel free to play with the speed configuration.

#Caveats

  1. If you want build placement to work like in Minecraft or Fortnite, you definitely don't want the lerp part. In that case, you can simply set speed = math.huge and it just works. In that case you also do not need to bookkeep the realPosition anymore, which would make this script more compatible with other scripts.
  2. I'm sure you are aware: For this to work in multiplayer, you still need to split this script into client and server side.

Other than that, this should work just fine :)

#How to move Models?

There are two ways to move models:

  1. The first way requires the model's PrimaryPart to be set (which is often not set simply because for most models it actually does not make any sense). If you have the PrimaryPart, you can use SetPrimaryPartCFrame, like so: model.SetPrimaryPartCFrame(CFrame.new(newPos)). In case of a model, you would also have to change part.Position to model.PrimaryPart.Position.
  2. The lesser known TranslateBy function does not require a PrimaryPart. However it needs relative movement, not an absolute position. Also without a PrimaryPart, you need a different way of determining what the model's Position is (which, for some reason, after 12 years of Roblox, is still not trivial to figure out without PrimaryPart) and would require quite a few more changes to the code.

#Code

-- configuration
local speed = 10 -- the speed at which the part should move


-- services
local RunService = game:GetService("RunService")

-- Mouse and player
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

-- Creates the part and sets properties
local part = Instance.new("Part")
part.Anchored = true
part.CanCollide = false
part.Parent = game.Workspace

-- for snapping (moving in discrete space) to work, you will have to keep track of the real position
local realPosition = part.Position

-- Don't worry about this function
local function Snap(pos)
    return Vector3.new(math.floor(pos.X / 2 + 0.5) * 2, 0.5, math.floor(pos.Z / 2 + 0.5) * 2) -- Math
end

-- Here is where the lerping starts
local mousePos

local function OnMouseMove()
    mouse.TargetFilter = part -- Ignores the part

    -- Lerping
    if mouse.Target and mouse.Target.Name == "Baseplate" then
        -- we want to move the part
        mousePos = mouse.Hit.p
	else
		-- we do not want to move the part
		mousePos = nil
    end
end

mouse.Move:Connect(OnMouseMove) -- Mouse bookkeeping event

 
local function OnRenderStep(dt)
	if mousePos then
		local oldPos = realPosition  -- part.Position
		local delta = mousePos - oldPos -- Vector representing movement from oldPos to mousePos
		local distance = delta.Magnitude
		local maxDistance = dt * speed
		
		--print(distance, maxDistance)
		
		local newPos
		if distance > maxDistance then
			-- move at speed toward position
			newPos = oldPos + maxDistance / distance * delta
		else
			-- we arrived at mousePos
			newPos = mousePos
		end
		
		-- track real position (in continuous space)
		realPosition = newPos
		
		-- snap position to grid (you can remove this line, if you want to move continuously)
	    newPos = Snap(newPos)
		
		part.CFrame = CFrame.new(newPos)
	end
end
RunService.RenderStepped:connect(OnRenderStep)

4 comments

0

Thanks! I am aware that this will not work on a server game (unless it is a 1 of 1 game)

1

Would there be a way to use this using a model?

0

Also it sometimes go off the grid but for the most part it works!

0

I updated my answer to explain how to make this work with models

This discussion is preserved as it was. New answers, comments, and votes are closed.