I would've uploaded the marketplace model but Roblox kept on flagging it for some reason
This Projectile system was created by me @Bartokens as a challenge for myself. I wanted to recreate the projectile systems seen in games like Marvel Rivals and Overwatch, where you have full control over hit detection and how they move. The main reason why I decided to make this was to see if I could, since I couldn’t find any existing open-source projectile systems on Roblox. It’s free to use, and currently functional, however there are a few bugs with the current version, so it’s not entirely perfect.
What is Projectile+?
Projectile+ or ProjectilePlus is an all-in-one projectile system, and by that I mean it includes everything you would want in a projectile system, and if it doesn't then please request new features. This includes:
* Projectiles with customizeable hit detection, sizes, speeds, and paths.
* Projectile bouncing
* Projectiles with gravity
* Projectiles with homing
* Projectile "Catchers" which can be used to intercept projectiles.
* Hitscan
* Projectile time control
* Client Visuals
As far as performance goes, you can expect FPS drops at a few hundred projectiles, but this is also dependent on how your handling your VFX. The projectiles use custom physics rather than built-in Roblox body movers or physics. It uses basic SUVAT equations during runtime, and I got the idea for that from this post
Features
Basic Projectiles
Projectiles can be made with a simple:
|---|---|
||local StartPosition |
||local Direction |
||local Owner = Character|
||local Key = Laser|
||local Radius = 2|
||local LifeTime|
||local Speed = 100|
|||
||local Projectile = ProjectileSystem.CreateProjectile(Owner,Key,Radius,Direction,StartPosition,LifeTime,Speed)|
Doing this will instantly create a projectile. The parameters should be self explanatory, but you can read more about them in the documentation.
Projectiles also have properties that can be changed during runtime, including speed and radius. You can read about all of them in the documentation.
Bouncing Projectiles
Projectiles have a special property called ReflectEnabled. This can be toggled on and off whenever you like, and makes it so that the projectile bounces off everything it runs into. This includes players, but that behavior can be toggled.
Projectiles with gravity
Projectiles by default don’t have gravity, but they have a special property called GravityEnabled, as well as a property called GravityForce. These can both be changed during runtime, and customize how gravity works for individual projectiles.
Projectiles with homing
Projectiles have a special method called Homing, which makes the projectile actively follow a specified BasePart. The strength of the homing is a separate parameter called HomingStrength. Additionally you can change the HomingTargetPosition property during runtime, which makes the projectile home in on a specific Vector3.
Projectile Catchers
There is a special class of objects within the system called “Projectile Catchers”. These are imaginary boxes that do not take up physical space in the workspace, but rather use @azavier123 's zone module to detect when projectiles run into them. This can be used for things like barriers that destroy projectiles, or abilities that can reflect projectiles. Catchers can be welded to BaseParts as well, allowing them to move with whatever they’re welded to.
Overwatch Style Barriers
Ultrakill style coin reflect
Inspired by Magneto’s ultimate ability from Marvel Rivals:
Hitscan
Now this is probably the most underdeveloped part of the module, but for good reason. Hitscan is not something you need this module to do, as it can be done very easily by just using raycasts. If you aren’t aware, Hitscan type hit detection and Projectile type hit detection are two very different methods of creating bullets in shooter games. Hitscans hit instantly, and projectiles take time to actually hit their target. The only difference between this and raycasting normally is that this Projectile Catchers can intercept Hitscans.
Time Control
My favorite feature of this module is the ability to control the time scale of projectiles. Each projectile has a special property called TimeScale that is 1 by default. This property can be changed during runtime. Increasing it makes it go faster, and lowering it makes it go slower. You can actually go in the negatives, and reverse the time of the projectile.
Time Stop:
Projectiles that start at normal time but slowly reverse:
Client Visuals
By default the projectiles are invisible. In order to see them, you’ll have to require the Client module under the main module. You would require this in a LocalScript, ideally under StarterPlayerScripts. Then, you can detect the Client.ProjectileAdded event, and then use the WeldPart method, which makes any BaseParts you pass through it follow the trajectory of the projectile. You can even weld multiple BaseParts to one projectile at once.
Full Documentation (If you don't want to download the module)
`–Version 1 Documentation
–Projectile Plus developed by Bartokens. Zone module by azavier123
–Projectile Plus is an all-in one projectile system that handles client-server interactions and uses it’s own physics calculations.
–Projectiles are not parts, but rather tables that are constantly updated on the server.
–You can create your own parts on the client for visuals, and handle all events on the client such as projectile hit.
–You can also differentiate between hitting players and hitting the map.
–Includes Homing, Gravity, and Bouncing features.
–Setup Guide:
–1. Place the ProjectilePlus module in ReplicatedStorage.
–2. In any server script, require the module (the parent of this script) to activate it.
–3. In any local script, require the Client module to activate the client.
–4. You can now use any of the Server or Client methods without error.
–Server Methods:
–ProjectilePlus.CreateProjectile(
– Owner : Model, --The owner of the projectile. You would set this to the character of the player.
– Key : string, --A unique identifier to give the projectile which can be referenced on the client.
– Radius : number, --The radius of the Projectile.
– Velocity : Vector3, --The direction the projectile will move towards.
– StartPosition : Vector3, --The position the projectile starts at.
– Lifetime : number, --How long the projectile will last in seconds before being destroyed.
– Speed : number, --The speed of the projectile
– raycastParams : RaycastParams --Optional RaycastParams
–)
–Creates a projectile on the server
–Projectile Properties:
--Owner --The owner of the projectile. Ignored on hit detection.
--Speed --How fast the projectile moves.
--TimeScale --1 by default. Can be used to speed up or slow down the projectile.
--Radius --The radius of the projectile
--ReflectEnabled --Determines whether or not the projectile bounces when hitting map surfaces.
--Velocity --The direction the projectile moves in
--Position --The position of the projectile. Updates every frame.
--CFrame --Read only property. The CFrame of the projectile. Updates every frame.
--Key --The unique ID of the projectile
--Lifetime --How long the projectile will exist in seconds.
--LastTime --The last time the projectile was updated on the server.
--StartTime --The time the projectile was created.
--Debounce --The debounce time of the projectile. Used to prevent hit events from firing multiple times.
--HitList --A table of all hit players by the projectile. Resets for each individual player on debounce.
--DestroyOnHit --Determines whether or not the projectile is destroyed when hitting a player.
--DestroyOnMapHit --Determines whether or not the projectile is destroyed when hitting the map.
--CheckForPeople --Determines whether or not the projectile actively checks for players. Turn this off if you don't need player detection
--CheckForMap --Determines whether or not the projectile actively checks for the map. Turn this off if you don't need map detection
--UseRaycastingForPeople --When true the projectile will use raycasting instead of spherecasting for player detection. Ideal for smaller projectiles.
--UseRaycastingForMap --When true the projectile will use raycasting instead of spherecasting for map detection. Ideal for larger projectiles.
--raycastParams --The raycastParams used for hit detection.
--OParams --The OParams used for spatial queries.
--OnHitSomeone --A function that is fired when the projectile hits a player.
--OnHitMap --A function that is fired when the projectile hits the map.
--ID --The unique ID of the projectile created by HTTPService:GenerateGUID()
--HomingTarget --The current homing target of the projectile. Only works when projectile:Homing() is called.
--HomingTargetPosition --The current homing target position. Only works when projectile:Homing() is called.
--HomingStrength --How aggresively the projectile will follow the homing target.
--GravityEnabled --Toggles gravity for the projectile.
--GravityForce --The strength of gravity for the projectile. 1 by default.
–Projectile Methods:
--projectile:Destroy() --Destroys the projectile.
--projectile:Homing(Target, Strength) --Makes the projectile begin homing on a specified target part.
--projectile:StopHoming() --Makes the projectile stop homing.
–Projectile Events:
--projectile.Destroying() --Fired when the projectile is destroyed.
--projectile.HitSomeone(Hit,HitPosition) --Fired when the projectile hits a player.
--projectile.HitMap(Hit,HitPosition) --Fired when the projectile hits the map.
–ProjectilePlus.CreateCatcher(
--Size: Vector3, --The size of the Catcher
--Cframe: CFrame, --The CFrame of the Catcher
--Shape: Enum.PartType --The Shape of the Catcher.
–)
–Creates a projectile catcher which detects when projectiles collide with it.
–Catcher Properties:
--OnCaught --An optional function which is fired on projectile caught.
--Debounce --How many seconds before the Catcher can catch the same projectile again.
--CaughtList --The list of projectiles caught by the Catcher. Individual projectiles removed on debounce.
--Position --The position of the Catcher.
--CFrame --The CFrame of the Catcher.
--Size --The size of the Catcher.
--Shape --The shape of the Catcher.
–Catcher Methods:
--catcher:Destroy() --Destroys the Catcher.
--catcher:WeldTo(WeldTarget, Offset) --Welds the Catcher to a part with an optional CFrame offset. The part can also be any table with a CFrame property, meaning Catchers can be welded to projectiles.
--catcher:UnWeld() --Unwelds the Catcher.
–Catcher Events:
--catcher.Caught(Projectile) --Fired when a projectile is caught.
--catcher.Destroyed() --Fired when the Catcher is destroyed.
–ProjectilePlus:HitScan(
--Origin: Vector3, --The origin point of the Hitscan raycast.
--EndPoint: Vector3, --The end point of the Hitscan raycast.
--MaxRange: number, --The max range of the Hitscan raycast.
--raycastParams: RaycastParams --Optional rayCastParams.
–)
–A built in HitScan function. It is really just a simple raycast, but it can be intercepted by Projectile Catchers.
–Returns a model, a table, or a part depending on if it hit a player, a catcher, or the map respectively.
–Currently does not work with wedge or cylinder catchers.
–ProjectilePlus:Initialize()
–Activates the server side of the module. This must be called before any other functions, though it is automatically called on first require.
–ProjectilePlus:GetProjectiles()
–Returns all existing projectiles.
–ProjectileSystem:ClearProjectiles()
–Destroys all existing projectiles.
–ProjectileSystem:PlayerCleanup(Player:Player)
–Destroys all existing projectiles belonging to a specific player. Automatically called on player leaving if AutoPlayerCleanup is set to true.
–Client Events:
–Client.ProjectileAdded(Projectile)
–An event that fires when projectiles are created on the server and then passed to the client.
–Client.ProjectileDestroying(Projectile)
–An event that fires when projectiles are destroyed on the server and the client.
–Special Client Projectile Methods:
–Projectile:WeldPart(part: BasePart, offset: CFrame?)
–Welds a BasePart to the projectile by updating it’s CFrame every frame with an optional offset.
–Projectile:ClearWelds()
–Clears all active welds
`
Current Bugs
Bugs
Now Ideally I would’ve liked to release this system bug free, but I’m on a tight schedule so I don’t have the time to figure this out at the moment. Currently there is one somewhat noticeable effect that has to do with how the client handles projectiles. Currently, the client does it’s own physics simulations. This removes the need for remote events, and allows the client projectiles to follow the exact same trajectories as the server projectiles. However, there are some cases where the client projectiles follow offset paths compared to the server projectiles. This becomes more and more noticeable the more the server lags. This is most noticeable with projectiles that curve:
As you can see in the video, the server projectiles (colored red) go exactly to where the mouse is, but the client projectiles (colored blue) are slightly offset as the projectiles curve. Honestly, I’ve been experimenting with solutions but nothing has worked as I’ve wanted it too. If you have any ideas than I’m open to suggestions.
And that’s about it. Please let me know how you like the system. I’ll be updating it occasionally if I find the time.