I’m currently scripting a tweened “tree fall” destruction system, where if characters are knocked into a tree, it’s supposed to fall 90 degrees away from the direction they’re facing.
My current issue is I can’t figure out how to implement the HumanoidRootPart LookVector of the character into my CFrame.Angles rotation.
I’ve tried using CFrame.lookAt() with ToOrientation at the end to no avail, as well as searching through the DevForum.
It’s important to note that I’m utilizing the Pivot Point of the tree trunk in order to ensure that the tree rotates from the bottom of the tree rather than the center.
Yeah that’s the current issue, I’m not sure how to go about implementing that. I can’t directly apply it to the offset as it’s a CFrame and LookVector is a Vector3.
What about trying to set up a CFrame variable, one that starts at the tree’s pivot position, and looks in the direction of the lookVector? Then, pivot the tree (or the cloneObject right now) to cframeVariable * 90 degrees. Or have you already tried that?
You should be able to use local AngleCF = Player.CFrame:ToWorldSpace(CFrame.Angles(0, 0, math.rad(90))) This should return a CFrame object with no transformation (just rotation) in world space which you can then convert to the trees object space using Tree.CFrame:ToObjectSpace(AngleCF).
I’m currently using :PivotTo as a means of rotating the part. I’m assuming the process would be different to convert the AngleCF back to ObjectSpace. I’m not sure how though.
Here is the code where the tree object is being pivoted:
Given the first parameter in your CFrame, I believe this will alter the position of the character which is not what I want. The goal is simply to move rotate the tree based on the direction that the HumanoidRootPart is facing with an offset of 90 degrees, all while maintaining the current position of the Character seeing as I already rotate it for the wall splat mechanic as shown in the reference video.
local pivotPoint = cloneObject:GetPivot()
local angleCF = movingChar.HumanoidRootPart.CFrame:ToWorldSpace(CFrame.Angles(0, 0, math.rad(90)))
cloneObject:PivotTo(pivotPoint:ToObjectSpace(angleCF))
Also for clarification, I am not using a model. I’m only using :PivotTo so as to ensure the tree rotates from the bottom (where the pivot point is set).
Heres my solution.
Id say drop the cframe angles and switch to matrices. This is a presonal opinion of mine but I think it’s more readable and versatile.
I didn’t bother with tweening it cause it would make the code unnececeraly longer and harder to read. Script is only so you can understand how it works and is supposed to be integrated into your system but feel free to copy stuff.
local directionPart: Part = workspace.Direction
local treeModel: Model = workspace.Tree -- I assumed you were using a model but it's pretty easy to switch to a part/mesh that you are using (My bad)
local Angle: NumberValue = script.Angle -- Positive numbers will go higher, Negative numbers will go lower (Default is 0 for the 90 degree turn)
function Fall()
local treeProperties = treeModel:GetPivot()
local lookAt = CFrame.lookAt(directionPart.Position, treeProperties.Position)
-- Since we don't include the "Y" value of our lookVector (In line 14 we replaced it with "Angle" value)
-- We need to fallback the function, Otherwise the tree could get an empty/dysfunctional vector
-- This empty/dysfunctional vector will either: Do something unexpected or remove the model altogether
if lookAt.LookVector.X == 0 and lookAt.LookVector.Z == 0 then
-- TODO: add a fallback function
return
end
local matrix = CFrame.fromMatrix(treeProperties.Position, lookAt.XVector, Vector3.new(lookAt.LookVector.x, Angle.Value, lookAt.LookVector.Z))
treeModel:PivotTo(matrix)
end
-- The following section of this script is for the video demonstration and can be ignored
directionPart:GetPropertyChangedSignal("Position"):Connect(Fall)
Angle:GetPropertyChangedSignal("Value"):Connect(Fall)
Keep in mind that the pivot of this model is set to the bottom
Is there a reason you are unable to use matrices? I would gladly assist!
cframeValue.Value = CFrame.lookAlong(cframeValue.Value.Position, character:GetPivot().LookVector) -- "character" is the variable of the character which contains the HumanoidRootPart that you want to face the tree to its LookVector
I would imagine something like the following would work; in which I’ve included a demo so you can understand how it works better - see the comments for more details.
Example
Note: the Maid library here was just being used to cleanup the parts/connections, remove that if you don’t / haven’t used a Maid library - it’s not necessary for the demo.
--[=[
computeFallTransform
@desc computes the new transform of an object if it were to fall in the
direction of `vec` by the specified `fallAngle` given an upVector
@param transform CFrame - the object's original CFrame/WorldPivot
@param vec Vector3 - the direction of the fall
@param fallAngle number - (optional) defaults to rad(90deg); the max angle - in radians - that we'd like to fall
@param upVector Vector3 - (optional) defaults to Vec3.yAxis; the up vector
@returns CFrame - the new transform; note that we default to the original transform if the given `vec` parameter's
magnitude is approximately 0
]=]
local function computeFallTransform(transform, vec, fallAngle, upVector)
fallAngle = typeof(fallAngle) == 'number' and fallAngle or -math.pi*0.5
upVector = typeof(upVector) == 'Vector3' and upVector or Vector3.yAxis
-- ensure our direction vector is non-zero
local dis = vec.X*vec.X + vec.Y*vec.Y + vec.Z*vec.Z
if math.abs(dis) > 1e-6 then
-- normalize our direction vector
vec = vec * (1/math.sqrt(math.abs(dis)))
-- ensure that we're not facing our upVector, if we are then
-- let's default to the world x axis
if math.abs(vec:Dot(upVector)) >= 9.9e-1 then
vec = Vector3.xAxis
end
-- rotate the transform in our given direction by some given amount
local direction = transform:VectorToObjectSpace(vec)
return transform * CFrame.fromAxisAngle(direction:Cross(upVector), fallAngle)
end
return transform
end
----------------------------------------------
-- --
-- EXAMPLE USAGE --
-- --
----------------------------------------------
--> note just some Maid class to cleanup our connections/parts when we're done;
--> remove this if you don't use one and remove all maid:addTask(...) lines
local Maid = require(path.to.maid.library)
local maid = Maid.new()
--> debug parts for demo
local tree = Instance.new('Model')
tree.Name = 'Tree'
local trunk = Instance.new('Part')
trunk.Name = 'Trunk'
trunk.Position = Vector3.yAxis*(10.5 + 6*0.5)
trunk.PivotOffset = CFrame.identity - Vector3.yAxis*6*0.5
trunk.Size = Vector3.new(2, 6, 2)
trunk.Locked = true
trunk.Anchored = true
trunk.CanQuery = false
trunk.CanTouch = false
trunk.CanCollide = false
trunk.Transparency = 0
trunk.Parent = tree
tree.PrimaryPart = trunk
tree.Parent = workspace
maid:addTask(tree)
local part = Instance.new('Part') -- move & rotate this part around in workspace to see changes
part.Name = 'Point'
part.Position = Vector3.yAxis*11 + Vector3.xAxis*5
part.Size = Vector3.one
part.Locked = false
part.Anchored = true
part.CanQuery = false
part.CanTouch = false
part.CanCollide = false
part.BrickColor = BrickColor.Red()
part.Transparency = 0
part.Parent = workspace
maid:addTask(part)
local handles = Instance.new('Handles')
handles.Style = Enum.HandlesStyle.Movement
handles.Adornee = part
handles.Faces = Faces.new(Enum.NormalId.Front)
handles.Parent = part
--> demo settings
local USE_LOOK_VECTOR = true -- if false: we'll use the direction between the part and the tree instead of the look vector
--> record & cache the original CFrame & PivotOffsets of the tree
local origin = trunk.CFrame
local pivotOffset = trunk.PivotOffset
local transform = origin * pivotOffset
--> now let's update & visualise our results
local connection
connection = RunService.Heartbeat:Connect(function (dt)
local vec
if USE_LOOK_VECTOR then
vec = part.CFrame.LookVector
else
vec = transform.Position - part.Position
-- Note: the following is only used to update our rotation for the demo
part.CFrame = CFrame.lookAlong(part.Position, vec)
end
local targetTransform = computeFallTransform(transform, vec)
tree:PivotTo(targetTransform)
end)
maid:addTask(connection)