Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

Need some direction with bee swarm style mining script?

Asked by 3 years ago
Edited 3 years ago

Hello, new user here.

I have been tinkering with roblox scripting for a few weeks now and I have been trying to emulate the bee swarm style mining system (or rather pollen gathering system). right now I have a setup of raycasts to come from the players head in various directions and then detect the part they are hitting and then move the part down by a marginal amount as the flowers do in bee swarm. Everything I have done is from browsing the internet for hours upon hours to get this to work lol. As of right not it works, however its not perfect like it is in bee swarm. So to get to my question, is there a better way I could be doing this? Should I be using raycasting? Originally I was using onotouched, with an invisible "scoop" which would do the same onTouched as the rays with different shapes.

Again, I am very new to scripting and have been doing it for fun in my free time via watching videos, reading and just trying things out. So my code most certainly isn't pretty or perfect, just asking for some direction so I can continue this fun project! thanks

game.Players.PlayerAdded:Connect(function(player)
    player.CharacterAdded:Connect(function(character)

        -- get the event from client side
        local ReplicatedStorage = game:GetService("ReplicatedStorage")
        local rayCastEvent1 = ReplicatedStorage:FindFirstChild("rayCastEvent1")

        -- raycast function
        local function rayCastEvent1(player,var)

            local raycastParams = RaycastParams.new()
            raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
            raycastParams.FilterDescendantsInstances = {character}
            raycastParams.IgnoreWater = true

            -- fire multiple raycast to move multiple parts of the mine at once
            local raycastResult = workspace:Raycast(character.Head.Position, Vector3.new(0, -50, -20), raycastParams)
            local raycastResult2 = workspace:Raycast(character.Head.Position, Vector3.new(0, -100, 0), raycastParams)
            local raycastResult3 = workspace:Raycast(character.Head.Position, Vector3.new(0, -50, 20), raycastParams)
            local raycastResult4 = workspace:Raycast(character.Head.Position, Vector3.new(20, -50, 0), raycastParams)


            if raycastResult or raycastResult2 or raycastResult3 or raycastResult4 then

                    -- find parts hit by raycast
                local hitPart, hitPosition = unpack({raycastResult.Instance.Parent, raycastResult.Position})
                local hitPart2, hitPosition2 = unpack({raycastResult2.Instance.Parent, raycastResult2.Position})
                local hitPart3, hitPosition3 = unpack({raycastResult3.Instance.Parent, raycastResult3.Position})
                local hitPart4, hitPosition4 = unpack({raycastResult4.Instance.Parent, raycastResult4.Position})


                -- set model# to part hit by each raycast   
                local model = hitPart
                local model2 = hitPart2
                local model3 = hitPart3
                local model4 = hitPart4
                wait()

                -- find the child of the part hit since the part hit is the model
                if hitPart.Parent or hitPart2.Parent or hitPart3.Parent or hitPart4.Parent == game.Workspace.mineParts then

                    hitPart.PrimaryPart = hitPart:FindFirstChild("aMinePart")
                    hitPart2.PrimaryPart = hitPart2:FindFirstChild("aMinePart")
                    hitPart3.PrimaryPart = hitPart3:FindFirstChild("aMinePart")
                    hitPart4.PrimaryPart = hitPart4:FindFirstChild("aMinePart")

-- move parts hit by ray with cframe
                hitPart:SetPrimaryPartCFrame(hitPart:GetPrimaryPartCFrame()*CFrame.new(0,-.3,0))
                    hitPart2:SetPrimaryPartCFrame(hitPart2:GetPrimaryPartCFrame()*CFrame.new(0,-.3,0))
                    hitPart3:SetPrimaryPartCFrame(hitPart3:GetPrimaryPartCFrame()*CFrame.new(0,-.3,0))
                    hitPart4:SetPrimaryPartCFrame(hitPart4:GetPrimaryPartCFrame()*CFrame.new(0,-.3,0))

                    wait(5)
                    hitPart:SetPrimaryPartCFrame(hitPart:GetPrimaryPartCFrame()*CFrame.new(0,.3,0))
                    hitPart2:SetPrimaryPartCFrame(hitPart2:GetPrimaryPartCFrame()*CFrame.new(0,.3,0))
                    hitPart3:SetPrimaryPartCFrame(hitPart3:GetPrimaryPartCFrame()*CFrame.new(0,.3,0))
                    hitPart4:SetPrimaryPartCFrame(hitPart4:GetPrimaryPartCFrame()*CFrame.new(0,.3,0))
                end



            end

        end
        game.ReplicatedStorage.rayCastEvent1.OnServerEvent:Connect(rayCastEvent1)

    end)
end)

1 answer

Log in to vote
0
Answered by 3 years ago
Edited 3 years ago

Hello,

Very fun question. Let's unpack it to make sure we're on the same page:

After going and playing "Bee Swarm Simulator" for about a minute, I seem to notice something. It appears as if each Bee chooses a random part that is within a certain radius to the player, farms the part, and then chooses another part within a certain radius of the player. This means that we have to construct an algorithm to:

  1. Figure out which flower field the player is on.

  2. Search through each flower part in the field and measure the distance between a given flower and the player.

  3. Choose a random flower part that is within the distance given.

Pretty straightforward.

To figure out which field the player is located on, we could use various methods. The method I am going to use will be checking if the player's location is within a certain area. To do this I create minimum and maximum x and z values to check against the player's position. We encapsulate this code in a function so that we can use it later.

Implementation of said function:

local minx = 0
local maxx = 100
local minz = 0
local maxz = 100

local function infield(player) --input with player object
    local char = player.Character or workspace:WaitForChild(player.Name)
    local plrpos = char.PrimaryPart.Position
    local plrposx = plrpos.X
    local plrposz = plrpos.Z

    if (plrposx >= minx) and (plrposx <= maxx) and (plrposz >= minz) and (plrposz <= maxz) then
        return true, workspace.Field1
    else
        return false, nil
    end
end)

I will note that this function is very simple and only accounts for one field, but in reality, you're probably going to be using touch interests to be figuring out the position/field anyway. If you really do want to use a function like this though, we could create a 2d array to store the info of each field.

An example of said system is shown below. We assume that you have a folder in the workspace called "Fields" that contains invisible, anchored, and non-collidible parts to represent the boundaries of each field. We also assume that the parts are named the same as each real field that is parented to the workspace. Using these parts, we can create many arrays of many maximum and minimum x and z values.


local allfields = {} for i,v in pairs(workspace.Fields:GetChildren()) do local ms = v.Size local mp = v.Position local xl = mp.X - ms.X/2 local xm = mp.X + ms.X/2 local zl = mp.Z - ms.Z/2 local zm = mp.Z + ms.Z/2 table.Insert(allfields,{v.Name,xm,xl,zm,zl}) --insert min/max info into big table end local function infield(player) --input with player object local char = player.Character or workspace:WaitForChild(player.Name) local plrpos = char.PrimaryPart.Position local plrposx = plrpos.X local plrposz = plrpos.Z for i,v in pairs(allfields) do if (plrposx >= v[2]) and (plrposx <= v[3]) and (plrposz >= v[4]) and (plrposz <= v[5]) then return true, workspace[v[1]] end return false, nil end)

Alright, now that we've gone over figuring out the player's field, we can go on searching through all the flower objects in the field. To do this, we'll create a function that searches through the field and checks the distance between the player and the flower part. Luckily for us, Roblox already has a function that can check the distance between two points called Magnitude. This means that we just have to loop, use the function, and then add it to a table if it's within our threshold.

local distance = 10

local function searchfield(player,field)
    local char = player.Character or workspace:WaitForChild(player.Name)
    local plrpos = char.PrimaryPart.Position

    local accepted = {}

    for i,v in pairs(field:GetChildren()) do
        if (plrpos - v.Position).Magnitude <= distance then
            table.Insert(accepted,v)
        end
    end

    return accepted
end)

Now, we simply choose a random value within our table. To do this cleanly, I'm going to create yet another function that incorporates our previous functions

local function pickflower(player)
    local in, field = infield(player)
    if in == false then
        return false
    end

    local flowers = searchfield(player,field)

    if #flowers == 0 then
        return false
    end

    return flowers[math.random(1,#flowers)]
end)

Let's put all our code together:

local allfields = {}

for i,v in pairs(workspace.Fields:GetChildren()) do
    local ms = v.Size
    local mp = v.Position

    local xl = mp.X - ms.X/2
    local xm = mp.X + ms.X/2

    local zl = mp.Z - ms.Z/2
    local zm = mp.Z + ms.Z/2

    table.Insert(allfields,{v.Name,xm,xl,zm,zl})
end

local function infield(player)
    local char = player.Character or workspace:WaitForChild(player.Name)
    local plrpos = char.PrimaryPart.Position
    local plrposx = plrpos.X
    local plrposz = plrpos.Z

    for i,v in pairs(allfields) do
        if (plrposx >= v[2]) and (plrposx <= v[3]) and (plrposz >= v[4]) and (plrposz <= v[5]) then
        return true, workspace[v[1]]
    end

    return false, nil
end)

local distance = 10

local function searchfield(player,field)
    local char = player.Character or workspace:WaitForChild(player.Name)
    local plrpos = char.PrimaryPart.Position

    local accepted = {}

    for i,v in pairs(field:GetChildren()) do
        if (plrpos - v.Position).Magnitude <= distance then
            table.Insert(accepted,v)
        end
    end

    return accepted
end)

local function pickflower(player)
    local inA, field = infield(player)
    if inA == false then
        return false
    end

    local flowers = searchfield(player,field)

    if #flowers == 0 then
        return false
    end

    return flowers[math.random(1,#flowers)]
end)

Why is this any better?

With a function-oriented system, we've made it easier to change our code, easier to scale up our game/functions, easier for others to read your code, AND we've created a robust system that is able to properly manage which flowers to pick, instead of just firing Rays all around.

Implementation

Ok, we can pick a flower! Now what? Let's implement your code:

We can create a variable named 'Bees' that will dictate how many bees we have access to, we then take this number and use it to dictate how many parts should be moved down. Another thing we can add is a loop that tells the bees when to mine blocks.

An implementation of this is seen below:

local bees = 5

while true do
    for i,v in pairs(game:GetService("Players"):GetChildren()) do
        local pick = pickflower(v)

        if pick ~= false then
            local maxbees = bees

            if maxbees > #pick then
                maxbees = #pick
            end

            for bee = 1, maxbees do
                local num = math.random(1,#pick)
                local picked = pick[num]
                table.remove[pick,num]

                --do whatever you want with picked
            end
        end
    end

    wait(1)
end

Practice Exercises

  • Implement the code so that many different people can farm

  • Make the number of bees differ from person to person

  • Make the number of bees save when you rejoin

Resources

Below is documentation discussing everything I have used and explained to you in this post:

Functions

Basic Loops

I'V Pairs

Magnitude

Conclusion

I hope I was able to help set you in a positive direction!

Cheers,

Chase

0
thank you very much for the in depth answer, I really didn't expect this! I dont have time to go over this tonight but I will attempt to implement this tomorrow and see where I can get with your practice questions as well. I really do appreciate it! ChunkyChubbs123 7 — 3y
Ad

Answer this question