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.
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.
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?
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.
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.
I use SetPrimaryPartCFrame() to do this, I find it simplier.
This is wrong. The metamethods are ran when the key indexed does not already exist.
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
One of the best tutorials I’ve ever seen. Good job!
Wow really good! I wish there had been something this good when I was attempting this for the first time years ago…
Thanks!
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.
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. Ended up working out how to verify collisions on the server, so those pesky exploiters don’t ruin my game so easily lol
Thank you. This was a very good tutorial on placement system.
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?
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
Hope that helps!
Definitely keeping a note on this for future use.
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.
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!
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.
If I understood the script right then I think that’s what you are looking for.
Thank you so much for this! Definitely bookmarking this for future use.