Chopping tree exactly where you clicked

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