Having multiple bases for placement

Currently my placement system relies on a single part (the black part, named ‘Base’) which basically goes from edge to edge of the house, howeverm if the house has areas that jut out (pictured below) then the object can be positioned thru the walls and then into the ‘void’

Theorising here, but could it work if just set the ‘base’ as the mouse.Target?? like

if mouse.Target.Name == 'Base' then 
    Base == mouse.Target 
end

And then I have half a dozen parts be the base??

Nevermind, that wouldn’t work, as if two bases are connected to each other then the part would jump from one base to the other.

Could there be a way instead to just prevent the model from ever entering the wall?

local LowerX, UpperX, LowerZ, UpperZ = CheckBase(PlayersPlot.Base)
	
local Item = cateogry:FindFirstChild(item)
if not Item then return end
	
local ItemClone = Item:Clone()
if not ItemClone then return end
	
ItemClone.Parent = PlayersPlot.Camera
	
mouse.TargetFilter = ItemClone
	
RenderStepped = RunService.RenderStepped:Connect(function()
	RenderPosition(PlayersPlot, mouse.Hit.p, ItemClone, LowerX, UpperX, LowerZ, UpperZ)
end)

CheckBase function

return function(base)
	local LowerBoundX = base.Position.X - (base.Size.X / 2)
	local UpperBoundX = base.Position.X + (base.Size.X / 2)
	
	local LowerBoundZ = base.Position.Z - (base.Size.Z / 2)
	local UpperBoundZ = base.Position.Z + (base.Size.Z / 2)
	
	return LowerBoundX, UpperBoundX, LowerBoundZ, UpperBoundZ
end

RenderPosition

return function(playersPlot, mouseP, object, lowerX, upperX, lowerZ, upperZ)
	local MouseClampedP = ClampMouse(mouseP, lowerX, upperX, lowerZ, upperZ)

	local Size = object.PrimaryPart.Size
	if not Size then return end
	
	object:SetPrimaryPartCFrame(CFrame.new(Round(MouseClampedP - Vector3.new(Size.X / 2, 0, Size.Z / 2), 1, playersPlot.Base.Position.Y + (Size.Y / 2))))		
end

I tried to just post the necessary scripts, as there a lot to this.

3 Likes

Answered another question with similar issue a few minutes ago. You could try casting a ray from the character to see if anything besides the base is in its way.

if not workspace:FindPartOnRay(Ray.new(Character.Head.Position,Mouse.Hit.Position-Character.Head.Position), Base) then

Another thing to note is that you could replace the “Base” with whatever else you want to be able to place items on, leaving more room for versatility.

Made the object jump around and not follow the mouse 100% truly. What you see in the gif is not lag, the model just jumps
com-video-to-gif
And it could still go into the wall a little bit

2 Likes

Made a stupid mistake

local ignl = {Character,Base}
local ray = Ray.new(Character.Head.Position,Mouse.Hit.Position-Character.Head.Position)
if not workspace:FindPartOnRayWithIgnoreList(ray,ignl) then

You should also set the model’s transparency to 1 if the mouse isn’t pointing at the base.

1 Like

Still is a little glitchy looking, plus it goes into the top wall
com-video-to-gif%20(1)

Add the furniture’s model into the ignl table, that should fix the stuttering.

For the thing being stuck in the wall, you have to add a small vector to the 2nd argument of Ray.new so that it detects what it touches.

Ok stuttering now gone, still enters the walls tho
com-video-to-gif%20(2)

The walls are inside a folder along with other parts of the house (doors etc) would adding that folder to the ignore list fix this? Or changing the folder to a model

local p0,p1 = Character.Head.Position, Mouse.Hit.Position
local dir = p1-p0
dir = dir+dir.Unit
local ray = Ray.new(p0,dir)

So would I have to remove the old ray?

local ray = Ray.new(player.Character.Head.Position,mouse.Hit.Position-player.Character.Head.Position)

This what I got

RenderStepped = RunService.RenderStepped:Connect(function()
		local ignl = {player.Character,PlayersPlot.Base, ItemClone}
		local p0,p1 = player.Character.Head.Position, mouse.Hit.Position
		local dir = p1-p0
		dir = dir+dir.Unit
		local ray = Ray.new(p0,dir)
		if not workspace:FindPartOnRayWithIgnoreList(ray,ignl) then
			RenderPosition(PlayersPlot, mouse.Hit.p, ItemClone, LowerX, UpperX, LowerZ, UpperZ)
		end
	end)

Which the above doesnt work at all

Maybe you can use Model:GetExtentsSize along with a new part at the center of the model (so that you can consistently center the new position on the model), and use a Region3 to detect when any parts are inside that model. If any parts (other than the model and base) are detected, you can either simply prevent the table from being moved there or mark the position as invalid, like making all of the parts in the model red and translucent.
Maybe something like this:

local function CheckSpace(model)

    local modelSize = model:GetExtentsSize()

    local unitRay = mouse.UnitRay
    local ray = Ray.new(mouse.UnitRay.Origin, mouse.UnitRay.Direction * 100)
    local rayIgnoreList = {
        --character,
        --base,
        --model
    }
    local p = workspace:FindPartOnRayWithIgnoreList(ray,rayIgnoreList)
    if not p then 
        local region = Region3.new(
            -modelSize * Vector3.new(0.5,0,0.5) + mouse.Hit.Position, 
            modelSize * Vector3.new(0.5,1,0.5) + mouse.Hit.Position
        )
        local regIgnoreList = {
            model,
            --base
        }
        local parts = workspace:FindPartsInRegion3WithIgnoreList(region,regIgnoreList,1)
        if #parts == 0 --[[ or AnotherValidation(parts[1]) ]] then
            -- on success,
            return true
        else 
            -- on Region3 failure
            return false
        end
    else
        -- on Ray failure
        return false
    end
end

There is a part inside the model, which is like a hitbox


Which encases the whole model and is what I use to get the models size basically, then with placement, I divide the models size/2 which would give the centre. However, to model still gets placed outside the wall

Code
RenderPosition

return function(playersPlot, mouseP, object, lowerX, upperX, lowerZ, upperZ)
	local MouseClampedP = ClampMouse(mouseP, lowerX, upperX, lowerZ, upperZ)

	local Size = object.PrimaryPart.Size
	if not Size then return end
	
	object:SetPrimaryPartCFrame(CFrame.new(Round(MouseClampedP - Vector3.new(Size.X / 2, 0, Size.Z / 2), 1, playersPlot.Base.Position.Y + (Size.Y / 2))))		
end

MouseClamp

return function(mouseP, lowerX, upperX, lowerZ, upperZ)
	return Vector3.new(math.clamp(mouseP.X, lowerX, upperX), mouseP.Y, math.clamp(mouseP.Z, lowerZ, upperZ))
end

Round

function roundNumber(number, to)
	to = to or 1
	
	return math.floor(number/to + 0.5) * to
end

return function(vector, unit, yValue)
	return Vector3.new(roundNumber(vector.X, unit), yValue, roundNumber(vector.Z, unit))
end

This is basically all it uses for positioning. I feel like this line

object:SetPrimaryPartCFrame(CFrame.new(Round(MouseClampedP - Vector3.new(Size.X / 2, 0, Size.Z / 2), 1, playersPlot.Base.Position.Y + (Size.Y / 2))))	

Is what’s screwing with it

A solution I thought of most likely slower then doing some ray casting magic is get touching parts on parts of the table and find if it is touching the wall or another idea is to ray cast from one side of the table to the other side and see if it gets stopped by a wall.

I feel like that wouldn’t really work too well.

Have you tried visualizing the rays to see were the rays are hitting? This may help with some debugging.

Try this:

local lasthit = nil
RenderStepped = RunService.RenderStepped:Connect(function()
  local ignl = {player.Character,PlayersPlot.Base, ItemClone}
  local p0,p1 = player.Character.Head.Position, mouse.Hit.Position
  local dir = p1-p0
  dir = dir+dir.Unit*0.2
  local ray = Ray.new(p0,dir)
  local HitPart = workspace:FindPartOnRayWithIgnoreList(ray,ignl)
  if not HitPart then
    RenderPosition(PlayersPlot, mouse.Hit.p, ItemClone, LowerX, UpperX, LowerZ, UpperZ)
  elseif HitPart~=lasthit then
    lasthit = HitPart; print(HitPart.Name)
  end
end)

And tell what’s being printed (if anything).

Please bind it to render stepped not connected it’s much smoother if you use a bind to render step.

Not really, it just makes it easier to synchronize with other renderstep binds.

Yes, and that is my point we don’t know if he has other stuff running on render step already it’d be a good thing if it was binded regardless as you wont need to go back later and wonder why this looks so strange from the others.
Truely it’s just nit picking.

Teleport

Floor01

Wall13

Wall04

Wall13

Floor01

Wall11

Floor01

Wall11

Wall09

Floor01 is the floor, it never prints Base (which is the part inside of all of the floors. And the model never showed up