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

How do we use the CanPierceFunction??

Does this module fix the client-server delay for projectiles

Fast cast is too powerful. Made a minigun:

https://we.tl/t-C6WThdzfbj

See CanPierceFunction in the docs for more information on this, including an example.

No, this does not perform any special networking compensation. It is strictly a means of firing projectiles.

2 Likes

I honestly can’t figure out why, maybe I’m really dumb and I overlooked something obvious, but the cosmetic bullets aren’t moving. When I fire my gun the VisualizeCasts shows the projectile moving, but the bullet spawns in front of the gun and stays there. When I unanchor the bullet part it just falls through the ground.

Edit: nvm I figured it out with a yt tutorial

I’m having an issue with FastCast. It goes on an infinite error loop and is causing horrible lag:
10:58:26.972 ReplicatedStorage.FastCastRedux.ActiveCast:122: attempt to perform arithmetic (mul) on table and number - Client - ActiveCast:122

I’m also getting another error before the loop starts:
11:57:23.933 WorldRoot is not a valid member of Vector3 - Server - FastCastRedux:140

This is how I’m firing the cast.
RaycastParams, CastBehavior and Caster:

local castBehaviour = fastCast.newBehavior()
local castParams = RaycastParams.new()

castParams.FilterDescendantsInstances = {plr.Character}
castParams.FilterType = Enum.RaycastFilterType.Blacklist
castParams.IgnoreWater = true

castBehaviour.RaycastParams = castParams
castBehaviour.MaxDistance = 1000
castBehaviour.CosmeticBulletTemplate = game.ReplicatedStorage.CosmeticBullet
castBehaviour.CosmeticBulletContainer = game.Workspace

Client:

direction = (mouse.Hit.p - gunModel.MuzzleFlash.Position).Unit
remoteEvent:FireServer(gunModel.MuzzleFlash.Position, direction, 300)

Server:

mouseEvent.OnServerEvent:Connect(function(client, origin, direction, velocity)
	
	castParams.FilterDescendantsInstances = {client.Character}
	caster.Fire(origin, direction, velocity, castBehaviour)
	
	gunModel.MuzzleFlash.MuzzleEffect:Emit(60)
	gunModel.BodyAttach["Fire" .. math.random(1, 3)]:Play()
end)

What’s happening? I believe that I used the function and made the cast behaviour correctly but it goes on an infinite error loop whenever I try to fire the cast.

sorry for any lack of information given, I’m kinda on a rush right now.
Edit: I switched the bullet firing to the server, but I’m still getting the same problem. I’ll try to update code samples when I can.

caster.Fire(origin, direction, velocity, castBehaviour)

caster:Fire(), not caster.Fire - that’s the only obvious error I can see right now. Other than that I’m not sure from the code you’ve provided.

1 Like

The issue seems to have been fixed after replacing the dot with a semicolon. Thought it would be just a dot considering FastCast is a module script, but I guess there’s some differences with the two.

Thanks anyway.

Very interesting! I made a similar system like yours (before I discovered this) but with less features and lines of code. It works by having a table of all active rays then also the heartbeat event to update them all. It is a lot more simple as well.

Great work!

After the max distance is reached how do we destroy the projectile that was shot since it would just be frozen in the air? Is it terminate if so what do we pass through the event?

The best part is that since I use Heartbeat, the bullet will accommodate for lag. In the event of any lag, the cast will move how much it should’ve moved as if there was no lag at all, ensuring that it stays on time and remains consistent to the motion values you specifed.

How does Heartbeat work, then?

I’ve been wrestling with this issue for a bit and can’t seem to find a solution. How does one work around this problem? It works perfectly fine when my origin isn’t inside a block, but when it is, it doesn’t register hitting the block when it shoots.

Is there an efficient way I can solve/ work around this?

Have you tried blacklisting the player’s character and the cosmetic bullets from the raycast? I’ve come across that issue before and that’s what I had to do to fix it.

Also for blacklisting cosmetic bullets I recommend you just set the cosmetic bullet container to a good Folder in the workspace and then blacklist that container.

Yes, I have blacklisted both the cache folder and the character, but I don’t think that’s the issue. A bullet flying through other blocks shouldn’t have anything to do with blacklisting your character and bullet cache folder.
If you misunderstood, here’s a video of my issue ^^.

Heartbeat has a parameter when it fires that is the amount of time the heartbeat took. Under normal cases, this is 1/60. If there is lag and the server is running at, say, 15 ticks/sec rather than the target 60 for heartbeating, that value will be 1/15 which is far larger than 1/60. This time is used to stretch or compress the individual ray segments so they stay on track at the cost of accuracy.

You are correct in that this is not the issue. The issue actually comes from the fact that the end of the barrel is inside of the wall. A ray only hits from the outside. Spawning a ray inside of the object and firing outwards will cause it to completely miss the object.

An easy(?) solution is to cast a single custom raycast (unrelated to FC) from the butt of the gun to the barrel to see if it runs into any world objects. If it does, just play the fire sound but don’t actually fire a bullet.

4 Likes

You do use terminate. Have a look at the example gun – The terminate event gives you a reference to the bullet’s ActiveCast which contains its cosmetic bullet. You can dispose of it appropriately there.

1 Like

what are the tuple arguments for the terminate event?

Anyone know where do I put the pierce function since right now I am putting it in the ray hit event.
It will print true but the bullets would not go through

local caster =  FastCast.new()

local castParams = RaycastParams.new()
castParams.FilterType = Enum.RaycastFilterType.Blacklist

local newBullet = Instance.new("Part", Folder) 
newBullet.Size = Vector3.new(0.1, 0.1, 1)  
newBullet.Material = Enum.Material.Neon
newBullet.Shape = Enum.PartType.Block
newBullet.CanCollide = false
newBullet.Anchored = true
newBullet.Color = Color3.fromRGB(209, 130, 6)

local castBehavior = caster.newBehavior()
castBehavior.RaycastParams = castParams
castBehavior.Acceleration = Vector3.new(0,(-workspace.Gravity/2)+ (BulletDrop),0)
castBehavior.CosmeticBulletContainer = Folder
castBehavior.CosmeticBulletTemplate = newBullet
castBehavior.CanPierceFunction = nil
castBehavior.MaxDistance = 100

local function OnLengthChanged(cast, lastPoint, direction, length, velocity, bullet)
	if bullet then
		local bulletLength = bullet.Size.Z/2
		local offset = CFrame.new(0,0, -(length - bulletLength))
		bullet.CFrame = CFrame.lookAt(lastPoint, lastPoint + direction):ToWorldSpace(offset)
		Debris:AddItem(bullet, .5)
	end
end

local function OnRayHit(cast, result, velocity, bullet)
	local hit = result.Instance
	local ECharacter = hit.Parent
		if ECharacter and ECharacter:FindFirstChildWhichIsA("Humanoid")and hit:IsA("BasePart") then
		Debris:AddItem(bullet, .01)
		local Humanoid = ECharacter:FindFirstChildWhichIsA("Humanoid")
		if not game.Players:GetPlayerFromCharacter(ECharacter) then
				Humanoid:TakeDamage(BulletDamage)
			end
		elseif not ECharacter:FindFirstChildWhichIsA("Humanoid") and hit:IsA("BasePart") then
			local HitPierce = Pierce(cast, result, velocity)
		print(HitPierce)
	end
end

Event.OnServerEvent:Connect(function(player, mouseP)
	if player == game.Players:GetPlayerFromCharacter(Tool.Parent) then
		local Character = player.Character
		local RNG = Random.new()
		castParams.FilterDescendantsInstances = {Character, Tool, Folder}
		castParams.IgnoreWater = false
		Raycast_Params.FilterDescendantsInstances = {workspace}
		Raycast_Params.FilterType = Enum.RaycastFilterType.Blacklist
		spawn(function()
		for i = pelletsShot, maxpellets do
		local origin = Tip.CFrame.p
		local length = 100	
		local UnitDirection = (mouseP - origin).Unit
		local pelletSpread = Vector3.new(RNG:NextNumber(-maximumOffset, maximumOffset), RNG:NextNumber(-maximumOffset, maximumOffset), 0)	
		local NewDirection = (UnitDirection + pelletSpread) * length
		local Laser = workspace:Raycast(origin, NewDirection, Raycast_Params)
		if Laser then
		else
			Laser = {}
			Laser.Position = origin + NewDirection
		end
		local direction = (Laser.Position - origin).Unit 
		caster:Fire(origin, direction, BulletSpeed, castBehavior)
			end
		end)
	end
end)	
caster.LengthChanged:Connect(OnLengthChanged)
caster.RayHit:Connect(OnRayHit)

is it possible to force the CastTerminating event to run?

This is covered in the documentation for Caster.

Similarly, this is covered in the documentation for ActiveCast.

1 Like