How do I slow down a mining ore system, so that it's not instantaneous

I wish to have a system which awards players for mining an ore, however, the current system I have in place mines the ore the instant that the tool named “Pickaxe” is touching the ore. I’ve tried adding a wait() statement to it, and it just makes it so that each part goes transparent separately , which is not what I want it to do. Any help would be very much appreciated!

This is what happens whenever I put the tool up to the ore
https://gyazo.com/b5b1fe383f52baab8ce2df266caa4cdf

Serverscript responsible for mining the ore.

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local OreTouchedEvent = ReplicatedStorage.OreTouchedEvent
local OreTransparency = 0
local debounce = false

OreTouchedEvent.OnServerEvent:Connect(function(player, Ore)
	local char = player.Character
	local hum = char:FindFirstChildOfClass("Humanoid")
	if hum then
		local pickaxe = char:FindFirstChild("Pickaxe")
		if pickaxe then
			if debounce == false then
				debounce = true
			for _, v  in ipairs(Ore:GetChildren()) do
				if v:IsA("BasePart") and v.Name ~= "Hitbox" then
					v.Transparency += 0.25
					debounce = false
					end
				end
			end				
		end
	end
end)
1 Like

I’m assuming that on a LocalScript you’re just using the touched event.

Now I do have a little idea (not sure if it’s performant though).

You would detect the touch, task.wait for like 5 seconds, and then you’d cast a ray to see if the block is still touching. Something like this

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local OreTouchedEvent = ReplicatedStorage.OreTouchedEvent
local OreTransparency = 0
local debounce = false

OreTouchedEvent.OnServerEvent:Connect(function(player, Ore)
	local char = player.Character
	local hum = char:FindFirstChildOfClass("Humanoid")
	if hum then
		local pickaxe = char:FindFirstChild("Pickaxe")
		if pickaxe then
			if debounce == false then
				debounce = true
                -- start of new code
                task.wait(5)
                local RANGE = 2
                local Cast = workspace:Raycast(pickaxe.Position, pickaxe.CFrame.LookVector * RANGE)
                if not Cast then return end
                -- end of new code
			for _, v  in ipairs(Ore:GetChildren()) do
				if v:IsA("BasePart") and v.Name ~= "Hitbox" then
					v.Transparency += 0.25
					debounce = false
					end
				end
			end				
		end
	end
end)

If you can find the new code I added (you hopefully should be able to), I’ll just add it here separately

-- start of new code
task.wait(5)
local RANGE = 2
local Cast = workspace:Raycast(pickaxe.Position, pickaxe.CFrame.LookVector * RANGE)
if not Cast then return end
-- end of new code

And by the way, I think you could just probably get rid of the RemoteEvent and just detect the touch on the server for more performance (unless I’ve misunderstood your code)

Oh and by the way, the part I just added doesn’t check to see if the object is an ore or not so I can do that if you want me to (the stuff I added was also just an example dont actually use it)

There’s a remote event to detect which player has mined an ore, to award them with currency depending on the ore type.

1 Like

In a LocalScript?

Is this also in a LocalScript?

Could you possibly provide your LocalScript code?

Yup! In a localscript.

local IronOre = game.Workspace.IronOre
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Hitbox = script.Parent:WaitForChild("Hitbox")
local replicatedStorage = game:GetService("ReplicatedStorage")
local OreTouchedEvent = replicatedStorage.OreTouchedEvent

Hitbox.Touched:Connect(function(player)
	OreTouchedEvent:FireServer(IronOre)
end)
2 Likes

It’s slightly different for each ore type

1 Like

Wait so you have a separate script for each ore type? Why wouldn’t you just use one collective script for all of them?

I don’t really know how to create a collective localscript for each ore type, as I’m very new at scripting.

1 Like

I’d assume I’d have to use a module script

Ah nevermind then, that’s not really the main issue right now.

There’s probably a bunch of solutions but I’ll just give you one I’m just think of right now (and I’ll explain it)

Although it’s probably not the most performant way.

local IronOre = game.Workspace.IronOre
local Players = game:GetService("Players")
local Player = Players.LocalPlayer
local Hitbox = script.Parent:WaitForChild("Hitbox")
local replicatedStorage = game:GetService("ReplicatedStorage")
local OreTouchedEvent = replicatedStorage.OreTouchedEvent

-- new variables

local Character = Player.Character or Player.CharacterAdded:Wait()
local Pickaxe = Characted:FindFirstChild("Pickaxe")
local Count = 0

Hitbox.Touched:Connect(function(player)
      local function Check()
           Count += 1
           local Cast = workspace:Raycast(Pickaxe.Position, Pickaxe.CFrame.LookVector * 2)
           if Cast then
              if Cast.Instance.Name ~= IronOre.Name then return end
           else
              return
           end
        end

        repeat task.wait(1) Check() until Count == 5
	OreTouchedEvent:FireServer(IronOre)
        Count = 0
end)

There’s probably a better way but now I’m gonna explain each line

local function Check()

Just creating a new function

Count += 1

Increasing the counter each time (every second)

local Cast = workspace:Raycast(Pickaxe.Position, Pickaxe.CFrame.LookVector * 2)

Casting an invisible ray forward from the pickaxe’s position (make sure that your pickaxe’s LookVector is pointing forward)

if Cast then

Checking if the ray actually hit something

if Cast.Instance.Name ~= IronOre.Name then return end

If the instance that was hit is NOT the IronOre, then we’ll completely exit (the rest of the code will NOT RUN)

else

If our ray didn’t hit anything

return

If our ray didn’t hit anything, then we’ll exit (the rest of the code WILL NOT RUN)

repeat task.wait(1) Check() until Count == 5

Okay this explanation is gonna be the longest, so we will run the Check function every second (hence task.wait(1)) 5 times

Why? Because the count is increased everytime the Check function runs (and you know now that it runs every second). So by the 5th time, the until condition (Count == 5) will have been met and the script will move onto the next line (firing to the server via your remoteEvent)

Sorry if this is a lot to take in. Hopefully I explained it kinda okay. And yes I know this is not the most performant since I’m firing a ray 5 times but uh I couldn’t think of anything else

You could also use Part:GetTouchingParts every second but uhhh idk if that’s more performant than raycasting every second

As I have multiple ores, would I just replace the IronOre to whichever ore I need?

Also, how would I change the look vector of the pickaxe tool? As I tried checking within properties, and it wasn’t there. If it is, I probably missed it.

With the raycast results check the name of the ore (name them in the workspace) and if the result comes back with an item check

if Cast.Instance.Name == "Iron Ore" then 
    -- do code using Iron Ore variables like number of hits, value, time for debounce, etc. 
elseif Cast.Instance.Name == "Aluminum Ore" then 
    -- do code with Aluminum Ore varables
-- then whatever code for all your other ores
end
1 Like

You could try to implement a certain amount of hits an ore requires to be broken.
Additionally, have your ore touched script proceed only when its hit by an active Pickaxe. You could do this by using :SetAttribute() on the tool and checking on the server. Then just have a slight cooldown on your pickaxe so it isn’t spammable.

While trying this code out, I received an error unfortunately.

 Workspace.IronOre.Script:16: attempt to index nil with 'Position'
1 Like

You should check [Scottifly’s] post out too, there’s stuff in that post that I didn’t mention in mines

I didn’t know if your Pickaxe was a model or a part. I’ll need to see the Pickaxe’s hierarchy in the Explorer

My response to this is the same as the one above :arrow_up:

I’m simply using a part as a placeholder ,as once I get this system setup, I’ll switch it to a tool that looks like an actual pickaxe.

image

I’ve been trying to change the raycast code so that it functions as intended, but unfortunately I haven’t been able to figure it out.

The most recent error that occurred was a “attempt to index nil with ‘Part’” error on line 17, and I don’t really know why it’s doing that.

I made sure to check the look vector of the part, so that’s not the issue. The issue is unknown to me.