# Chopping tree exactly where you clicked

I know that this has been asked before but the answer I got from the creator of Lumber Tycoon I could not make anything out of. How to make a choppable tree like in lumber tycoon 2?
can somebody please explain how I would use
treePart.CFrame:pointToObjectSpace(mouseClickPos)
and if you want, it would be nice to give a script for the axe to do this, instead of just clicking the tree. but that is only if you like.

1 Like

treePart.CFrame:PointToObjectSpace(mouseClickPos gives the position of the mouse hit relative to the tree part (the tree part is kind of treated as the center of the world).

If your tree part has other tree parts connected to it, this might work, if their size is biggest on their y axis and they are positioned and oriented so that connectedTreePart.CFrame*Vector.new(0, -connectedTreePart.Size.Y/2, 0) is closer to the tree partâ€™s CFrame on the tree partâ€™s CFrameâ€™s x and z axis than connectedTreePart.CFrame*Vector.new(0, connectedTreePart.Size.Y/2, 0) is.

local function createWeldConstraint(part0, part1)
local weldConstr = Instance.new("WeldConstraint")
weldConstr.Part0, weldConstr.Part1 = part0, part1
weldConstr.Parent = part0
end

local function makeTreeFall(treePart, hitPos)
local treePartCf = treePart.CFrame
local relY = treePartCf:PointToObjectSpace(hitPos).Y
local upperParts, lowerParts = {}, {}
for i, v in ipairs(treePart:GetConnectedParts()) do
if v ~= treePart then
if treePart.CFrame:PointToObjectSpace(v.CFrame*Vector3.new(0, -v.Size.Y/2, 0).Y > relY then
upperParts[#upperParts+1] = v
else lowerParts[#lowerParts+1] = v
end
end
for i, child in ipairs(v:GetChildren()) do
if child:IsA("WeldConstraint") and (child.Part0 == treePart or child.Part1 = treePart) then
child:Destroy()
end
end

local orgSize = treePart.Size
treePart.Size = Vector3.new(orgSize.X, orgSize.Y/2+relY, orgSize.Z)
local newTreePartSize = orgSize-Vector3.new(0, treePart.Size.Y, 0)
treePart.Position = treePartCf*Vector3.new(0, -newTreePartSize.Y/2, 0)

local newTreePart = treePart:Clone()
newTreePart.Size = newTreePartSize
newTreePart.Position = treePart.CFrame*Vector3.new(0, newTreePartSize.Y/2+treePart.Size.Y/2, 0)
-- new welds
for i, upperPart in ipairs(upperParts()) do
createWeldConstraint(newTreePart, upperPart)
end
newTreePart.Parent = treePart.Parent

for i, lowerPart in ipairs(lowerParts) do
createWeldConstraint(treePart, lowerPart)
end
end

To do the axe thing, raycasting might be useful. When the axe is swinging, you could cast a ray from where the ax blade starts to the end of the ax blade every frame to detect when it hits a tree part. Then give the position and the part of the raycastresult to the makeTreeFall function if the part is a tree part.

local RunService = game:GetService("RunService")

local function makeParams(char)
local params = RaycastParams.new()
params.FilterType =
Enum.RaycastFilterType.Blacklist
params.FilterDescendantsInstances = {char}
end

local function isTreePart(part)
-- your logic here (maybe check the name or parent)
-- return true if it is a tree part
end

local function detectHits(axe, animTrack)
local char = axe.Parent
local params = makeParams(char)
while animTrack.IsPlaying do
local startPos = -- where the ray should start
local endPos = -- where the ray should end
local rayDirection = endPos-StartPos
local raycastResult = workspace:Raycast(startPos, rayDirection, params)
local hitPart = rayCastResult and raycastResult.Instance
if hitPart and isTreePart(hitPart) then
makeTreeFall(raycastResult.Position, hitPart)
return
end
RunService.Heartbeat:Wait()
end
end
4 Likes

well if the tree part had different parts to it, wouldnâ€™t I be able to use mouse.Target, and make it have the part be a specific name so it can recognize it and unweld it? ( changing the name to get rid of script confusion )

You can get the distance of the players click from the middle of the part. This will give you a rough idea of where the player is attempting to chop it.

You would most likely need to round values for this as a players click would be on the surface of the part.

Yes, you can use mouse.Hit and mouse.Target. I just thought raycasting from the axe blade was what you wanted.

It depends, I now have made the code to do so but It will be hard to fire a server to get it to work for a tool. If you could help it would be nice:

local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera
local RunService = game:GetService("RunService")
local target
local down
local WalkKey = "G"

game:GetService("UserInputService").InputBegan:Connect(function(inputObject, gameProcessedEvent)
if inputObject.KeyCode == Enum.KeyCode[WalkKey] then
if mouse.Target.Name == "UnweldTest" then
mouse.Target.Weld:Destroy()
mouse.Target.Name = "Welded"
if mouse.Target ~= nil and mouse.Target.Locked == false then

end
end
end
end)

this finds the weld, gets rid of it from the name and then changes the name so no confusion happens. but its keybinded, and also will only work in StarterCharacterScripts. Is there a way to put this in Server Script Service, so it can receive the fired event? While I could try and make it look for the tool it would be hard.

wait forget thatâ€¦ I just did it. I simply searched for the player model and tryed to see if I could find the tool. now It works perfectly! Here is the script, for people who want it. ( local script inside Starter Character Scripts )

local player = game.Players.LocalPlayer -- finds local player
local mouse = player:GetMouse()  -- finds local players mouse
local camera = workspace.CurrentCamera -- finds current camera
local RunService = game:GetService("RunService")  -- finds runservice
local target  -- dont change, finds mouses target
local down
local WalkKey = "G" -- set G to whatever keybind you want it to be for.
local PlayerModel = workspace:WaitForChild(player.Name,1) -- dont change, finds the players model.

game:GetService("UserInputService").InputBegan:Connect(function(inputObject, gameProcessedEvent) -- plays by keybind, change this to click if you like.
if inputObject.KeyCode == Enum.KeyCode[WalkKey] then
if mouse.Target.Name == "UnweldTest" then -- set UnweldTest to whatever part you want to be unwelded.
if PlayerModel.Hello then -- change Hello to the axe or tools name
mouse.Target.Weld:Destroy() -- this destroys weld
mouse.Target.Name = "Welded" -- change to whatever you want besides Unweld test, or what you made the wanted targets name.
if mouse.Target ~= nil and mouse.Target.Locked == false then -- extra
end
end
end
end
end)

Everything works for me! After this I will probably find out how to put force on the part so it falls over.