DragDetector Constraint function not working

Hi folks,

I have a project in which you’d be able to move parts around using DragDetectors. The area you can build in is limited with visual parts & with a Vector3 clamper.

Chapters:


My issue

The `DragDetector:AddConstraintFunction()` method is quite oddly working to me. I may be doing wrong things (and that is probably what is happening), but the constraint I am looking for is **NOT** working.

The idea

The constraint is made so that, if you go out of bounds, the part cannot go past it: 1. Minimum coordinates: `x = -2048, y = 0, z = -2048` 2. Maximum coordinates: `x = 2048, y = 2048, z = 2048`

There is also a more physical approach. When your part collides with the border (materialized by the red grid ou can see here:)


If the part touches the border, it stops. This is collision build and this feature is also part of Studio.


Position clamping

I solve the position clamping with a function called
ReplicatedFunctions:ClampVector3(V: Vector3, Min: Vector3, Max: Vector3): Vector3

This function allows me to clamp the Position Vector3 accordingly.

Collision building

I simply put the part in where it *should* be, I then run a function called
ReplicatedFunctions:ReturnBoundingParts(List: {Instance}, Strict: boolean?): {BasePart}

where List is the list of parts to analyze (aka check if foreign parts are touching it), Strict tells the script if only red borders should be analyzed (Strict = false which is the default), or if it should make a pure collision building as in Studio (check every foreign parts from the selection, Strict = true)

This function returns a list of colliding parts, which can describe if one or more foreign parts are touching the selection. (#ReplicatedFunctions:ReturnBoundingParts(List, Strict) > 0)


The issue

Expected behavior

As its arrow handle brother (shown in the video below), when the part **touches** the red border, it does NOT go any further.

Current behavior

The constraint isn't working properly. Here is the script with functions I detailed earlier.

:warning: All the selection is in a model called SelectionModel. The DragDetector is parented to this model. The HandleSelectionPart is a part that is the adornee of some Handles to show axes. This part is moved first, then the whole SelectionModel is moved using

ReplicatedFunctions:ApplyPosition(Model: Model, Position: Vector3): ()
--PVInstanceObject is a table with a key "Instance" pointing to the Instance it is associated with. OOP scripting.

local startCFame: CFrame --CFrame initialized with DragStart

function DragConstraint(Inst: TypesModule.PVInstanceObject, ProposedMotion: CFrame): CFrame
	if isMoving then
		if Inst.Instance:IsA("Model") then
			SelectionModel.PrimaryPart = Inst.Instance.PrimaryPart
		else
			SelectionModel.PrimaryPart = Inst.Instance
		end

		--Cache the current (aka "old") CFrame
		local cachedCFrame = Inst.Instance:GetPivot()
		
		--Moves the handle at the desired position
		HandleSelectionPart.Position = startCFrame.Position + ProposedMotion.Position

		--Clamps the position
		HandleSelectionPart.Position = ReplicatedFunctions:ClampVector3(HandleSelectionPart.Position, Vector3.new(-2048, 0, -2048), Vector3.new(2048, 2048, 2048) )
		
		--Moves the SelectionModel to where the handle is
		ReplicatedFunctions:ApplyPosition(SelectionModel, HandleSelectionPart.Position)

		--Check if the instance is not interfering with borders, ...: if it does, use cachedCFrame
		if #ReplicatedFunctions:ReturnBoundingParts(SelectionModel:GetChildren(), false) > 0 then
			print("Part touching border. Reverting to previous position.")

			--Places the Handle & the model back to the previous position
			HandleSelectionPart.Position = cachedCFrame.Position
			ReplicatedFunctions:ApplyPosition(SelectionModel, cachedCFrame.Position)
			
			--Transmits the previous position to the DragDetector
			return ProposedMotion.Rotation + (cachedCFrame.Position - startCFrame.Position)
		else
			--Gives the ProposedMotion as it is valid
			return ProposedMotion
		end
	else
		--In case the system is unset, returns 0
		return CFrame.new(0, 0, 0) * CFrame.Angles(0, 0, 0)
	end
end

This looks right to me (although I struggled to understand how it works), but here’s the result:


Conclusion

I may have not understood how DragDetectors were made. Due to my French nationality, it is sometimes hard for me to understand documentation.
If you think my problem is untreatable via AddConstraintFunction, I believe it is as I have seriously checked different topics about that, and posts that @PrinceTybalt made in the two following posts:

I even tested the testplace, but I could not find my use case. Although I found applications where restrictions were applied to dragging.

Thanks for having read the post, and having helped me,
Varonex_0

1 Like

Could any of these be the issue? (extremely quick look at your issue)

Setting the Position: This might cause issues if the part is anchored or if there are other constraints affecting it. Instead of setting the position directly, you could use the CFrame property to move the part. For example, you could use HandleSelectionPart.CFrame = HandleSelectionPart.CFrame + ProposedMotion.

Collisions:

Returning the ProposedMotion: At the end of the function, you’re returning the ProposedMotion. However, if the part is colliding with something, you might want to return a different CFrame that moves the part away from the collision.

The first point would be equivalent to what I did. I am working exclusively with anchored parts! The HandleSelectionPart can be set through CFrame or Position, that would not change anything. I also need to use the startCFrame, and not its position (although technically, your solution is also correct because I set/reset everything upon DragStart & DragEnd).
I am using the Position to avoid collisions with Local & World space (which should not occur either way, that is just a sort of safety measure!)

When the part is colliding with something, I am returning:

return ProposedMotion.Rotation + (cachedCFrame.Position - startCFrame.Position)

If you watch the youtube clip, you can notice that it prints out “Part touching border. Reverting to previous position.”.

cachedCFrame refers to the CFrame of the previous drag (or, to be more correct, the CFrame before the next Drag occurs). So by doing this, I return the DragFrame at the previous drag. I also tried to return MoveDrag.DragFrame, but the problem is the same.

Problem solved, stupid problem:

See how the function header is different than what you’re supposed to have?:

function DragConstraint(Inst: TypesModule.PVInstanceObject, ProposedMotion: CFrame): CFrame
...
end

That’s because I’m doing:

function DragConstraint(Inst: TypesModule.PVInstanceObject, ProposedMotion: CFrame): CFrame
...
end

...
MoveDrag:AddConstraintFunction(1000, function(ProposedMotion: CFrame): CFrame
	DragConstraint(Obj, ProposedMotion)
end)

See the error?

The function DragConstraint() returns a CFrame, whereas here:

MoveDrag:AddConstraintFunction(1000, function(ProposedMotion: CFrame): CFrame
	DragConstraint(Obj, ProposedMotion)
end)

It does NOT.

Hours spent for a stupid thing I forgot… Nevermind, joys of programming!

Solution:

MoveDrag:AddConstraintFunction(1000, function(ProposedMotion: CFrame): CFrame
	return DragConstraint(Obj, ProposedMotion)
end)

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