Hello scripters, I have been struggling with this as the main issue of this project, I have an game event that uses ray cast, and it is hooked up to an function, and I have it ran when a user types something, but once they do that it should keep looping until they say stop, but that’s where my issue is. It doesn’t loop properly, my current system is messy and anything I try with loops the ray cast “Glitches” forward then gets placed backwards, help needed, thanks in advanced.
Server sided:
game.Players.PlayerAdded:Connect(function(player)
if table.find(Permitted, player.UserId) then
player.Chatted:Connect(function(msg)
if msg == "!EyeEvent" then
if game.Workspace.HappyHome then
LaserPart.Parent = workspace
MinigameActive = true
else
Map:Clone().Parent = workspace
LaserPart.Parent = workspace
MinigameActive = true
end
elseif msg == "!EndEvent" then
MinigameActive = false
LaserPart:Destroy()
wait(2)
LaserPart.Parent = game.ReplicatedStorage
elseif msg == "!Reset" then
workspace.HappyHome:Destroy()
Map:Clone().Parent = workspace
end
end)
end
end)
MinigameActive = false
local target_previous = Vector3.new()
local Detector = Instance.new("Part")
Detector.Anchored = true
Detector.CanCollide = false
Detector.Transparency = 0.5
Detector.Color = Color3.fromRGB(255, 0, 0)
Detector.Size = Vector3.new(1, 1, 1) * 4
function startGame(Target)
local origin = rayOriginPart.CFrame.Position
local rayTarget = target_previous:Lerp(Target.Position, laser_TrackingAccuracy)
local direction = (rayTarget - origin)
local results = workspace:Raycast(origin, direction * 100, raycastParameters)
if not results then
results = {Position = rayTarget}
else
if results.Instance.Parent:FindFirstChild("Humanoid") and not results.Instance:IsDescendantOf(workspace.HappyHome) and not results.Instance.Parent:IsA("Accessory") then
results.Instance.Parent:FindFirstChild("Humanoid"):TakeDamage(10)
elseif results.Instance:IsDescendantOf(workspace.HappyHome) then
local NewDetector = Detector:Clone()
NewDetector.Parent = workspace
NewDetector.Position = results.Instance.Position
local PartsList = NewDetector:GetTouchingParts()
results.Instance:Destroy()
for _,Part in ipairs(PartsList) do
if Part:IsDescendantOf(workspace.HappyHome.Home.House) then
Part:BreakJoints()
Part:ApplyImpulse(math.random(1, 100), math.random(100, 500), math.random(1,100))
end
end
NewDetector:Destroy()
wait(1)
end
end
local distance = (results.Position - origin).Magnitude
local LaserPosition = laserPart.Position
LaserPart.Size = Vector3.new(laser_Thickness,laser_Thickness,distance)
laserPart.CFrame = CFrame.new(origin, results.Position) * CFrame.new(0,0, -distance/2)
target_previous = rayTarget
end
while true do
if MinigameActive == true then
Runservice.Stepped:Connect(function(dt)
local target = FindNearest(rayOriginPart.Position)
if target then
startGame(target.HumanoidRootPart)
end
end)
end
wait(10)
end
The final loop is repeatedly calling Runservice.Stepped:Connect which is going to create a multitude of connections (all firing). Define the connection outside the loop and put the conditional check inside it, like so.
Runservice.Stepped:Connect(function()
if MinigameActive then
local target = FindNearest(rayOriginPart.Position)
if target then
startGame(target.HumanoidRootPart)
end
end
end)
You will no longer need the while loop if you do that, but you will also be doing a lot of ray casting. If you only want to check every 10 seconds, then save the connection and disconnect it afterwards…
local cnx = Runservice.Stepped:Connect(function()
-- do something
cnx:Disconnect()
end)
After looking at this closer, I see that you have it setup so when the user types “!EyeEvent” you want to start the minigame, and when they type “!EndEvent” you want to end it. For this, create a BindableEvent and then Fire it with a value of true or false depending on what the user types (to enable or disable the game). Then you create a connection to that event and can just spin a normal wait loop inside that connection (no need for run service). You will need to use a RemoteEvent if this is going local->server.
you could put something like this where you want to start the game:
MinigameActive = true
coroutine.wrap(function()
while MinigameActive do
wait(update_rate)
--- your game loop logic
if MinigameActive then
local target = FindNearest(rayOriginPart.Position)
if target then
startGame(target.HumanoidRootPart)
end
end
end
end)()
so that every time the amount of seconds in the update_rate variable passes your game loop logic runs.
and the to stop it you just set MinigameActive = false
Here’s an example. Paste this into a new workspace and create a BindableEvent in replicated storage…
local m = game.ReplicatedStorage.Event
local running = false
m.Event:Connect(function(isRunning, id)
print("called with", id)
running = isRunning
while running do
print("Is running")
wait(0.5)
end
print("ending")
end)
m:Fire(true, 1)
wait(3)
m:Fire(false, 2)
Here’s the output:
16:29:33.760 called with 1 - Server - Script:5
16:29:33.760 ▶ Is running (x6) - Server - Script:8
16:29:36.764 called with 2 - Server - Script:5
16:29:36.764 ▶ ending (x2) - Server - Script:11
You can see it ran for a while, and then both callbacks exited.
Woah! Okay I see, that’s really cool, haven’t really looked in bindable events, that is really interesting. Thanks! I will research that, any advice before hand?
BindableEvents are for local->local or server->server. If you need to do local->server or server->local, use a RemoteEvent. Also, whenn you are reading the docs, anytime you see RBXScriptSignal that means it’s an event (they are in the Events section) but that means you can :Connect to them. Lastly, know that events stay connected until you disconnect them or the item they are connected to is destroyed. Normally, you want to stay connected until it is destroyed, but in some instances you will want to disconnect manually.