Creating A Furniture Placement System

Very detailed explanation, thank you for this! Will be using this in my project.

Always grateful to be apart of this community to allow myself to extend my experience in programming and to understand different components with examples from others.

74 Likes

There are an overwhelming number of threads asking for guidance on placement systems or assistance in fixing their code. Not only does this tutorial adequately and smoothly cover how to make one, but it’s got the fancy OOP too. Well made.

There’s one thing I noticed though. I didn’t take a critical look at this article since I have no use for placement systems yet, but your data saving code caught my eye. I wanted to ask - is there a reason that you save blank tables to clear data over using GlobalDataStore::RemoveAsync?

39 Likes

Placement systems are something that so many people want to know how to make but they actually quite easy once you know how to actually make them. This tutorial will definitely be a great start for those that are trying to learn how to make such a system.

21 Likes

To be honest no. I guess that was an oversight. It could/should be set to nil and no errors would be caused.

Thanks for pointing that out!

Edit: So you can’t use :SetAsync() with a nil value. I also tried using :RemoveAsync() but keep getting warnings. So an empty table it shall stay for the time being.

24 Likes

I use SetPrimaryPartCFrame() to do this, I find it simplier.

11 Likes

This is wrong. The metamethods are ran when the key indexed does not already exist.

15 Likes

Yes I had a few ppl alert me to this (got things jumbled in my memory). Its fixed on SH, but im on mobile atm. Ill update the post when i next can.

Edit: Should be fixed now

13 Likes

One of the best tutorials I’ve ever seen. Good job!

13 Likes

Wow really good! I wish there had been something this good when I was attempting this for the first time years ago… :stuck_out_tongue:
Thanks!

14 Likes

Thank you for this! I think this is the perfect amount of work shown without giving away too much code including tweening the movement of parts as you move your mouse, rotation tweens, etc. You showed the basics and that leaves the rest of us to challenge ourselves to include more features.

One of the few tutorials I will recommend to people frequently as too many people ask for this. :stuck_out_tongue:

7 Likes

Love the tutorial, but IsColliding always returns false.

Edit: Nevermind, fixed it, I was being stupid and trying to get the server to check for collisions on a part created by the client. :roll_eyes: Ended up working out how to verify collisions on the server, so those pesky exploiters don’t ruin my game so easily lol

https://gyazo.com/8d233faf1787f49131cdf8d25315b23c

14 Likes

Thank you. This was a very good tutorial on placement system.

10 Likes

https://gyazo.com/a710dbb47684b9c3b43ff7ab47092d5c

As I am using this I noticed that when you rotate the model it’s not centered, how can I change it?

17 Likes

Good question! The reason it’s not centered is because it’s locking to a grid. If you want the item to line up directly to the mouse then set the GridUnit equal to 0.

Another behavior you might notice is that anything that isn’t a 90 degree increment may not be properly bound to the surface. This is because the code assumes axis aligned rotation and does some simpler math because of it. To fix this you must adjust how the model size is calculated (as a world space bounding box).

local function worldBoundingBox(cf, size)
	local size2 = size/2;
	
	local c1 = cf:VectorToWorldSpace(Vector3.new(size2.x, size2.y, size2.z))
	local c2 = cf:VectorToWorldSpace(Vector3.new(-size2.x, size2.y, size2.z))
	local c3 = cf:VectorToWorldSpace(Vector3.new(-size2.x, -size2.y, size2.z))
	local c4 = cf:VectorToWorldSpace(Vector3.new(-size2.x, -size2.y, -size2.z))
	local c5 = cf:VectorToWorldSpace(Vector3.new(size2.x, -size2.y, -size2.z))
	local c6 = cf:VectorToWorldSpace(Vector3.new(size2.x, size2.y, -size2.z))
	local c7 = cf:VectorToWorldSpace(Vector3.new(size2.x, -size2.y, size2.z))
	local c8 = cf:VectorToWorldSpace(Vector3.new(-size2.x, size2.y, -size2.z))
	
	local max = Vector3.new(
		math.max(c1.x, c2.x, c3.x, c4.x, c5.x, c6.x, c7.x, c8.x),
		math.max(c1.y, c2.y, c3.y, c4.y, c5.y, c6.y, c7.y, c8.y),
		math.max(c1.z, c2.z, c3.z, c4.z, c5.z, c6.z, c7.z, c8.z)
	)
	
	local min = Vector3.new(
		math.min(c1.x, c2.x, c3.x, c4.x, c5.x, c6.x, c7.x, c8.x),
		math.min(c1.y, c2.y, c3.y, c4.y, c5.y, c6.y, c7.y, c8.y),
		math.min(c1.z, c2.z, c3.z, c4.z, c5.z, c6.z, c7.z, c8.z)
	)
	
	return max - min
end

function Placement:CalcPlacementCFrame(model, position, rotation)
	local cf, size = self:CalcCanvas()
	local modelSize = worldBoundingBox(CFrame.Angles(0, rotation, 0), model.PrimaryPart.Size)

	-- same stuff from before
end

2019-02-27_19-41-23

Hope that helps!

53 Likes

Definitely keeping a note on this for future use.

14 Likes

Awesome work! I see that the code only supports one specific part called “ExampleCanvas”, how would I be able to make the code support multiple parts? In case I want to have each player have their own canvas which they can place their furniture on.

3 Likes

It’s entirely possible to do and quite easily extended onto the system provided. That being said, it’s something I leave for readers to figure out. Good luck! :grin:

14 Likes

What part of the scripts would I need to edit to allow players to place items on different height surfaces? Currently can’t have placement on say a two storey building, etc. or different heights/levels of floors.

7 Likes

If I understood the script right then I think that’s what you are looking for.

3 Likes

Thank you so much for this! Definitely bookmarking this for future use. :smiley:

3 Likes