The green part needs to be flat on the slope at all times. But it also needs to face towards the red part which can be at any height above or below the green part.
The green part is raycasted onto the slope, so you can use Raycast.Position and Raycast.Normal.
It’s called projection. Let’s remove the local height value of the red brick by doing:
local position = red.Position
local delta = position - Raycast.Position
position -= delta * Raycast.Normal:Dot(delta.Unit)
green.CFrame = CFrame.new(Raycast.Position, position)
The “red brick” in this video is the Player’s Camera CFrame.
It doesn’t look like it’s always facing the camera, but it is staying level with the normal now.
local position = Raycast.Position
local upVector = Raycast.Normal
local lookVector = workspace.CurrentCamera.CFrame.lookVector
local rightVector = lookVector:Cross(upVector)
lookVector = upVector:Cross(rightVector)
green.CFrame = CFrame.fromMatrix(position, rightVector, upVector, -lookVector)
Do you know how I can prevent the position from going “behind” the camera? It seems to happen whenever the angle of the camera and the slope is <90 degrees, such as looking straight down and uphill while on a slope.
I feel like this would only cause more wierd behavior, but you could try add
local camCFrame = workspace.CurrentCamera.CFrame
local lookVector
if camCFrame.UpVector.Y < 0 then
lookVector = camCFrame.UpVector
else
lookVector = camCFrame.lookVector
end
I’ve also noticed that standing parallel to the slope it doesn’t quite line up the way I’d expect it to like it does while facing up or down the slope. Not related to my clamping in the code below, already checked that.
local Placement = Deployable.Placement
local Bounds = Placement.PrimaryPart
---
local CameraCFrame = self.CurrentCamera.CFrame
local X,Y,Z = CameraCFrame:ToOrientation()
X = math.clamp(X-math.rad(20), math.rad(-85), math.rad(-40))
CameraCFrame = CFrame.new(CameraCFrame.Position) * CFrame.fromOrientation(X, Y, 0)
local RayOrigin = CameraCFrame.Position
local RayLookVector = CameraCFrame.LookVector
---
local RayDirection = RayLookVector*10
local Raycast = workspace:Raycast(RayOrigin, RayDirection, RayParams)
local Position = (Raycast and Raycast.Position) or (RayOrigin + RayDirection)
local Normal = (Raycast and Raycast.Normal) or Vector3.yAxis
---
local RightVector = RayLookVector:Cross(Normal)
local LookVector = Normal:Cross(RightVector)
local Pivot = CFrame.fromMatrix(Position, RightVector, Normal, -LookVector)
local Extents = Placement:GetExtentsSize()
Bounds.PivotOffset = CFrame.new(0,-Extents.Y/2,Extents.Z/2)
Placement:PivotTo(Pivot)