How would I go about a continuous beam in the most efficient way?

As seen in the GIF below from the game Power Simulator:
https://gyazo.com/a2111b96ff443bf25b991c6972e119ed

Does anyone have any idea how this is achieved? Because by the looks of it, the beam is resizes depending on the distance it has reached, meaning the ray API is used. But would this mean hundreds of rays are being fired to figure out the distance of the beam as well as acting as a damager? I have a feeling if I did this it would not be healthy for the server to deal with.

Furthermore, there is a particle at the end of the ray which suggests there is a dummy part at the hit position at the end of the ray to emit the particles.

1 Like

Well, only thing I have in mind right now is raycasting + particle effects. You can also use UnbindAction and ContextActionService if you want to trigger it that way.

Hope this helped.

1 Like

Do you reckon the raycasting if fired hundreds of times to get a distance to then resize the beam part?

Not entirely sure what you mean, but maybe you should try and experiment with raycasting to know more about this feature.

By the looks of it, the size of the beam part (yellow neon cylinder) depends on how far the target is. For example, if a player shoots the beam at a part 10 studs away, then the beam part coming out of the hand is 10 studs long. This is constantly updating as the player changes the distance of their target.

Would it be wise to fire hundreds of rays within let’s say, 10 to 15 seconds?

1 Like

Make ray every frame for 10 - 15 seconds and if the magnitude between player hits the position of ray is different, update the beam.

Would that be stressful for the server?

No, raycasting is very cheap. If you’re worried about it, you could have the server tell each client to do the raycasting and rendering of the cylinder.

6 Likes

I see, I will look into this, thank you!

Here’s a sample of what you can do:

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local Player = Players.LocalPlayer
local Mouse = Player:GetMouse()
local Character = Player.Character or Player.CharacterAdded:Wait()
-- Placeholders
local Part
local Ray

UserInputService.InputBegan:Connect(function(InputObject, GameProcessed)
	if InputObject.UserInputType == Enum.UserInputType.MouseMovement then
		Part:Destroy()
		local Ray = Ray.new(Character.RightHand.CFrame.p, (mouse.Hit.p - Character.RightHand.CFrame.p).unit * 300)
		local Part = Instance.new("Part")
		local FoundPart, Position = workspace:FindPartOnRay(Ray, Character, false, true)
		local Distance = (tool.Handle.CFrame.p - position).magnitude
		Part.Size = Vector3.new(0.3, 0.3, distance)
		Part.CFrame = CFrame.new(Character.RightHand.CFrame.p, position) * CFrame.new(0, 0, -Distance / 2)
		Part.Parent = workspace
	end
end)
3 Likes
Reply to old post

That’s the purpose of this thread if you read it first before posting; finding out how this was done.

Getting the player’s mouse doesn’t really say anything about accomplishing this. Yes, it gets the mouse but what then? You’ll need to include a lot more than that.

1 Like

Oh wow, that’s fantastic, I will take this apart to see if I can utilise this in my code :smiley:

1 Like

Sorry for posting such a basic reply, I initially saw a reply of my infinished reply and panicked so I gave another unfinished reply.

1 Like

No worries, perfect reply thank you! So far this looks like it’s all a client thing, of course will cause security ramifications. Would it be stressful on the server to request where the mouse position be within renderstepped? Or should it be vice versa, the client sends to the server the mouse position, and then once the server does all that fancy calculations with rays, use FireAllClients to render the beam effect? Note that this will be alongside the the ray creation.

You can utilize remotes in order to do this, but the replication is up to you. It’s just an example.
However, constantly firing a remote can cause some network problems so I would definitely recommend only allowing it to be fired when it is enabled.

1 Like

Sorry to bother again, in your opinion, would it be wise to do this:

Client sends mouse position to server > server creates ray > server uses :FireAllCients(startPosition, hitPosition) > client renders the beam.

Note this is gonna happen every heartbeat:wait()/renderstepped, or at least 0.1 seconds.

I would recommend doing everything visual on the server, to improve UX since there will be a delay if you wait for the server to respond. What we can do, is handle damage on the server since that is what is mostly able to be exploited when having things handled on the client.

Instead of ray casting I made a simple script using a beam, you can check it out if you’d like.
https://gyazo.com/3754eee997bb588a9d38b38b7755dc15

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Player = Players.LocalPlayer
local UserInputService = game:GetService("UserInputService") 
local Mouse = Player:GetMouse()
local Held = false
local Character = Player.Character

local Beam = Instance.new("Beam")
Beam.Segments = 1
Beam.Width0 = 1
Beam.Width1 = 1
Beam.Color = ColorSequence.new(Color3.new(1, 0, 0))
Beam.FaceCamera = true
local attachment0 = Instance.new("Attachment")
local attachment1 = Instance.new("Attachment")
Beam.Attachment0 = attachment0
Beam.Attachment1 = attachment1
Beam.Parent = workspace.Terrain
attachment0.Parent = workspace.Terrain
attachment1.Parent = workspace.Terrain
Beam.Enabled = false

repeat wait() until Character
local BodyGyro = Instance.new("BodyGyro", Character.HumanoidRootPart)

UserInputService.InputBegan:Connect(function(inputObject,chatting)
	if chatting then return end
	if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
		Beam.Enabled = true
		Held = true
		while Held do
			BodyGyro.MaxTorque = Vector3.new(0,math.huge,0)
		 	BodyGyro.CFrame = CFrame.new(Character.HumanoidRootPart.CFrame.p, Mouse.Hit.p)
			BodyGyro.P = 1e9
			local RightHand = Character:FindFirstChild("RightHand")
			attachment0.Position = RightHand.Position
			attachment1.Position = Mouse.Hit.p
			wait()
		end
	end
end)

UserInputService.InputEnded:Connect(function(inputObject)
	if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
		Held = false
		Beam.Enabled = false
	end
end)
6 Likes

Wow I never thought about using a beam, certainly reduces the stress as a part is no longer needed to simulate the beam. However, just at a glance, wouldn’t the beam penetrate parts? Seeing as there’s no way to tell the beam to stop at a certain range when something if between the player and the mouse position.

I am not entirely sure about this, I would test it to make sure it is compatible for your particular use case.

I wouldn’t worry about raycasting.
Raycasting doesn’t use much performance, especially if you’re not doing a lot of long distance rays.

In Hackr I do up to ~25 raycasts every frame (60 frames per second) for no performance loss.