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

If you want a bit of a status update for why this is so difficult, here’s the problems I have to solve:

  • How do I decide to pierce or not? (This is easy, just do a callback!)
  • How do I handle physics? Say we do hit a part and we want to pierce…
    • We need to add that part to an ignore list (which can get nasty really quick if the user is using stuff like a whitelist).
    • We can’t just skip ahead by the lost distance (e.g. say the cast would have gone 5 studs, we went 1, so just skip by 4)
      • We need to also find out how much time that cast would have taken if it were only supposed to go the given distance. This is inherently inaccurate since we can’t accommodate for potential lag, so for casts that simulate physics, we risk an effect similar to what I will call “bullet refraction” if we try to calculate trajectory from this information.
      • The only way to do this without issue is to keep the behavior consistent – Act like it’s one giant segment of time, and don’t try to divide it up. This means repeating the same cast over and over until we can reach the full distance or reach a conclusion (e.g. function says “okay, we hit this part now”). This is going to be incredibly difficult to emulate. The cost of this is that users can’t trace a bullet going through something like a pseudo-ballistic gel with a curved path, and I have a feeling that this goal is going to come up.

It’s a bit of a mess, but I’m working on it! :stuck_out_tongue:

1 Like

Alright everyone! Latest version is out!

I present to you: FastCast v 9.0.0 - The Piercing Update. This release is bound to have some bugs so please message me or reply here if you find anything wrong. Your CanRayPierce method must return before the next call to Heartbeat or RenderStepped (depending on the side it’s running on). If it doesn’t, it will throw an error.

It is now possible to specify a callback that enables bullet piercing. Here’s the example that was added to the example gun:

function CanRayPierce(hitPart, hitPoint, normal, material)
	-- This function shows off the piercing feature. Pass this function as the last argument (after bulletAcceleration) and it will run this every time the ray runs into an object.
	if material == Enum.Material.Plastic or material == Enum.Material.Ice or material == Enum.Material.Glass or material == Enum.Material.SmoothPlastic then
		-- Hit glass, plastic, or ice...
		if hitPart.Transparency >= 0.5 then
			-- And it's >= half transparent...
			return true -- Yes! We can pierce.
		end
	end
	return false -- No, we can't pierce.
end
11 Likes

Dose it matter a great deal if I call this module from the server or client?
What are the differences if done with one over the other?

It’s dependent on replication, and by extension, is like many other client/server setups where…

  • If you call on the server…

    • You get the benefits of
      • Only needing to run the code once across the entire game
      • Automatically replicating data to clients
    • You get the drawbacks of
      • Seeing bullet jittering again from ping/latency
      • Inconsistent hit registry when compared to the visuals of the client who fired the bullet
  • If you call on the client…

    • You get the benefits of
      • Perfect bullet simulation for every client individually
      • (If you do hit detection on the client) flawless hit registry, and, since this is not using a physical part but is instead using lua data, it is presumably very difficult to exploit the location of the bullet, making firing and detecting hits from the client a potentially safe option.
    • You get the drawbacks of
      • Needing to manually replicate casts to each client individually which requires a different scripting setup, one that isn’t too difficult if you are a more knowledgeable individual.
      • (If you do hit detection on the client) the potential (again, albeit very rare) for exploits.

Personally I have bias to doing everything on the client since FastCast’s underlying systems would require knowledge of Roblox’s encrypted lua VM to exploit adequately. This makes it a pretty good option to simply handle rendering and hit detection alike on the client.

8 Likes

Got it, Thanks.

Another thing I’m wondering: Dose /Will it support a ‘Universal Black list?’
(A blacklist things can be added to/removed from in real time, that will always be remembered by the module and can be used by all clients)

I kinda need this for my bullet detection to avoid hitting triggers and such.

Example: there’s a invisible non-colliding part (Not in the ‘Universal Blacklist’). If a bullet hits this part, it’s checked against some parameters
(Somthing like: if transparency ~=1 and CanCollide then…)

Once it fails the check, it’s added the ‘Universal Blacklist’ and the bullet continues as if it hadn’t hit anything. (The ray would then ignore it form then on so future bullets wouldn’t ever hit it again)

If this isn’t currently possible, would you consider looking into it for a future update?

It’s possible but you’d have to implement it yourself by hacking together something with the piercing system that I just added + your own blacklist.

Do you think you might add somthing like this in the future?

If not, I’ll figure somthing out, but I’d rather not edit the module directly so I can update it easier.

I shall now grant this the dog stamp and use it in every single FPS game i will make. the module does everything it needs to do perfectly, but some native support for auto replication (firing on the server has the bullet lagging behind a bit) to other clients would be cool.

3 Likes

I believe I’ve found a bug: I’m trying to use this with a shotgun I’ve made, but cannot get it to fire more then one bullet.
Is there somthing special I need to do to get it to work?

(Apologies for the bad formatting below, I don’t know how to post a code block)

for Shot =1,6 do
Projectile:FireWithBlacklist(
tool.Value.Fire_Point.Position, --Origin
direction *100, --Direction, *MAX_DIS
modifiedBulletSpeed, --Speed
{workspace.CurrentCamera}, --Ignore this
Tracer, --Tracer Part
false, --IgnoreWater?
Vector3.new(0,-15,0) --Gravity
)
end

I simply changed the script in my shotgun and instead of calling the Fire() function once I am calling it 5 times.

Also I changed the spread values from 0 - 2

This way I get a nice shotgun :))

Hmm, that still didn’t work for me…

I guess it might be somthing in my firing system?
Dose it work for you if you put your fire function in a ‘for’ loop like I did, instead of calling it multiple times manually?

Didnt try it.
here is my changed MouseEvent in the script

MouseEvent.OnServerEvent:Connect(function (clientThatFired, mouseDirection)
	if not CanFire then
		return
	end
	CanFire = false
	Fire(mouseDirection)
	Fire(mouseDirection)
	Fire(mouseDirection)
	Fire(mouseDirection)
	Fire(mouseDirection)
	wait(FIRE_DELAY)
	CanFire = true

end)

Well, I’m still not sure why mine isn’t working.
The biggest difference I can see is that I’m firing my FastCast function fully on the Client, not Server. (Assuming your ‘Fire’ function is just creating a FastCast)

Jeah, don’t fire from the client, it won’t work then.

Why not, that’s what I’ve always done?
All the other weapons work fine (pistol, smg), It just won’t fire more then one bullet at a time for some reason.

Hey! I’m making a game that will feature quite a few ability-based projectiles, and I’m working to use FastCast for that purpose. My current plan for integrating FastCast is to set up a caster object for each individual ability and having every entity (NPC, player, etc.) that uses that ability use that specific caster object. Is this the proper way to go about it? Or should I be creating entity-exclusive casters instead, such that every player/NPC/whatever has their own ability casters?

@Paintertable Using the system itself from the clientside causes no problems for it, it’s designed to work on both (in fact, you can see evidence of this on the if statement located at line 140 and ending at line 144. I don’t know if this is what you meant to say or not, but I’ll bring it up just in case.

if RunService:IsClient() then
	targetEvent = RunService.RenderStepped
else
	targetEvent = RunService.Heartbeat
end

@ChefJustice Yep! This is one way to go about it. Do be careful when tracking which NPC/Player has used the ability! The same LengthChanged and RayHit functions will fire for everyone if you implement it this way. I recommend instantiating a caster every time the ability is referenced so that each NPC/Player has their own, unless you are comfortable with handling that event call differentiation on your own. There are pros and cons to both, but otherwise there will be no negative impact in terms of performance.

2 Likes

What would be the benefit on doing it on the client? Would the projectiles be more smoother?
Currently the projectiles don’t fire from the bulletpoint directly and spawn (or are visible) some studs later. (ofc they spawn at the bulletpoint but they aren’t visible instantly which makes it looks weird sometimes.)

This is genuinely a lifesaving module, thank you. Any future plans for projectile ricochet?

1 Like

you can make the bullets ricochet using the module. just make it so when it hits something it fires the same bullet in a different direction. if you don’t know what direction to make the bullets go, this thread might help

2 Likes