I’m trying to make a tool that let’s people place down plants for a sandbox style game I’m working on. I need the plant to place only if the ray hits smooth terrain, and it needs to be placed where the ray hits. I’ve never really tried raycasting before now so I have no idea if this is easily done or not, but this is what I’ve come up from just looking at the ROBLOX wiki:
local tool = script.Parent
local player = game:GetService("Players").LocalPlayer
local mouse = player:GetMouse()
mouse.Button1Down:connect(function()
local plant = game.Players.LocalPlayer.PlayerGui.ScreenGui.selectedPlant.Value
print("Mouse pressed!")
local ray = Ray.new(tool.Handle.CFrame.p, (mouse.Hit.p - tool.Handle.CFrame.p).unit * 500)
local part, position = workspace:FindPartOnRay(ray, player.Character, true, false)
if part == game.Workspace.Terrain then
local clone = game.ReplicatedStorage.Flora[plant]:Clone()
clone.Parent = workspace
clone.PrimaryPart.CFrame = part.CFrame
end
end)
What edits will I need to make to get this to work?
Instead of setting the clone’s position to the terrain’s, set it to the position variable returned from the raycast. You already have the variable available, but you don’t use it.
This is one of the few cases where you want to check the validity of the arguments you’re receiving, rather than assuming they’re valid.
local tool = script.Parent
local player = game:GetService("Players").LocalPlayer
local mouse = player:GetMouse()
mouse.Button1Down:connect(function()
local plant = game.Players.LocalPlayer.PlayerGui.ScreenGui.selectedPlant.Value
print("Mouse pressed!")
local ray = Ray.new(tool.Handle.CFrame.p, (mouse.Hit.p - tool.Handle.CFrame.p).unit * 500)
local part, position = workspace:FindPartOnRay(ray, player.Character, true, false)
if part and (part:IsA("Terrain") or part.Name:lower() == "terrain") then
local clone = game.ReplicatedStorage.Flora[plant]:Clone()
clone.Parent = workspace
clone.PrimaryPart.CFrame = part.CFrame
end
end)
On the check line, I personally wouldn’t recommend checking by part name since BaseParts can also be named Terrain. If you must check by name, change the operator to and.
There are a few other comments I’d like to make on this code, but that’s not the point of this thread.
Make sure to also inform the user of successful or failed placements for the sake of user experience. It may be frustrating if things don’t get placed where they click, as players may think your system is broken.
This is very helpful, thank you! However 2 new issues have arisen.
No matter where I click on the terrain, the plants only get sent to the very center of the terrain base (I’m testing this on a giant grass base)
After a few seconds of using it, the tool get’s deleted seemingly for no reason. I tried moving the cloning bit over to the server side assuming it was some kind of anti exploit measure but it still gets deleted. (sorry if this one is off topic, I might have to look around for some threads or start a different one for this)
The first issue is because you’re setting the CFrame of the plant to the part’s CFrame. In the case of setting CFrames, if you set the CFrame of one object to another, it puts itself in the center. This is also so because you’re not using offset.
You’ll want to convert the position, which is the second argument you get from FindPartOnRay, into a CFrame, then set the plant’s CFrame to that. I think you can just do