Making a shuriken that shows damage when hit

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? I want to make a tool that throws a shuriken when activated. If the shuriken hits an NPC or a player, a text label appears, showing how much damage that NPC or player had taken.

  2. What is the issue? I used a remote function to return the damage and the target position. The remote function only returns when the shuriken has been destroyed (by debris or by hitting a NPC/player), which is detected by a repeat-until loop. The problem is when multiple shurikens are thrown and some hit an NPC/player, the remote function doesn’t return anything until the last shuriken is destroyed.

  3. What solutions have you tried so far? I have tried replacing the repeat-until loop with ChildRemoved event but the remote function returns before the shuriken is destroyed so it becomes nil.

Serverscript.Script:

local ServerStorage = game:GetService("ServerStorage")
local Debris = game:GetService("Debris")
game.ReplicatedStorage.ThrowShuriken = function(plr, target, startPos, mousePos)
      local shuriken = ServerStorage.Shuriken:Clone()
      shuriken.Name = plr.Name.."Shuriken"
      shuriken.Position = startPos
      shuriken.Parent = workspace
      local bodyVelocity = Instance.new("BodyVelocity", shuriken)
      bodyVelocity.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
      bodyVelocity.Velocity = (mousePos - startPos).unit*100
      local bodyAVelocity = Instance.new("BodyAngularVelocity", shuriken)
      bodyAVelocity.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
      bodyAVelocity.AngularVelocity = shuriken.CFrame:ToWorldSpace(CFrame.new(0, 5, 0)).Position - shuriken.Position
      shuriken.Touched:Connect(function(a)
             if a:FindFirstAncestorOfClass("Model") and a:FindFirstAncestorOfClass("Model") ~= plr.Character and a:FindFirstAncestorOfClass("Model"):FindFirstChild("Humanoid") then
                  shuriken.CanTouch = false
                  a:FindFirstAncestorOfClass("Model").Humanoid:TakeDamage(math.random(24, 26))
                  shuriken:Destroy()
            end
      end)
      Debris:AddItem(shuriken)
      repeat wait() until not shuriken:IsA("BasePart") -- The line here only checks if the last shuriken thrown was destroyed or not although the "shuriken" variable is created every time this remote function fires
      if shuriken.CanTouch then
            return damage, target.Position
      else
           return nil, nil
      end
end

StarterPack.Shuriken.LocalScript:

local canThrow = true
local mouse = game.Players.LocalPlayer:GetMouse()
script.Parent.Activated:Connect(function()
       if canThrow then
             spawn(function()
                  canThrow = false
                  wait(0.5)
                  canThrow = true
            end)
            local damage, targetPos = game.ReplicatedStorage.ThrowShuriken:InvokeServer(mouse.Target, script.Parent.Handle.Position, mouse.Hit.p)
            if damage and targetPos then
                  local position, OnScreen = game.Workspace.CurrentCamera:WorldToScreenPoint(targetPos)
                  if OnScreen then
                        game.Players.LocalPlayer.PlayerGui.ScreenGui.DamageLabel.Position = Udim2.new(0, position.X, 0, position.Y)
                        game.Players.LocalPlayer.PlayerGui.ScreenGui.DamageLabel.Visible = true
                        wait(0.5)
                        game.Players.LocalPlayer.PlayerGui.ScreenGui.DamageLabel.Visible = false
                  end
            end
      end
end)

This post might not be clear, since this is my first post. I won’t mind if you gave feedback on it so I can improve :slight_smile:

Don’t use loops to check for things.

Loops are inefficient, messy, and often break your code.

Instead use events, that’s what events are for. Events are passive (not running when nothing is happening) and create less problems.

Do you mean like this?

local result = game.Workspace.ChildRemoved:Connect(function(child)
    if child == shuriken and shuriken.CanTouch == false then
        return damage, target.Position
    else
        return nil, nil
    end
end)
return result

If yes then, as I said above, the result is returned before the part is destroyed so client side recieves nil

Should I use a remote event and instead of returning damage, I’ll use another remote event to :FireClien()?

Okay imma give a bunch of feedback

other feedback

Firstly, the “template topic” is meant to be replaced by your own topic. What I am saying is don’t post:

I see many times people leave the template topic and just add a few extra words to answer the template questions. Normally I don’t say anything but since you asked I gave my feedback.


Next,

Is this meant to say
game.ReplicatedStorage.ThrowShuriken.OnServerInvoke = function
?


Next,

Correct that will not work


I’m confused the function should be running and returning independently each time it’s called, you can use print statements to see it more clearly.

Thanks a lot, but I solved it by replacing the remote function with a remote event, and fires the remote event back to the client whenever the shuriken hits. The repeat-until loop is now put in a spawn() function variable.

Maybe you could spawn an invisible part with a billboardgui?