I’m attempting to emulate a scale tool that applies its transformation gradually. While the transformation is being applied, I want parts around the transforming part to be physically affected, like getting pushed out of the way. So far, I plan to gradually change the transforming part’s size property while adjusting its position with a prismatic constraint.
However, I’ve run into the issue where the prismatic constraint doesn’t take effect while the part’s size is changing. So far, I’ve tried using a tween and the vector3 lerp method, but both had the same effect of nullifying the prismatic constraint. Does anyone have other ideas I can try?
Bit hard to understand but you could try grouping parts with other parts near into one model, that way you can loop through them and do what you need to do.
I have never even tried of making a scaling tool but hear me out right?
What if you make 6 spheres on all sides of the part, then you check if the mouse has clicked on one of the spheres and check if the mouse moves forward or backward. Now you can check if the player up or downscalled the part and you can make that side either bigger or smaller.
So you want to do this in small increments so that if parts get clipped in side of the size change they will get in theory pushed out side and when close to a ledge the unanchored part should fall.
I have no idea how this would turn out, but before you apply the new size, use :GetPartBoundsInBox with the new size to see what parts it’ll collide with. Then you could apply an impulse to those parts away from the newly sized one.
My problem right now isn’t that I can’t get other parts to react to the transforming part. My problem is that I can’t get the transforming part to transform both its position and size at the same time. I’ll deal with the parts reacting to getting pushed aside after I cross this bridge.
When initially building the scale tool, I considered this, but could only find the Resize base part method that would do this. What I didn’t like about it was that it limited me to only 1 stud increments. I suspect this is controlled by the ResizeIncrement property, but since that’s read-only, I don’t know if I can change it. Hence why I’m using the current somewhat convoluted system of adjusting size and position. If you know any other ways to emulate the Resize method, I’d love to see if I can implement it.
I made a scaling system a while ago, here’s a snippit of the scaling code.
local function Size()
local Handles = Instance.new("Handles")
Handles.Style = Enum.HandlesStyle.Resize
Handles.Name = "Size"
Handles.Parent = Player.PlayerGui
table.insert(TableHandles, Handles)
local Direction = Vector3.one
local Original = Vector3.one
local OringalCF = CFrame.new(0, 0, 0)
local MOriginal = Vector3.one
local SDirection = Vector3.one
local Multiplier = 1
Handles.MouseDrag:Connect(function(face, distance)
distance = RoundTo(distance, IncrementalMove)
distance*=Multiplier
CurrentTarget.Size = Original+SDirection.Unit*distance
CurrentTarget.CFrame = CFrame.new(MOriginal)*CFrame.new(((Direction.Unit*Multiplier)*distance)/2)*CurrentTarget.CFrame.Rotation
end)
Handles.MouseButton1Up:Connect(function()
SendUpdate() -- fires a remote to update the objects cframe and size on the server
end)
Handles.MouseButton1Down:Connect(function(face)
face = face.Name
Multiplier = -1
local RDirection = CurrentTarget.CFrame.LookVector
local DSDirection = Vector3.FromNormalId(Enum.NormalId[face])
if face=="Back" then
Multiplier = 1
RDirection = -RDirection
end
if face=="Right" then
Multiplier = 1
RDirection = CurrentTarget.CFrame.RightVector
end
if face=="Left" then
Multiplier = -1
RDirection = -CurrentTarget.CFrame.RightVector
end
if face=="Top" then
Multiplier = 1
RDirection = CurrentTarget.CFrame.UpVector
end
if face=="Bottom" then
Multiplier = -1
RDirection = -CurrentTarget.CFrame.UpVector
end
Original = CurrentTarget.Size
OringalCF = CurrentTarget.CFrame
Direction = RDirection
SDirection = DSDirection
MOriginal = CurrentTarget.Position
print(face)
print(Direction)
end)
end
Size()
Some things aren’t filled in but it should be understandable enough. I used btools code to learn and other code, then realized that it was pretty confusing and was able to come up with my own code.
I found using handles the easiest method as making handles myself would be time consuming.
I think @PreciseGaps has the right idea using the Handles object as that saves you from implementing a lot of your own linear algebra to do 2D calculations to resize based on mouse movement.
Assign the handles object to whatever part you are selecting
Handles has to be in PlayerGui or CoreGui to be usable, and you dont have CoreGui access outside studio so parent it to the player-who-is-resizing’s PlayerGui)
Make sure to set the Adornee property to the part, otherwise the handles wont show up
Once you have the handles visible, you’re going to need to connect some functions to some of the handles events. From my brief reading, it seems like there’s two viable ways to do this:
Option 1:
MouseDragged – Fires when you hold down the right mouse button, and drag the mouse, and ends when you let the mouse button go. This forwards two arguments to the connected function, (more in 3)
Option 2
MouseButton1Down – For when you click down on a handle (should tell the game you are now in ‘dragging mode’ and should connect a function to uses UserInputService to monitor the mouse moving as the player tries to resize +
MouseButton1Up – This is fired when the right mouse button is released, and should disable the function that checks for your mouse movement (which is the same one you connected to in MouseButton1Down) so the game stops checking if the mouse was moved (can cause lag if multiple checks build up)
The connection MouseDragged will pass two arguments to the connected function which are faceId and distance which refers to the side of part (aka ‘face’, see here for more info) and the distance in pixels the mouse moved. With that info you can determine what axis the part should resize on, and how much to resize based on the distance number.
You should probably do some kind of check to see how far the camera is from the part your resizing. If its close to the part, then it shouldn’t resize as much, and if its farther apart, then it should resize more. This will help allow for resizing at scale, like how it works in studio
Once you figure out how much to resize by, youll want to adjust the CFrame using TranslateBy() on the axis that your resizing (i.e. XYZ). The distance you need to move to the part to make it look like its ‘growing’ in one direction is going too be half the total size you resized. So if my part was located at Vector3.new(0,0,0) annd I increased the size on the Y axis from Vector3.new(1,1,1) → Vector3.new(1,2,1) then my parts new position would need to be final_Y_Size - start_Y_Size which in this case is 2 - 1 which equals 1. But I only want half of that, so the total distance i need to move in the Y axis is 0.5 (positive so upwards). You can see this in studio if it doesnt make sense.
Once you know the new Size and Position of the box, you can apply them, and then use WorldRoot:GetPartsInPart() to get a table of all of the parts that would now be inside the newly resized part, and you can move those parts out accordingly (lots of ways to do this)
Again, my problem is what is essentially your step 5. Not figuring out how to scale a part like the scale tool does and not how to get blocks to move out of the way (yet). That is, I have my size and position variables; I just need to apply them gradually and that is where my problem is. I can move my part just fine, but I can’t resize at the same time.
To reiterate, the problem is not getting the goal or making parts react. The problem is, to put it in the outline you’ve laid out, applying both adjustments (ie. position and size) gradually at the same time. I might use the solutions you all have been suggesting if the resizing isn’t pushing parts out of the way, but for now, I want to actually get that resizing to work.
Alternatively if you wanted to do it ‘manully’, then a loop of some kind, not sure if the pricinciple still applies but you typically set CFrame after setting size.
for i = 1, 10, 0.1 do task.wait()
part.Size = Vector3.new(i,i,i)
part.CFrame = part.CFrame
end
Before settling on the prismatic constraint method, I did try using tweens. However, they didn’t seem to apply any physics. Parts wouldn’t get pushed aside while the tween was playing and the part wouldn’t move anything on top. I tried 2 things to simulate physics, which were to set the AssemblyLinearVelocity property of the part and to use ApplyImpulse on all touching parts. Both of them resulted in the parts lagging behind and usually falling off if the transformation was big enough. I didn’t get any suggestions in the thread I posted around 2 weeks ago before deciding to use a prismatic constraint.
As for the Resize method:
With regards to doing it manually, I’m not actually doing any of the position setting through scripts. In fact, a quick test showed that that worked only as well as the tweens did. As mentioned before, I’m using a prismatic constraint to do that position changing, so I don’t actually have a way to guarantee setting the size after position is set.
I did coincidentally try to use RunService.Stepped to set size every frame before physics applied. I think this would set size before the prismatic constraint set position, effectively achieving what you’re suggesting. It didn’t work, though, so I guess physics is a little too unpredictable for that. I’d be open to trying whatever other methods you can think of, though.
While we’re on the topic of things I’ve tried, I also attempted to use the Lerp method in a while loop that went on until the transforming part reached within 0.001 studs of the target position, which also didn’t work.