Custom Movement Weird Behavior

Hello everyone, so I’m currently creating a custom movement which is the same as the game “Bloxorz” it works great until we reach the edge of the baseplate and it shows some weird behavior

as seen on the video the block does this weird behavior when it’s near the edge

here is the relevant code for it. any help would be greatly appreciated

function Movement:_getRotation(Keycode: Enum.KeyCode): CFrame
	-- 
	if Keycode.Name == "A" then
		return CFrame.Angles(0,0, math.rad(ANGLE))
	elseif Keycode.Name == "D" then
		return CFrame.Angles(0,0, math.rad(-ANGLE))
	elseif Keycode.Name == "W" then
		return CFrame.Angles(math.rad(-ANGLE),0, 0)
	elseif Keycode.Name == "S" then
		return CFrame.Angles(math.rad(ANGLE),0, 0)
	end
end


-- Checks if Bloxorz is Lying Down 
function Movement:_isLyingDown(CurrentBloxor: Model): boolean
	-- 
	local Bloxorz = CurrentBloxor
	
	-- 
	local BloxorSize = Bloxorz:GetExtentsSize()
	local BloxorzCFrame = Bloxorz:GetPivot()
	
	-- 
	local UpCast = workspace:Raycast(BloxorzCFrame.Position, BloxorzCFrame.UpVector * (BloxorSize.Y + .1), CastParams)
	local DownCast = workspace:Raycast(BloxorzCFrame.Position, -BloxorzCFrame.UpVector * (BloxorSize.Y + .1), CastParams)
	
	if UpCast or DownCast then
		return false
	end
	
	return true
end

-- This Simulates a Move First If the Bloxor Will Stand After Moving so We Can Offset It Properly
function Movement:_willStandAfterMove(Keycode: Enum.KeyCode, PositionToSet: Vector3): boolean
	-- 
	local GhostBloxorz = self.GhostBloxorz
	
	-- 
	local TempBloxorz = self.BloxorzModel:Clone()
	TempBloxorz:PivotTo(GhostBloxorz:GetPivot())
	
	local TempBloxorzCFrame = TempBloxorz:GetPivot()
	local Rotation = self:_getRotation(Keycode)
	local Position = PositionToSet
	
	-- 
	TempBloxorz:PivotTo(Rotation * (TempBloxorzCFrame - TempBloxorzCFrame.Position) + (TempBloxorzCFrame.Position + Position))
	
	-- 
	local IsLyingDown = self:_isLyingDown(TempBloxorz) 
	TempBloxorz:Destroy()
	return not IsLyingDown
end

-- Gets the Position to Move to
function Movement:_getPositiontoMove(Keycode: Enum.KeyCode)
	--
	local GhostBloxorz: Model = self.GhostBloxorz
	
	-- Get Movement Offset
	local YOffset = GhostBloxorz.PrimaryPart.Size.Y
	local XOffset = GhostBloxorz.PrimaryPart.Size.X
		
	------ LEFT / RIGHT MOVEMENT
	if Keycode.Name == "A" then
		
		if self:_isLyingDown(GhostBloxorz) then
			if self:_willStandAfterMove(Keycode, Vector3.new(-XOffset, 0, 0)) then
				return Vector3.new(-YOffset * MOVE_OFFSET, 0, 0)
			end
			
			return Vector3.new(-XOffset, 0, 0)
		end
		
		return Vector3.new(-YOffset * MOVE_OFFSET, 0, 0)
	elseif Keycode.Name == "D" then
		if self:_isLyingDown(GhostBloxorz) then
			if self:_willStandAfterMove(Keycode, Vector3.new(-XOffset, 0, 0)) then
				return Vector3.new(YOffset * MOVE_OFFSET, 0, 0)
			end
			
			return Vector3.new(XOffset, 0, 0)
		end
		
		return Vector3.new(YOffset * MOVE_OFFSET, 0, 0)
		
		
	------ FRONT / BACK MOVEMENT	
	elseif Keycode.Name == "W" then
		if self:_isLyingDown(GhostBloxorz) then
			if self:_willStandAfterMove(Keycode, Vector3.new(0, 0,XOffset)) then
				return Vector3.new(0, 0,-YOffset * MOVE_OFFSET)
			end
			
			return Vector3.new(0, 0,-XOffset)
		end
		
		return Vector3.new(0, 0,-YOffset * MOVE_OFFSET)
	elseif Keycode.Name == "S" then		
		if self:_isLyingDown(GhostBloxorz) then
			
			if self:_willStandAfterMove(Keycode, Vector3.new(0, 0,XOffset)) then
				return Vector3.new(0, 0,YOffset * MOVE_OFFSET)
			end
			
			return Vector3.new(0, 0,XOffset)
		end
		
		return Vector3.new(0, 0,YOffset * MOVE_OFFSET)
	end
end 

-- Compiles Everything to Move the Bloxorz
function Movement:_process(Keycode: Enum.KeyCode)
	-- 
	if self._inProcess then return end 
	if self.BloxorzModel:GetAttribute("Died") then return end
	
	-- Get Bloxor Model
	local Bloxorz: Model = self.BloxorzModel
	local GhostBloxorz: Model = self.GhostBloxorz
	
	local BloxorSize = GhostBloxorz:GetExtentsSize()
	local GhostBloxorzCFrame = GhostBloxorz:GetPivot()
	
	-- Get Moveset
	local Rotation = self:_getRotation(Keycode)
	local Position = self:_getPositiontoMove(Keycode)
	
	if not Rotation or not Position then return end
	
	-- Position Ghost Bloxor to Initial CFrame 
	self._inProcess = true
	GhostBloxorz.PrimaryPart.Anchored = false
	GhostBloxorz:PivotTo(Rotation * (GhostBloxorzCFrame - GhostBloxorzCFrame.Position) + (GhostBloxorzCFrame.Position + Position - Vector3.new(0, 2, 0)))
		
	-- 
	task.wait()
	GhostBloxorz.PrimaryPart.Anchored = true
	TweenService:Create(Bloxorz.PrimaryPart, MOVE_TWEENINFO, {CFrame = GhostBloxorz:GetPivot()}):Play()
	UpdatePositionBridge:Fire(GhostBloxorz:GetPivot())
	
	task.delay(MOVE_TWEENINFO.Time / 2, function()
		self._inProcess = false
	end)
end

It may an issue with gimbal lock.
Basically if you try to CFrame an item 90 degrees 2 of it’s axes will become aligned and now rotating it on either of those axes will cause issues.

Search up gimbal lock on the forums since they will have better answers than I can give.

The angles work well, it’s just the position that’s broken when it’s near the edge. would that still be caused by the gimbal lock?

To be honest I’m not sure.
The strange thing I noticed is when it flips over the edge it rotates in 2 directions.
Maybe try printing the Position and Orientation each time it flips and see how the numbers change when it flips over the edge to see what’s happening with the math of your CFraming.

fixed it! lol just changed this

GhostBloxorz:PivotTo(Rotation * (GhostBloxorzCFrame - GhostBloxorzCFrame.Position) + (GhostBloxorzCFrame.Position + Position - Vector3.new(0, 2, 0)))

to this

GhostBloxorz:PivotTo(Rotation * (GhostBloxorzCFrame - GhostBloxorzCFrame.Position) + (GhostBloxorzCFrame.Position + Position - Vector3.new(0, 1.9, 0)))

I think the block gets really pushed down the baseplate that it pops it out on the side?

1 Like

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