Best way to make a projectile

Hello, recently I’ve wanted to make a basic projectile, I want the projectile to behave almost exactly like the official ROBLOX rocket launcher. And I’ve had the question of “What’s the best way to do it?”. I have seen a couple methods I’ve seen but I want community feedback.

PLEASE NOTE, I am not just begging for code, I actually want to understand but, I don’t know where to start. Please provide a slightly in-depth explanation as I’m really bad at understanding things.

I’ll show an example of a setup Here:

image
Basically, I want a projectile to come out of the attachment.

Here is the Client Script:

local Mouse = game.Players.LocalPlayer:GetMouse()

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

Mouse.Button1Down:Connect(function()
	local MousePos = Mouse.Hit
	RE:FireServer(MousePos)
	
end)

BTW, I know Mouse() is deprecated but it’s easy to use, understand, and it’s cleaner. But if User Input Service is more performant or has some functionality needed, please let me know.

Here is the incomplete Server Script:

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

local Hole = script.Parent.Parent.Handle.Attachment --Where the projectile should come out of

RE.OnServerEvent:Connect(function(MousePos)
	local Projectile = Instance.new("Part")
	Projectile.CanCollide = false
	--STUFF GOES HERE
end)

Thanks for reading!

2 Likes

First of all, the onServerEvent also receives the player as parameter (RemoteEvent | Roblox Creator Documentation).

You can get the player’s character from there. Afterwards, you need to check whether the character has the tool equipped (use find first child and check if it’s nil). If the tool is equipped then set the projectile cframe to the attachment cframe.

Then you can give the projectile a velocity. A simple example is found here BasePart | Roblox Creator Documentation.

Good luck!

Looks like I forgot about a lot of things. I forgot that the first arg in Remote Events is the player. Also, I could have just used Tool.Activated instead of checking if the tool is out. Sorry for the inconvenience! I will try your methods and report back. Thanks!

1 Like

Hey look it’s Doritos mate

A couple more things I should add onto what he said:

  • I believe you could set the NetworkOwnership of the Part to nil so that the owner will be on the server, apparently “preventing invisible hops” or something (Network Ownership | Roblox Creator Documentation)

  • I’d recommend using BodyVelocity, since the Velocity property is deprecated and is advised to not be used

  • The Client Script you sent, will actually return back a CFrame value I believe, if you want to get the Position instead you can do Mouse.Hit.Position for Vector3 values

That’s all I have to say :thinking:

2 Likes

Thanks! I’ve heard about Network Ownership before, thanks for the link. Also, I just figured out that it returned a CFrame and I already did Hit.Position, but thanks anyways!

2 Likes

Okay so I tried your method but, I think I did something wrong. For some reason the projectile fires from the origin of the map (0,0,0) for some reason. Here is the script:

RE.OnServerEvent:Connect(function(Player, MousePos)

local Projectile = Instance.new("Part")

Projectile.CanCollide = false

Projectile.CFrame = Hole.CFrame

local BV = Instance.new("BodyVelocity", Projectile)

BV.Velocity = MousePos - Hole.CFrame.Position

Projectile.Parent = workspace

end)

Oh I see

Your Hole variable is referring to the Attachment object, which is actually gonna be relative to the world origin since it’s supposed to be an Offset which is why it’s resulting as the CFrame being moved there

Try this:

local Handle = script.Parent.Parent.Handle

RE.OnServerEvent:Connect(function(Player, MousePos)

local Projectile = Instance.new("Part")

Projectile.CanCollide = false

Projectile.CFrame = Handle.CFrame

local BV = Instance.new("BodyVelocity", Projectile)

BV.Velocity = MousePos - Hole.CFrame.Position

Projectile.Parent = workspace

end)
1 Like

Okay it works now. I have two more questions. Is their a way to use attachments as a CFrame? Or should I just use an invis part instead? Also, the speed of the projectile changes depending on how far away the mouse position is how would I make it so the speed is constant?

I recommend this tutorial

It’s a recreate of an old roblox tutorial which allowed you to make a gun like the classic guns roblox has

Sorry, but this is what I’m looking for. I was looking for a projectile like the classic ROBLOX rocket launcher. That is raycasting which reaches its destination immediately.

2 Likes

Apparently I just realized these (Inside the properties of the Attachment):

I believe you could set the BodyVelocity’s MaxForce property to Vector3.new(math.huge, math.huge, math.huge) for it to maintain constant speed

Okay, so I modified some things and this is my result. The changes made make the part face the way the mouse is pointing and it stays at a constant speed with tampering with it. The only problem is it kind of lags for a second when it is created. Do you think this could be solved with Network Ownership? Also, if you see any other problems with the code tell me. Here it is:

RE.OnServerEvent:Connect(function(Player, MousePos)

local Projectile = Instance.new("Part")

Projectile.Size = Vector3.new(1, 1, 3)

Projectile.CanCollide = false

Projectile.Anchored = false

Projectile.CFrame = CFrame.new(Hole.Position, MousePos)

local BV = Instance.new("BodyVelocity", Projectile)

BV.Velocity = Projectile.CFrame.LookVector * 100

Projectile.Parent = workspace

end)

I believe so, although the MaxForce property still isn’t assigned

For some reason it still has a constant speed without setting it. I’ll try it out though to see if something changes.

Tried it got this error image

wait nvm I forgot Vector3.new()

Okay so I added network ownership and MaxForce. My conclusion is this: Network Ownership did seem to do something but their still is a delay when the part is created. To make sure I did everything right, I took the official ROBLOX rocket launcher from the toolbox and it had the same delay issue. It’s probably to do with calculating the Velocity or maybe running that velocity after being parented to the workspace.

When I added MaxForce it didn’t show any noticeable difference which I find kind of weird.

Here is the final Server Script:

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

local Hole = script.Parent.Parent.Handle

RE.OnServerEvent:Connect(function(Player, MousePos)

local Projectile = Instance.new("Part")

Projectile.Size = Vector3.new(1, 1, 3)

Projectile.CanCollide = false

Projectile.Anchored = false

Projectile.CFrame = CFrame.new(Hole.Position, MousePos)

local BV = Instance.new("BodyVelocity", Projectile)

BV.MaxForce = Vector3.new(math.huge, math.huge, math.huge) -- I can't tell if this makes a difference!

BV.Velocity = Projectile.CFrame.LookVector * 100

Projectile.Parent = workspace

Projectile:SetNetworkOwner(nil)

end)

I think that’s the best you’ll get for handling the part sadly, ROBLOX isn’t exactly 100% perfect on instantly detecting when a part is gonna move due to physics

The only other thing I could think of is setting the NetworkOwner when you first define your Projectile variable

I tried that but you can only set network ownership if a part is in the workspace.