I’m scripting a railgun (instantaneous bullet), and I was wondering if the following layout would be proper/ optimized:
client fires ray with userinputservice
if the ray comes into contact a mob (not a player), then a remote event will signal a server script to damage the mob
a bindable event is fired to all clients, which will signal a localscript to start the creation of a long part (the bullet) within the workspace current camera or local camera which extends from the gun to the ray hit position, which is destroyed soon after
First of all bindable events can only be use client side only or server side only, you cannot use them to communicate between clients. Also, If your raycasting split up the long ray into tiny rays using RunService.Heartbeat, it will save a ton of performance. Also, ensure that you find some sort of way to verify the target on the server. And on the client render the projectile as soon as they use the gun so it looks smooth, then on the server fire a remote event to all other clients to render it, and on the other clients before rendering it you can check if the projectile will be viewable from the camera to save performance.
**Edit - I just finished making a gun for a project I’m working on and to save a ton of performance put invisible border walls around the map, and when the ray comes into contact with one just delete the projectile and stop raycasting.
Thanks for all the great suggestions! I was wondering why splitting up the ray would reduce lag, and do you mean the ray fired first by the client or the bullet? How would I use RunService to split the ray furthermore? I’m not sure how to split rays in the first place; I thought they were an infinite line.
Ok Raycasting is very expensive so the longer the ray the more workload it would be, hence causing lag, to split up up rays how I do it is use a fixed speed, and then use the Delta time argument from RunService.Heartbeat to calculate the distance for the ray like this:
--Simple example of how to split up rays
--May have some syntax errors typed it online
local RunService = game:GetService("RunService")
local StartPosition --This is a vector representing where it should start
local Direction --This is a vector representing where the ray should travel
local CurrentPosition = StartPosition --This is a vector storing the current origin of the ray
local RunConn
local SPEED = 200
local MAX_DISTANCE = 500 --I set a max distance on how far the bullet can travel
RunConn = RunService.Heartbeat:Connect(function(DeltaTime)
local Distance = SPEED * DeltaTime -- Speed = Distance/Time
local CurrentRay = Ray.New(CurrentPosition, Distance * Direction)
local Hit, Pos, Normal = workspace:FindPartOnRay(CurrentRay)
CurrentPosition = CurrentPosition + (Distance * Direction)
if (CurrentPosition - StartPosition).Magnitude > MAX_DISTANCE then
RunConn:Disconnect()
RunConn = nil
end
end)
To move the bullets I use a body velocity with the same speed as the speed for casting the rays and then destroy it when the connection is disconnected. if you want to see the performance difference make two local scripts and in one cast the ray without splitting it up and in another split them up and you will see how much you save. To see a script’s performance just open the script performance window. Also I recommend you take a look at this module that uses the same approach, you may not be able to use it directly but it provides some good material related to scripting guns : Making a combat game with ranged weapons? FastCast may be the module for you!
Raycasting on Roblox is relatively quick (It’s why I wrote that module + why it has the name it does). This statement is unfortunately very false – a short ray can take just as much calculation as a long ray.
To OP – If your goal is to make a railgun, then a single raycast is the way to go no matter what. Anything more and you’re just overcomplicating it (unless you want to implement something like piercing, in which case you’d just rerun the raycast or something - keep it simple!).
As for your setup: I’d say it’s pretty good as you defined it. The only change I would make is to just create the bullet visual on the server itself and let Roblox replicate it for you rather than re-firing to all clients to say “Make this bullet here”. Since you aren’t simulating movement, rendering on the client isn’t really required since you don’t need stable visuals that don’t jitter due to latency.