Player Weld Restricts Object Orientation

My goal is to appropriately align an object (specifically a scooter union operation) to be perpendicular to the surface upon which it lies at all times, with the player’s character to always be aligned correctly on the scooter. Essentially, the player should simply move and rotate with the object (excluding animations). Rotating the scooter is for some reason adding complications, though.

Whenever the object is on an incline, it seems to vibrate. This is because of a weld that keeps the player’s character attached to the object. The weld seems to try to “fight” against the orientation changes. When my reorientScooter function changes the orientation of the scooter, the weld resets the orientation, causing a back-and-forth since the function is called whenever the scooter’s orientation is not perpendicular to the surface it is on. The resetting that the weld does causes it to not be perpendicular to the surface and so it looks like the object is vibrating, as shown in the following clip:

I tried disabling the weld just before changing the orientation of the object and re-enabling it afterward. Although this resolves the vibration issue, this results in the player’s character not being aligned with the scooter, as shown in the following clip:

In case it helps, here is the code responsible for welding the player to the object:

...
local function pinPlayerToScooter(character: Model, scooter: UnionOperation): RBXScriptConnection
  ...
  local primaryPart: Part = -- player primary part
  local scooterBaseRegion: Part = -- scooter base
  ...
  local weld = Instance.new("WeldConstraint")
  weld.Name = "ScooterPlayerPin"
  weld.Part0 = primaryPart
  weld.Part1 = scooterBaseRegion
  weld.Parent = scooterBaseRegion
  ...
end
...

Here is the code responsible for reorienting the object, given the surface normal of the surface upon which it lies (Note that reorientScooter is the main function here):

...
local scooter: UnionOperation = -- scooter union operation
local scooterPlayerPin: WeldConstraint = -- weld responsible for pinning player to scooter
...
local function calculateReorientationAngle(surfaceNormal: Vector3): number
  return math.acos(scooter.CFrame.UpVector:Dot(surfaceNormal))
end

local function determineReorientationAxis(angle, surfaceNormal: Vector3): Vector3
  local axis: Vector3 = nil

  if angle < 0.00001 or angle > math.pi + 0.00001 then
    axis = Vector3.xAxis
  else
    axis = scooter.CFrame.UpVector:Cross(surfaceNormal)
  end

  return axis
end

local function reorientScooter(surfaceNormal: Vector3): ()
  local angle = calculateReorientationAngle(surfaceNormal)
  local axis = determineReorientationAxis(angle, surfaceNormal)
  local newCFrame = CFrame.fromAxisAngle(axis, angle) * scooter.CFrame.Rotation + scooter.CFrame.Position

  -- Does not change orientation if there is an insignificant difference between the current orientation and the new orientation
  if isInsignificantVector3Difference(radianToDegreeVector3(Vector3.new(newCFrame.Rotation:ToOrientation())), scooter.Orientation) then return end

  scooterPlayerPin.Enabled = false -- disable weld whilst rotating scooter
  scooter.CFrame = newCFrame
  scooterPlayerPin.Enabled = true -- re-enable weld after rotating scooter
end
...

(Bumping thread due to no responses after an hour)

(Second bump since it’s been two hours; I unfortunately still haven’t fixed the issue)

(third bump since it’s been three hours; I tried manually updating the CFrame every frame to match the scooter’s but that will be too tricky for comfort due to animations moving parts around)

Interesting finding: I updated the player’s CFrame to stay in the same relative position to the scooter whilst disabling the scooter player pin and I still got the same jittering effect. Here’s the code:

local function reorientScooter(surfaceNormal: Vector3)
  local angle = calculateReorientationAngle(surfaceNormal)
  local axis = determineReorientationAxis(angle, surfaceNormal)
  local newCFrame = CFrame.fromAxisAngle(axis, angle) * scooter.CFrame.Rotation + scooter.CFrame.Position

  -- Does not change orientation if there is an insignificant difference between the current orientation and the new orientation
  if isInsignificantVector3Difference(radianToDegreeVector3(Vector3.new(newCFrame.Rotation:ToOrientation())), scooter.Orientation) then return end

  scooterPlayerPin.Enabled = false
		
  local playerRelativePosition = scooter.CFrame:PointToObjectSpace(primaryPart.Position)
  scooter.CFrame = newCFrame
  primaryPart.CFrame = CFrame.new(scooter.CFrame:PointToWorldSpace(playerRelativePosition)) * scooter.CFrame.Rotation
		
  scooterPlayerPin.Enabled = true
end

Fixed the issue! Idk why welding the character to the scooter resists CFrame changes, so I just manually change the CFrame to the WorldCFrame of some attachment that represents the ideal coordinate frame of the character. Here’s the code:

...
local function pinPlayerToScooter(character: Model, scooter: UnionOperation)
  ...
  local target: Attachment = Instance.new("Attachment")
  target.Name = "ScooterTarget"
  target.Position = scooter.CFrame:PointToObjectSpace(newPosition)
  target.Parent = scooter

  primaryPart.CFrame = target.WorldCFrame
  primaryPart.Anchored = true
  ...
end
...
local function updatePlayerPosition()
  primaryPart.CFrame = target.WorldCFrame
end
...
RunService.RenderStepped:Connect(updatePlayerPosition)
...

Unfortunately, this results in some lag to the many other computations I am doing, so I will need to do some optimization but that’s another venture. This issue is now closed.

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