I made a system that sets plants according to a certain position and gives those plants the orientation of whatever they’re on.
The problem here is that the orientation is behaving kind of weird.
See, normally plants should be set like seen on the image below.
However, sometimes they get weird cframes:
I have no idea of what is happening and I’d appreciate some help, heres the code:
local params = RaycastParams.new()
params.CollisionGroup = “Atmosphere”
params.FilterType = Enum.RaycastFilterType.Include
local function fill(WEDGE, normal)
if normal == Enum.NormalId.Right then
workspace.Terrain:FillWedge(WEDGE.CFrame - WEDGE.CFrame.RightVector * 1.9, WEDGE.Size + Vector3.new(2,3,3), WEDGE.Material)
WEDGE:SetAttribute("Tangible", true)
if workspace.CelestialBodies:FindFirstChild("Sphere" .. 1).PlantLifePossible.Value == true then
for count = 1,2 do
local plant = game.ReplicatedStorage:FindFirstChild("Planet" .. 1).Plants:GetChildren()[WEDGE:GetAttribute("PlantNumber")]:Clone()
if plant then
local lookv = WEDGE.CFrame.RightVector
local vector1 = Vector3.new(WEDGE:GetAttribute("Offset" .. count), WEDGE:GetAttribute("Offset" .. count), WEDGE:GetAttribute("Offset" .. count))
local vector2 = -vector1
local vectors = {vector1, vector2}
local vector = vectors[math.random(1,#vectors)]
local origin = (WEDGE.Position + vector) - lookv * 1
local ray = workspace:Raycast(origin, lookv * 100)
if ray then
if ray.Instance.Name == "Wedge" then
plant:SetPrimaryPartCFrame(CFrame.new(ray.Position) * CFrame.Angles(math.rad(ray.Instance.Orientation.X),math.rad(ray.Instance.Orientation.Y),math.rad(ray.Instance.Orientation.Z)))
plant:SetPrimaryPartCFrame(plant.PrimaryPart.CFrame * CFrame.Angles(0,0,math.rad(-90)))
plant.Parent = WEDGE
if plant.Name == “Plant2” then
local tween = ts:Create(plant.Leaves, ti, {CFrame = plant.Leaves.CFrame * angles})
tween:Play()
local tween2 = ts:Create(plant.Stem, ti, {CFrame = plant.Stem.CFrame * angles})
tween2:Play()
else
if plant.Name == “Plant3” or plant.Name == “Plant4” or plant.Name == “Plant5” then
local tween = ts:Create(plant.Leaves, ti2, {Size = plant.Leaves.Size + Size})
tween:Play()
local tween2 = ts:Create(plant.Leaves, ti, {CFrame = plant.Leaves.CFrame * angles})
tween2:Play()
else
local tween = ts:Create(plant.Bigplant, ti, {CFrame = plant.Bigplant.CFrame * angles})
tween:Play()
end
end
end
end
end
end
end
else
if normal == Enum.NormalId.Left then
workspace.Terrain:FillWedge(WEDGE.CFrame - WEDGE.CFrame.RightVector * -1.9, WEDGE.Size + Vector3.new(2,3,3), WEDGE.Material)
WEDGE:SetAttribute("Tangible", true)
end
end
end
local function empty(WEDGE, normal)
if normal == Enum.NormalId.Right then
workspace.Terrain:FillWedge(WEDGE.CFrame - WEDGE.CFrame.RightVector * 1.9, WEDGE.Size + Vector3.new(2,3,3), Enum.Material.Air)
WEDGE.Transparency = 0
WEDGE:SetAttribute("Tangible", false)
WEDGE:ClearAllChildren()
else
if normal == Enum.NormalId.Left then
workspace.Terrain:FillWedge(WEDGE.CFrame - WEDGE.CFrame.RightVector * -1.9, WEDGE.Size + Vector3.new(2,3,3), Enum.Material.Air)
WEDGE.Transparency = 0
WEDGE:SetAttribute("Tangible", false)
WEDGE:ClearAllChildren()
end
end
end
local function createrayorigins()
local descinstfl = game.Players.LocalPlayer.Character:GetDescendants()
local descinsttl = {}
for i, child in ipairs(descinstfl) do
if child:IsA("Part") or child:IsA("Union") or child:IsA("MeshPart") then
table.insert(descinsttl, child)
end
end
local params = RaycastParams.new()
params.FilterDescendantsInstances = descinsttl
params.FilterType = Enum.RaycastFilterType.Exclude
game:GetService("RunService").RenderStepped:Connect(function()
for i, pos in ipairs(game.Players.LocalPlayer.Character.RayAtt:GetChildren()) do
if pos:IsA("Attachment") then
local direction = (game.Players.LocalPlayer.Character.Head.CFrame.UpVector) * -1
local ray = workspace:Raycast(pos.WorldCFrame.Position, direction * 5000, params)
if ray then
if ray.Instance.Parent.Parent.Name == "Planet" then
if ray.Instance ~= workspace.Terrain then
if ray.Instance:GetAttribute("Tangible") == false then
local function GetNormalFromFace(part, normalId)
return part.CFrame:VectorToWorldSpace(Vector3.FromNormalId(normalId))
end
local function NormalToFace(normalVector, part)
local TOLERANCE_VALUE = 1 - 0.001
local allFaceNormalIds = {
Enum.NormalId.Front,
Enum.NormalId.Back,
Enum.NormalId.Bottom,
Enum.NormalId.Top,
Enum.NormalId.Left,
Enum.NormalId.Right
}
for _, normalId in pairs( allFaceNormalIds ) do
-- If the two vectors are almost parallel,
if GetNormalFromFace(part, normalId):Dot(normalVector) > TOLERANCE_VALUE then
return normalId -- We found it!
end
end
return nil -- None found within tolerance.
end
local normalid = NormalToFace(ray.Normal, ray.Instance)
fill(ray.Instance, normalid)
ray.Instance:SetAttribute("Tangible", true)
end
end
end
end
end
end
for i, pos in ipairs(game.Players.LocalPlayer.Character.RayAttUn:GetChildren()) do
if pos:IsA("Attachment") then
local direction = (game.Players.LocalPlayer.Character.Head.CFrame.UpVector) * -1
local ray = workspace:Raycast(pos.WorldCFrame.Position, direction * 5000, params)
if ray then
if ray.Instance.Parent.Parent.Name == "Planet" then
if ray.Instance:GetAttribute("Tangible") == true then
local distance = (game.Players.LocalPlayer.Character.PrimaryPart.Position - ray.Instance.Position).Magnitude - 200
if distance > 150 then
local function GetNormalFromFace(part, normalId)
return part.CFrame:VectorToWorldSpace(Vector3.FromNormalId(normalId))
end
local function NormalToFace(normalVector, part)
local TOLERANCE_VALUE = 1 - 0.001
local allFaceNormalIds = {
Enum.NormalId.Front,
Enum.NormalId.Back,
Enum.NormalId.Bottom,
Enum.NormalId.Top,
Enum.NormalId.Left,
Enum.NormalId.Right
}
for _, normalId in pairs( allFaceNormalIds ) do
-- If the two vectors are almost parallel,
if GetNormalFromFace(part, normalId):Dot(normalVector) > TOLERANCE_VALUE then
return normalId -- We found it!
end
end
return nil -- None found within tolerance.
end
local normalid = NormalToFace(ray.Normal, ray.Instance)
empty(ray.Instance, normalid)
ray.Instance:SetAttribute("Tangible", false)
end
end
end
end
end
end
end)
end
script.StartRayCast:GetPropertyChangedSignal(“Value”):Connect(createrayorigins)
this is a localscript that loads terrain and generates plants on top of it setting the plant’s orientation to the wedge raycast detects.