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

Oh! Yeah. I’ll edit that thread. It was suggested that I create a dedicated thread due to the level of completion this module had. Thanks for reminding me.

44 Likes

This will work for anything - I used a gun as an example because it’s the most common thing that would need this module.

Any sort of projectile will work even if it’s not for a weapon. In your case, you’ll want to fire the caster with a bit of a slower velocity so that it travels more like an arrow would.

32 Likes

If this has latency compensation ala Mad Murderer’s (firing client draws projectile immediately, other clients begin drawing projectile when and where the projectile should be at that moment) that would be so cool

27 Likes

It certainly does include lag compensation!

In the event of any lag, heartbeat’s delay time will be over the expected 1/60th of a second. The length of each ray is calculated through a specific equation:

RayLength = NormalizedDirection * Velocity * DeltaTime * 2

For clarity just to anyone who may end up being unsure, NormalizedDirection is a unit vector storing the direction of the ray, Velocity is the value specified by the user when the :Fire() method is called, and DeltaTime is the amount of time that the latest heartbeat took. So if lag occurs, the ray’s length will be made longer to compensate without issues.

38 Likes

Something I have been struggling with for so long is ranged weapons, and now this appears! Glad someone asked the Bow and Arrow question as that would likely be my intended use. Will this be able to create curved trajectories, such that if a player shot an arrow straight up 90 degrees, it would eventually fall back down in the same/near location it left?

35 Likes

Curved trajectories are still on the to-do list.

I don’t think appending the feature would be too much work.

I’ve narrowed down my plans to a pretty direct idea. For the next version I’m going to be appending a Gravity property. I’ll formally document it when I release the change, but a general explanation is as follows:

The Gravity property will be part of an individual caster object. Its default value will be 0 meaning that the trajectory is not affected by gravity. Users can set this value to whatever they please. I’ve been considering whether or not to add a method that sets the Gravity variable to be equal to the Workspace’s Gravity Property. I think it would be more common practice to just run Caster.Gravity = workspace.Gravity when a user creates the object, though.

This change would require a few edits to the script that runs each ray, especially the LengthChanged event. Right now, that event gives the start of the entire ray and the distance to the current ray point from that start value as some of its arguments, which would not be correct in terms of rotating the projectile based on flight path. I’d have to change it to be per-segment. This ideally won’t cause too many issues with migrating over from the previous version when this releases.

Given that I see a lot of the usage relates to arrows, I’ve also considered appending a second value - a Vector3, specifically - so that you can simulate wind and other factors. This value would represent a force and be added on top of the gravity value so that you can have a specific spot for gravity and a specific spot for this extra force. This feature will also benefit things like long-range weapons (sniper rifles, for instance) as they are affected by wind to a very notable extent.

Edit to blow this question out of the way: This Vector3 value will be in world space. That way, it’s easier to have a global wind value distributed to every caster. I might end up adding a way to make it behave in object space, but I don’t want to over-complicate things. Of course, as mentioned, this is all still up in the air.

When I release version 3, I’ll include documentation on these just as I did every other property.

37 Likes

I was asking about latency though, the time it takes for packets to travel, not framerate.

26 Likes

Oh. In that case, no, I have no compensation for this. I could add that later down the line probably by letting the server-side send a tick() value through some remote call (of course, clients may have different values for their epoch, so for the sake of simplicity I’ll ignore that here), and then allow that time value to be passed into the caster as a sort of thing to say “Hey, bump it ahead this much”. That’s just an idea.

For now and in the next version, I don’t plan on adding this feature, but that’s still up in the air. I’ll definitely consider it though.

22 Likes

we need more people like you in the world :slight_smile:

57 Likes

If you click on terrain then the bullet fires in the opposite direction, please fix this, I need it ASAP.

10 Likes

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.

13 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

59 Likes

Excellent for a bow and arrow

28 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?

16 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
24 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?

18 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?

9 Likes

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

14 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.

14 Likes

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

10 Likes