How can I make a client-sided projectile?

Hello,
I’ve been trying to make a client sided projectile, but I got stuck. So how can I do this? I tried remote events and bindable events and none of them worked in my favor. So what should I do? I also know this is a basic question, but any help is appreciated.

Thank you,
in advance.

2 Likes

I would use FastCast. It’s a very good module. He also has a video using it to do client replication. Although it’s outdated, it will give you a general idea of how client-sided projectiles are programmed.

1 Like

Is there another way to this? I have never touched modules before, and even with the youtube video I doubt I would be able to understand or use it. But, thank you for the response!

I would recommend that if you want to script anything remotely advanced, module scripts are imperative for you to learn, but this can be done without the module.

I would have the hit-scan be on the server, and the visual projectile be on the client. It would go something like this:

The server fires a ray projectile for hitscan, and every time the ray is updated, you would fire a RemoteEvent to the client sending information about the position and the direction. The client would then create a part and move the part every time it received more information about the server-sided array.

You would want the remote event firing pretty frequently for smooth effects, so I’d suggest using RunService.

1 Like

Is it possible I use body velocity instead? I know ray cast is much better, but for me body velocity is simpler.

Instance.new("Part") in a local script, you can handle its movement locally as well (providing the part is left unanchored) as movement of unanchored parts replicates to the server.

What are you trying to to? Create an projectile and that everyone can see or ONLY the player?

A projectile everyone can see, but it fires from all clients to get a fast response time.

If I were you, I would create the projectile on the server, and then do the visuals on the client. Then you compare the two to make sure there isn’t anyone exploiting it badly.

How should I go about testing the input?

The input of the user? If so use inputservice

This only works locally not on the server even if I unanchored the part.

Should I use a bindable event, remote event, or remote function?

For sending information about the projectile remote events.

1 Like

I just learned user input service can’t be used on a script. :confused: So how should I go about testing detection now?

Ok so I’ve managed to work something up, but it still works only on the local script maybe you can edit it to make it work on server. Here’s what I have
(In Order)
Local Script:

local player = game:GetService("Players").LocalPlayer
local mouse = player:GetMouse()
local UserInputService = game:GetService("UserInputService")
local RemoteEvent = script:WaitForChild("RemoteEvent")

local Holding = false
local debounce = false

if not UserInputService.KeyboardEnabled and not UserInputService.MouseEnabled then
	script.Parent:Destroy()
elseif UserInputService.KeyboardEnabled and UserInputService.MouseEnabled then

	mouse.Button1Down:Connect(function()
		Holding = true	
		repeat wait(0.25)
			if not debounce then
				debounce = true
				RemoteEvent:FireServer()
				wait(0.25)
				debounce = false
			end
		until Holding == false
	end)

	mouse.Button1Up:Connect(function()
		Holding = false
	end)
end

Script:

local RemoteEvent = script.Parent:WaitForChild("RemoteEvent")

local Event = script:WaitForChild("Event")

RemoteEvent.OnServerEvent:Connect(function(player)

Event:FireAllClients(player)

end)

Local Script:

local Event = script.Parent:WaitForChild("Event")
Event.OnClientEvent:Connect(function(player)
	local character = player.Character
	
	local Projectile = game:GetService("ReplicatedStorage").Objects:WaitForChild("Projectile"):Clone()
	Projectile.Parent = workspace
	Projectile.Position = character.Direction.Position
	local Fire = Instance.new("Sound")
	Fire.SoundId = "http://www.roblox.com/asset?id=130113322"
	Fire.Volume = 0.25
	Fire.Parent = Projectile
	Fire:Play()

	--Body Velocity

	local BodyVelocity = Instance.new("BodyVelocity")
	BodyVelocity.Parent = Projectile
	BodyVelocity.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
	BodyVelocity.Velocity = character.Direction.CFrame.LookVector * 150

	wait(0.4)
	Projectile:Destroy()
end)

if you have the projectile being fired in a local script, and it does not get replicated ( check roblox documentation ) it will be clientside. it all depends on what exactly you want, if i knew more i could give more guidance

You want to use a RemoteEvent. RemoteEvents and functions are meant to communicate server to client, and Functions will yield the code who fired it until the function bound ends, returning the parameters you want to. I am not experienced on FPS games, but I think it might be good to follow these steps:

  • First, create a local script, with an event to shoot the projectile (mouse click, bind a key, etc);
  • Second, get the parameters that will be used for the projectile (aim direction, weapon used);
  • Make a check on that local script to see if the player can shoot the bullet, and if it’s allowed, FireServer the remoteevent, passing the parameters used (aim direction, weapon used);
  • On the server script, bind the remoteevent.OnServerEvent to the function that will check the bullet collision. The first parameter on that function is always the player who fired the event, and the rest are the parameters you passed (aim, weapon used);
  • On the function you bound to the event, check again if the player can shoot (enough ammo, cooldown), in order to prevent exploiters;
  • If the player can shoot, raycast the trajectory from the player position to the aim direction, and apply damage if it hits a player; If the bullet is visibly slow, you can use spawn() (as not to yield the function) to make a small loop of raycasts, that stops either when it hits something or the maximum range is reached. You can simulate gravity on these multiple raycasts, and even check headshots for more damage;
  • FireAllClients the remoteevent, and bind a function on the local script to receive the direction the bullet travelled and the type of bullet and who shot. On this function, do the visual effects you want to add to the bullet, like particle emission, tweening the visual projectile, light emission.
  • You might want to bind another event for the server to fire when the player hits an enemy, as to show if it hit someone. You can also use RemoteFunction to InvokeServer instead of FireServer, so you can return the player who was hit back to the player. You will still have to use remotevent to FireAllClients the visual bullet you want to create.
2 Likes

Okay. In summary I want a client sided projectile which is a projectile on the client side. To make it have very fast response time instead of it being in a server script which has a delay.
Here’s a topic relating to something of what I’m trying to achieve.

So in summary it goes like:
Local Script(Fire) —> Script(Fires Client) —> Local Script(Shows on screen)
right? Also thank you for putting a lot of effort in your writing.