Making a combat game with ranged weapons? FastCast may be the module for you!

Are you sure you’re using the script correctly? This sounds like it may be an issue in your hit detection code, as the Caster:Fire(...) method takes in a Vector3 origin value, a Vector3 direction value (multiplied by the maximum distance for the current ray), and the speed of the bullet.

You will want to validate your code that determines the location or direction of the hit. Feel free to messsage me if you’d like more directed help.

12 Likes

Hey everybody! I’ve just released Version 4 of the module. Please make sure to message me if you see anything wrong.

This version adds…

Physics!

(I’m mentioning @SmoothBlockModel and @CheetahSp33d since you two had asked about it.)

I’ve also created an update log in the bulletin board. Please read it, as I’ve moved the API docs over to my GitHub as well as some other important information: FastCast Changelog Thread

58 Likes

Excellent for a bow and arrow

27 Likes

I’m not sure I completely understand. My game has a BUNCH of projectiles (absolutely zero hitscan weapons) ranging in size and speed. From what I read, this seems to be very useful to me, but I don’t want to go through the effort of getting and reading your model (not on my computer). What exactly does this do?

15 Likes

In basic, this module supplies an API that allows you to use raycasting that simulates physics for bullets. I think the easiest example would be to give you a rather brief script, since my original post explains it already. In the case that this kind of explanation isn’t what you wanted, just let me know and I’ll fix it up.

If you look at reply #15 I have a picture of a ray firing off with physics. Each one of those black cones is a segment. This module basically splits up the path of a bullet into tiny segments whose length is based on the speed of the projectile and how long the latest Heartbeat took (which allows it to accommodate for lag). Each of these segments is an individual hitscan test over a short range. They are fired off sequentially based on velocity and time. One of the immediate concerns I may see is that extremely fast bullets have long rays, but the frame-rate Roblox is limited at will make it not perceivable by players, so it works pretty well even with extremely fast bullets.

Let’s say you have a sniper rifle, something with a very high-speed projectile. You’d start off with a script a little something like what follows to handle the rifle’s function.

The script is lengthy (not overkill) so I’m going to wrap it into a details section. I’ve written functions that explain what each part is doing via comments so hopefully it should clarify a lot of stuff.

I forgot to append my API to the original post, as I did do documentation for this system. Sorry about that. You can have a look at it here: https://github.com/XanTheDragon/FastCastAPIDocs/wiki

Click to view
local FastCastModule = require(wherever the module is)
local SniperCaster = FastCastModule.new()
SniperCaster.Gravity = 5 --Add a slight bullet drop at 5 studs/sec^2 (game gravity is 196.2 by default)
SniperCaster.ExtraForce = Vector3.new() --You can set this to apply wind so that you can offset the bullet

function RayChanged(Origin, SegmentStart, Direction, Length)
    --As mentioned in the API, this function will fire every heartbeat, or when a new ray segment is calculated.
    --Origin is the start of the ray, where the muzzle is. SegmentStart is the start of the current segment.
    --Likewise, direction and length are the direction + length of the current segment.
    --Each one of the black cones in the image I referred you to is a segment.
    
    --In this function, you might update a tracer part by setting its CFrame or update anything else that may appear visually based on the bullet.
    --You can also use this function for something like playing a bullet near-miss sound!
end

function OnHit(Part, Position, Normal, Material)
    --This function will run when the ray hits something. The parameters returned are self-explanatory, but for the sake of good practice I'll explain anyway
    --Part is the part that got hit (will be nil if the ray reaches the end of its distance.)
    --Position is the position of either the hit or the point of the ray when it ends.
    --Normal is the surface normal of the part hit (this will be a zero-vector if Part is nil)
    --Material is the material of the part hit (this will be Enum.Material.Air if Part is nil)
    
    --Here, you might damage the player that got hit or do anything else involving when the bullet hits something.
end

--Now that you've set up the way the caster should work, you can connect its events to the two functions above.
SniperCaster.LengthChanged:Connect(RayChanged)
SniperCaster.RayHit:Connect(OnHit)

--After the setup of the caster is done as shown above, you can use this to fire your gun:
local BulletSpeed = 1600
local MaximumDistance = 1000

function FireWeapon(MuzzleEndPosition, FireDirection)
    --Some arbitrary function that will fire the gun. This might be paired to something in a Tool's Activated event.
    SniperCaster:Fire(MuzzleEndPosition, FireDirection * MaximumDistance, BulletSpeed)
end
23 Likes

How does the segmented raycasting over time combat the edge case of being able to tunnel into an object that is moving towards the projectile?

17 Likes

All my projectiles are relatively slow and easy enough to dodge when you see it coming, I’m assuming this is not for me?

8 Likes

Nope. You can make your projectiles have any speed you want.

13 Likes

That is quite a dilemma indeed.

The system doesn’t have a method for handling that namely since I had absolutely no idea that it was possible for that to occur.

I’ll have to come up with a way to fix that.

13 Likes

But where does raycasting come into play if the projectiles aren’t just for show?

9 Likes

If you want the projectiles to not only be for show (as in you want to use them for hit detection too), then this module is useless to you.

This module was designed for the express purpose of getting rid of part-based projectiles. Simply put, firing the raycaster should replace the creation of a velocity-based bullet that has touch detection. Likewise, the RayHit event of the raycaster should replace listening to the Touched event on the bullet part.

The reason I had suggested a cosmetic bullet is so that you can still retain the illusion of a physical part being used. You can create an anchored part that looks like your bullet, and CFrame it based on the LengthChanged event’s parameters so that you can put the bullet where the ray is currently located.

If we’re still having trouble understanding each other, I encourage you to message me - that way I can provide a bit more direct clarity on usage, and leave the public forum here to discussion and insight regarding the module’s features.

29 Likes

Yes!! This is EXACTLY what I’ve been needing, thank you so much for sharing this! :heart:

18 Likes

It would be really nice if you could make a Tool that uses your Script and upload it as a model or just have it in an Uncopylocked Place.

I tried reading stuff that you provided but I can’t get my head around it quite yet.

I learn better when I see Example code which is why I’m asking for this.

I know you have an Example Script but I can’t tell which is which, like do you need all of that code to make it work?

I just want a Tool that uses your Module to Fire Bullets as an Example.

Thank you! @Xan_TheDragon

16 Likes

Good idea. I’ll get that done for you. I’ll edit the post when I make it. :+1:

11 Likes

Sorry for being so late.

While I was doing your request, I ran into quite a dilemma: There was no easy way to track cosmetic bullets and their corresponding rays! So as a result of that, I took some time to release Version 5.

To @RuizuKun_Dev - The original post up top has been edited to include the gun you requested, it’s at the very bottom. I do have to thank you for asking about that, since I wouldn’t have realized that problem on my own. +1 for that.

15 Likes

Thanks for releasing this, I’ve been implementing this into my own game, and have been absolutely loving it!

One thing I was wondering about, is if it was possible to get the end position of a cast (before it has even finished), this would assume that nothing has moved into the trajectory of the cast before it has finished, but I was going to use something like this for some cosmetic additions to my weapons, to create a second cast.

7 Likes

How does this perform in comparison to a part with BodyVelocity?

6 Likes

Tests have shown fairly outstanding results.

To put it as simply as possible: The method that this module uses to update the position of the part yields strong benefits, as it does not rely on physics and the woes that can result from the physics system. Since it uses raycasting, hit detection is extremely consistent. This consistency can be lacking on physics-based bullets, especially if network ownership of the part’s physics is not specifically set to a certain client or the server. Most of the time, these kinds of bullets will skip their target or lag just before they hit someone during the transition of network ownership. Better yet, the raycasting is fast and based on the delta-time (amount of time it took to perform a step) so that the bullet won’t be stopped/moved in the event of lag.

Additionally, large amounts of these bullets that use physical simulation can cause lag on the place as there’s a lot of things to update at once. This raycaster is a lot less intensive.

9 Likes

Is it possible to increase the hit detection radius for big projectiles? I’ve tried your module and it only detects when the very middle of the projectile hits something, but in my game there are some fairly big projectiles.

3 Likes

The ray’s current point is designed to simulate the end point of the projectile.

Based on what you said, I’m going to assume you are CFraming a projectile to the position of the ray. If this is the case, you simply need to modify your CFrame to put the bullet behind that point. This is fairly simple, but for the sake of giving proof of concept I’ll supply example code anyway.

You should do something along the lines of this. Assume the bullet is a standard block part. (If it’s a mesh that isn’t using a MeshPart, or more specifically the visual projectile does not reflect the size of the part instance itself, you will need to find this length value for how long the bullet is).

Bullet.CFrame = CFrame.new(RayPoint, RayPoint + RayDirection) * CFrame.new(0, 0, Bullet.Size.Z/2)

This will cause the front of the bullet to be placed at the location of the ray’s current point, thus causing the front of the bullet to be at the point of hit detection. Hopefully this helped you out enough. Just ask if you need anything else.

8 Likes