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

Today, i ported most of my 3DMG code into modules (still using fastcast for hooks cuz its great), and then i ran into this error:
image

that leads to:
image

and:

idk what the error means, but can you fix this pls?

Thanks ahead of time

EDIT: This is also the latest version too

Yep. This is fixed now. Sorry about that. Caught me at a good time too, I was just about to go to bed image

All I had to do was add a nil check. You can either upgrade the module or add this yourself to both fire methods:

for index = 1, #yieldingThreads do
	local thread = yieldingThreads[index]
	if thread ~= nil then
		coroutine.resume(thread, ...)
	end
end
1 Like

Thanks :grinning: I can now proceed with transfer

1 Like

I’m working on a few things with FastCast right now: porting my circa v11 code to v13 and I’m having a few issues.

My cosmetic bullet object isn’t moving at all. I’ve copied this piece of code into my system

function OnRayUpdated(cast, segmentOrigin, segmentDirection, length, segmentVelocity, cosmeticBulletObject)
	if cosmeticBulletObject == nil then return end
	local bulletLength = cosmeticBulletObject.Size.Z / 2
	local baseCFrame = CFrame.new(segmentOrigin, segmentOrigin + segmentDirection)
	cosmeticBulletObject.CFrame = baseCFrame * CFrame.new(0, 0, -(length - bulletLength))
end

and I’m connecting it with

Caster.LengthChanged:Connect(OnRayUpdated)

and yet it doesn’t move. No errors. I’m guessing it has to do with something else in my code, but I’m not sure what.

Anyways, on another topic, what does using FastCast for a single server look like? At the same time, I’m making all the weapons in my game controlled via a script in ServerScriptService instead of being separated in every tool (I’m trying to make a more modular system). I’m guessing it’s not a good idea to do FastCast.new() for every fire event, so what should I do (also being able to have the player that shot is important too)?

I’m not quite sure. The handler looks ok. Are you using :Fire() properly? Check the API pages to make sure. Here’s the Fire method on the docs.

Correct, as outlined on the API: FastCast - FastCast API – As for what to do? On your server handler, create a caster in the root of the script, and then with a RemoteEvent in ReplicatedStorage fired by all of the guns, use the parameter that comes with RemoteEvents by default when they go from client => server, which is the client that fired the event.

It’s basically like a standard gun script, but you just have all clients fire to the same server script. As for keeping track of who fired something? Consider the UserData property of ActiveCast which is a table that can store any data you want on each individual bullet.

I’m not too sure what could be going wrong with the :Fire call. I’ve copy+pasted the call itself from the example gun into my system and it still doesn’t move (also, yes, I’ve copy and pasted the parameters too). Along with that, the cosmetic bullet termination doesn’t work either even though it’s connected. I’m guessing it has something to do with the OnRayMove function causing the cosmetic bullet to never terminate because it’s not moving? I can send my code, if needed.

I have a system similar to what you mentioned there but I wasn’t using UserData oops. I’ve looked on the API docs for how to use the UserData table of an active cast and it’s a little unclear what it contains/what it can contain. Do you mind explaining it?

It’s an arbitrary table so it can store anything you want.

cast.UserData.MyCustomKey = 123
cast.UserData.SomethingElse = { 1, 2, 3, 4, 5 }
cast.Userdata.Nice = "Good"

I can make this more clear on the API.

2 Likes

I am in the planning phase for my weapon scripts and for the projectiles I am going to use this module however I cannot seem to see a ‘mockup cast’. By this I mean where it does not account for time/velocity of the bullet and it shoots all the rays at once and immediately goes to RayHit, it’d be specifically helpful in projectile arcing.

My planning phase was doing this on the server to validate bullets, and I was worried if I just made the velocity some huge number it could have performance impacts rather than there being an option to mockup the cast completely ignoring the procedural step. This would be really helpful to get insight on

Creating a mockup is a bad idea because it assumes that the world will not change for the duration of the cast.

What if I fire the mockup cast and it hits some part, but then I fire the actual timed cast and someone or something moves into the path of the mockup? Now the hit result is different.

For validation I was going to fire a ray from client and server perspective and check :distance, if there wasnt a mockup do u think itd still be a good idea to use this method for arcing projectiles because it’s only gonna validate the direction and not the eventual falloff but it shouldn’t be exploited?

It seems I have found a bug, the bullet likes to “slip” under parts for some reason.


Note: I am using the provided example gun, I have not modified anything.

How did you make something like this? As in the bouncing?

It already comes implemented with the example gun.

Oh cool I’m definitely gonna implement that :slight_smile:

Also try changing the hitbox type from default to box. That helped me a ton

Your github not working for me

2 Likes

The github link doesnt work anymore??

1 Like

I had just purchased my own domain – it’s fixed now. Sorry! I’m brand new to DNS stuff and messed up some stuff.

4 Likes

These recent updates are excellent! I love that you incorporated the reflecting right into the example gun. I have to say though, I didn’t realize that I could use the Pierce function for so much more than just going through specific walls. I’ve been toying with it a bit and it’s actually a super helpful function.

Regardless, being able to change the velocity, acceleration, and position of my casts on the fly, along with pausing/resuming them is great. I already have a couple ideas in mind for what I’m going to do with these. I believe the most helpful new addition I’ve started using is the UserData table. It’s really nice to be able to throw variables into this table rather than passing that variable through like 4 functions.

All of these changes are very welcome, although I do have a question. Is there some way that I can still pass in my own cloned CosmeticBullet rather than the module doing the cloning itself from the template it’s given? In FastCast Ver. 10.0.0, the user is required to clone the bullet themselves and pass it in, and while the new template functionality is much cleaner, passing in my own cosmetic bullet was crucial to incorporating FastCast with the PartCache module.

Basically, this was my code before:

-- Get a bullet from the PartCache
local bullet = BulletCache:GetPart()
bullet.CFrame = CFrame.new(FirePointObject.WorldPosition, FirePointObject.WorldPosition + direction)
bullet.Parent = CosmeticBulletsFolder
	
-- Fire the caster
Caster:FireWithBlacklist(FirePointObject.WorldPosition, direction * BULLET_MAXDIST, modifiedBulletSpeed, blacklist, bullet, true, BULLET_GRAVITY, CanRayPierce)

As you can see, rather than cloning my own CosmeticBullet, I get one from a PartCache, and then give the FastCast module that bullet. While I could probably get by without using the PartCache module, my game is most likely going to need it so that I can keep it as fast as possible. I’ve been looking through the documentation and also the FastCast module itself for somewhere I could edit the PartCache functionality in, although honestly I’d rather leave the FastCast module as it is so that I don’t have to put the edits in with every new version.

Perhaps doing this is still possible and I’m just missing it somehow, if it is then I wouldn’t mind a pointer where haha. Other than this though, I’m really loving the FastCast updates! It took me a bit to get around to incorporating it into my game, although I find that all this new functionality is already paying off! :happy3:

EDIT: One more thing, is there some reason we’re not allowed to Pierce water? In the previous version of my guns I had a BULLETS_IGNORE_WATER variable, although now I can’t seem to get it to work. It’s for deciding whether bullets should stop or not when they hit water. Editing the cast with cast.RayInfo.Parameters.IgnoreWater = false has an error specifically for that case for some reason. I could just disable the error() call, although I’m wondering why that might be a fatally bad idea :eyes:

3 Likes

To be honest, “pierce” is a bit misleading, but fitting “A function that runs on any hit and can decide to terminate the cast or keep it going after changing it in any way” into a simple name is a bit tough. That, and the main purpose is for piercing. Yeah, any changes on the fly where the bullet hits something and you want to keep it going are indeed possible. The pierce function is a lot more powerful than it seems on the surface, which is part of why I added that to the example - I wanted people to see just how far they could push it.

Right now, no, not in the function call itself. I did this change because the vast majority of use cases ended up just cloning some template so I decided to cut that out of user scripts. On top of this, the ideology of the behavior packet is that it should be a singleton, so editing in something dynamic (setting your own instance of a cosmetic bullet) doesn’t fit that ideology.

You can do it manually, however, via editing the RayInfo object (see https://etithespirit.xyz/FastCastAPIDocs/fastcast-objects/castrayinfo/)

local cast = Caster:Fire(...)
cast.RayInfo.CosmeticBulletObject = whatever_you_want_here

That instance will be passed into the functions like any other cosmetic object, so it will be fully compatible with all existing code - no complications.

If I recall, a comment there or the error message itself describes it. In the scope of raycasting, Terrain is a single part. If you pierce water, that cast will never hit terrain again until the pierce routine completes, which means that if you shoot a body of water, that bullet will keep going until it exits the terrain without registering hits. This is part of why Roblox’s raycasting offers a specific variable to ignore water, and is why you should use that as well.

3 Likes