Limit CFrame to certain radius?

Lets say I have a part that is being constantly lerped to the player character like this:

https://i.gyazo.com/b217b48ab7c404f14c1ac9a08b31f108.mp4

How do I make it so that the part can’t get any further than a certain distance from the character? For example, when it gets near the red line it is forcefully CFramed so that it does not cross the line?

image

4 Likes

Here’s a simple example of how to do this. If the distance (i.e. radius) is greater than a given maximum, it will lock to that maximum distance:

  1. Check the distance after your original movement (a simple lerp in this example).
  2. Check the distance between the character and the part.
  3. If the distance is greater than MAX_DISTANCE, then continue to 4. Else, skip to 5.
  4. Adjust the position to be at the MAX_DISTANCE position by lerping the character position toward the goal position, using the ratio of max distance to current distance of your following part.
  5. Update the CFrame of the part.
local part = workspace.Part
local character = player.Character.PrimaryPart

local MAX_DISTANCE = 10

local position = part.Position

function Update()

	-- Current position of the character (or whatever your part is following):
	local newPos = character.Position

	-- The original movement (however you're calculating it):
	position = position:Lerp(newPos, 0.2)

	-- Check distance between the character's position and the calculated next movement:
	local distance = (position - newPos).Magnitude
	if (distance > MAX_DISTANCE) then
		-- Adjust the calculated movement to fit within MAX_DISTANCE:
		position = newPos:lerp(position, MAX_DISTANCE / distance)
	end

	-- Update CFrame:
	part.CFrame = CFrame.new(position)

end

-- Call Update every frame (or whatever your logic is)
Update()
5 Likes

Fairly easy to do, just do this

local dir = (partpos-charpos)
partcf = (partcf-partpos)+charpos+dir.Unit*math.min(dir.Magnitude,MAX_DIST)

Same idea if you wanna keep that specific radius away from them

local dir = (partpos-charpos)
partcf = (partcf-partpos)+charpos+dir.Unit*RADIUS

And to have it not go too close to the player

local dir = (partpos-charpos)
partcf = (partcf-partpos)+charpos+dir.Unit*math.max(dir.Magnitude,MIN_DIST)

Basically just offsetting from player in the same direction but the offset length is clamped under MAX_DIST, a set distance, or over MIN_DIST.
This shouldnt really be inefficient but it is simpler and more accurate compared to the above. It also keeps the parts original orientation.

For the lerping part you can just constantly lerp to that coordinate instead of setting it immediately. You can also add a condition in case the positions are the same (the resulting vector has a length of 0) so that the Unit vector doesnt freak out.

If you want it however to constantly lerp to the characters position for some reason you can change the lerp value to be max(rate,mult*dist/MAX_DIST)

9 Likes

@Crazyman32 @Wunder_Wulfe thanks guys, both of your solutions work.

I also wanted to ask how would I go about doing the same thing, but only in one direction? For example, when the player is moving forward the part trails behind them nicely, but when they start moving backwards I want the part to still constantly be behind the player.

https://i.gyazo.com/b590b652ef4a72f03941913dbd6a0c64.mp4

For that you can just keep lerping it to be at (partcf-partpos)+rootpos-rootlookvector*radius

It works, but not exactly how I’d like it. You see, I want it to still be able to touch the character, but if I put it close enough and move back, it still goes slightly in front of my character.

https://i.gyazo.com/7b8c54691c1a1a781546661f042928de.mp4

Your first example would be exactly what I want if it worked in only one direction.

it does but you are lerping too slowly

To put it behind the player, the general update algorithim could be:

  1. Calculate the distance between part/torso and clamp it
  2. Get the relative cframe (behind the torso)
  3. Lerp that cframe to the torso’s

Step 2/3 might look like this:

local partCF = part.CFrame
local rootCF = root.CFrame
local goalCF = CFrame.new(rootCF.p - (rootCF.LookVector * clampedDist)) * (partCF - partCF.p)
local newCF = partCF:lerp(newCF, 0.2)

it might actually look better if you factor distance from it into the rate or speed it up because otherwise it would look like it is constrainted and will have an abrupt change

2 posts were merged out for bumping