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

Hey, quick question again, hey it’s me!

So I tried out some beam work, and two beams together make it look like a super nice bullet. How do I make the fast cast use two beams with of course, two attachments, be the fire point? Or do I just seperate it to make a velocity based beam?

What would be the best way to use this module?

I want to have good hit detection, But when i use this on serverside, The bullets take a bit to shoot.

I’ve seen people say make the hit detection on server-side, But replicate the bullets on the client?

Also: Could this work with viewmodels?

1 Like

I can’t fully explain to you, but I can answer it.

Number 1: Yes, it can work with viewmodels, I use it for my viewmodel.

I usually do the bullets client side then do the damage on serverside, along with maybe another extra caster:Fire() on server to add those serverside bullets so people can see you shoot.

1 Like

If it’s a beam and 2 attachments, Can’t you just put them inside an invisible part, And make the part the bullet? This way the attachments would also follow the part i’d assume

https://gyazo.com/76eabac15e584846e39f1f73087506c3

https://gyazo.com/dcdcd0e249c3a5274caf32e57233a0da
This is how i created the part, This works fine for me (Even though i’m using a trail not a beam, But they should be the same.)

Do you mind sharing the bullet code to add that bullet in? Since I am having trouble with that.

Alright, The code used to clone the bullet is:

local BulletTemplate = game.ReplicatedStorage.Bullet:Clone() -- This will be the bullet we clone.

local CastBehavior = FastCast.newBehavior() -- put your settings here
CastBehavior.CosmeticBulletTemplate = BulletTemplate 

Furthermore, You can use “CosmeticBulletProvider” If you want to use a partcache.

Cheers mate, will try it out in a second.

By the way, Don’t forget you need to update the bullet’s CFrame, The module doesn’t do that by itself.

Hmm?? I used a part cache and it worked fine without changing the CFrame.

Oh?? Strange, I didn’t know that.

Also strange, whenever I shoot the bullet doesn’t move, it teleports right in front of muzzle but doesn’t shoot forward.

local caster = FastCastRedux.new()

local BulletFolder = workspace:WaitForChild("BulletFolder")

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

castParams.FilterDescendantsInstances = {BulletFolder}

local bulletTemplate = RS:WaitForChild("BulletPart"):Clone()
--bulletTemplate.Anchored = true
--bulletTemplate.CanCollide = false
--bulletTemplate.Size = Vector3.new(0.08, 0.057, 0.077)
--bulletTemplate.Material = Enum.Material.Neon
--bulletTemplate.Color = Color3.fromRGB(8, 148, 255)
--bulletTemplate.Transparency = 0.99


local bulletCache = PartCache.new(bulletTemplate, 90, BulletFolder)

local castBehavior = FastCastRedux.newBehavior()
castBehavior.RaycastParams = castParams
castBehavior.Acceleration = Vector3.new(0, -workspace.Gravity, 0)
castBehavior.AutoIgnoreContainer = true
castBehavior.CosmeticBulletContainer = BulletFolder
castBehavior.CosmeticBulletProvider = bulletCache
--castBehavior.CosmeticBulletTemplate = bulletTemplate

That’s what i meant, You’ll have to update the projectile’s CFrame, Here’s the code i used.

Caster.LengthChanged:Connect(function(Cast, LastPoint, Direction, Length, Velocity, Projectile)
	if Projectile then
		local ProjectileLength = Projectile.Size.Z/2
		local Offset = CFrame.new(0,0,-(Length-ProjectileLength))
		Projectile.CFrame = CFrame.lookAt(LastPoint, LastPoint+Direction):ToWorldSpace(Offset)
	end
end)

Alright, thanks. It works. I will add in an onrayhit so it deletes the bullet on impact of an object.

1 Like

Unsure if raycast parameters are off or what, but it doesn’t seem to filter correctly??

I get prints when the bullet hits the barrel of the gun (which is a child of “Tool”), thus it should be ignored??

local Tool = script.Parent
local Character = Tool.Parent

local Bullets = workspace:WaitForChild("Bullets")

local CastParams = RaycastParams.new()
CastParams.FilterType = Enum.RaycastFilterType.Blacklist
CastParams.IgnoreWater = true
CastParams.FilterDescendantsInstances = {
	Character,
	Tool,
	Bullets
}

local Caster = FastCast.new()

-- Set up cast behavior
local CastBehavior = FastCast.newBehavior()
CastBehavior.RayCastParams = CastParams
CastBehavior.Acceleration = Vector3.new(0, -500, 0)
CastBehavior.AutoIgnoreContainer = false
CastBehavior.CosmeticBulletContainer = Bullets
CastBehavior.CosmeticBulletTemplate = BulletTemplate

local function OnRayHit(cast, result, velocity, bullet)
	local Hit = result.Instance
	print(Hit)
	local HitCharacter = Hit:FindFirstAncestorWhichIsA("Model")
	if HitCharacter ~= Character then
		if HitCharacter and HitCharacter:FindFirstChild("Humanoid") then -- Character
			HitCharacter.Humanoid:TakeDamage(100)
		end
	end
	
	Debris:AddItem(bullet, 2)
end

Caster.RayHit:Connect(OnRayHit)

Is there a way to make the projectile and the end result different parts. By that I mean, can the projectile that flies through the air be a specific part, with its own specs, and then the bullet that is left on the part be a different part?? I want to use rectangle projectiles, but then have the part that sticks on the block be a ball :confused:

1 Like

RayHit doesnt seem to be firing for me

local module = {}

local RS = game:GetService("ReplicatedStorage")

local Modules = RS:WaitForChild("Modules")

local FastCast = require(Modules:WaitForChild("FastCastRedux"))
local OnHit = require(script:WaitForChild("OnHit"))

local Caster = FastCast.new()
local Behaviour = FastCast.newBehavior()

local cBullet = Instance.new("Part")
cBullet.Size = Vector3.new(0.1,0.1,0.2)
cBullet.Anchored = true
cBullet.CanCollide = false
cBullet.Color = Color3.fromRGB(18, 18, 18)

local CastParams = RaycastParams.new()
CastParams.IgnoreWater = true
CastParams.FilterType = Enum.RaycastFilterType.Blacklist

Behaviour.CosmeticBulletTemplate = cBullet
Behaviour.CosmeticBulletContainer  = workspace
Behaviour.RaycastParams = CastParams
Behaviour.Acceleration = Vector3.new(0,-9.8,0)

Caster.LengthChanged:Connect(function(CasterThatFired, LastPos, RayDir, Displacement, SegmentVelocity, Bullet)
	Bullet.Position = LastPos + (RayDir * Displacement)
end)

Caster.RayHit:Connect(function(CasterThatFired, RayResult, SegmentVelocity, Bullet)
	local Hit = RayResult.Instance
	print("Hit")
	if Hit.Parent:FindFirstChild("Humanoid") then
		print("Hum")
		local Func = OnHit[Hit.Name]
		if Func then
			print("Func")
			Func(Hit, RayResult)
		end
	end
end)

Caster.CastTerminating:Connect(function(ActiveCast)
	ActiveCast.RayInfo.CosmeticBulletObject:Destroy()
end)

function module.OnFire(Tool)
	local Pistol = Tool.Pistol	
	Pistol.Pistol.Fired:Play()
	
	CastParams.FilterDescendantsInstances = {Tool}

	local Origin = Pistol.Tip.Position
	local Direction = -Pistol.Bolt.CFrame.LookVector

	Caster:Fire(
		Origin,
		Direction,
		150,
		Behaviour
	)

end

return module

doesnt print or error anything even if i shoot directly at a wall. The bullet is fired, its even visible. And it goes straight trough anything i shoot it at without firing the rayhit. Ive been trying to solve this for days now.

This is on the server in a module by the way.

1 Like

How do you get the current cosmetic bullet?
CastTerminating doesn’t return the bullet so I have no idea how to delete the bullet after its done because I don’t know how to access it.

Never mind found out how.

Do we have to create a Caster for each individual weapon? I’m trying to make it modular and have client-server a lot quicker. Previously I had client and server scripts similar to your example. I am now just using the client to handle the physical bullets/etc. While server just do invisible check for player collisions. And I am trying to create a single module that can handle all the guns shooting, instead of having every single gun having their own individual scripts.

local Caster = FastCast.new()

function Bullet.Fire(player, weapon, mousePosition, firePoint)
	local WeaponFolder = Weapons:FindFirstChild(weapon)
	if not WeaponFolder then return end
	
	local Config = WeaponFolder.Weapon:FindFirstChild("Config")
	if not Config then return end
	
	local SPEED = Config:GetAttribute("Speed")
	local GRAVITY = Config:GetAttribute("Gravity")
	
	BulletTemplate.BrickColor = player.TeamColor -- Set bullet color to team color
	
	-- Set up cast behavior
	local CastBehavior = FastCast.newBehavior()
	CastBehavior.RayCastParams = CastParams
	CastBehavior.Acceleration = Vector3.new(0, -GRAVITY, 0)
	CastBehavior.CosmeticBulletContainer = Bullets
	CastBehavior.CosmeticBulletTemplate = BulletTemplate
	
	-- Projectile math
	local Origin = firePoint
	local Direction = (mousePosition - Origin).Unit
	
	Caster:Fire(Origin, Direction, SPEED, CastBehavior) -- Fire shot
	
	Caster.LengthChanged:Connect(OnLengthChanged)
	Caster.RayHit:Connect(OnRayHit)
end

This way it can be a million times easier, than having to go through say 100+ guns and all their scripts. I could just tell it what gun they firing from, and get that guns specifics from there.

My problem I then run into what could be a problem from the server. “Shoot” is fired from the client when they click.

-- SERVER
local FastCast = require(Shared.FastCast)

local Caster = FastCast.new()

-- Default raycast parameters
local CastParams = RaycastParams.new()
CastParams.FilterType = Enum.RaycastFilterType.Blacklist
CastParams.IgnoreWater = true

local function OnRayHit(cast, result, velocity, bullet)
	local Hit = result.Instance
	
	local HitCharacter = Hit:FindFirstAncestorWhichIsA("Model")
	if HitCharacter and HitCharacter:FindFirstChild("Humanoid") then -- Character
		HitCharacter.Humanoid:TakeDamage(100)
	end
end

local function FireBullet(player, mousePosition, firePoint)
	-- Find and set variables later --
	local SPEED = 20
	local GRAVITY = 300
	---------------------------------------------
	-- Set up cast behavior
	local CastBehavior = FastCast.newBehavior()
	CastBehavior.RayCastParams = CastParams
	CastBehavior.Acceleration = Vector3.new(0, -GRAVITY, 0)
	
	local Origin = firePoint
	local Direction = (mousePosition - Origin).Unit
	
	Caster:Fire(Origin, Direction, SPEED, CastBehavior)
	
	for _, v in pairs(Players:GetPlayers()) do
		if v == player then continue end
		
		ReplicateBullet:FireClient(v, mousePosition, firePoint)
	end
end

Shoot.OnServerEvent:Connect(FireBullet)

Caster.RayHit:Connect(OnRayHit)

I am then unable to tell on the server who actually fired the specific shot, so players are able to thus shoot themselves :confused:

Did you ever find a fix for this?? I’m using the inbuilt filter but it doesn’t actually seem to filter the descendants correctly??

I have a folder called “Splatter” and it’s added to the FilterDescendantsInstances, however I still get the bullet hitting the descendants of the folder :confused:

-- Create caster
local Caster = FastCast.new()

--// Object hit
local function OnRayHit(cast, result, velocity, bullet)
	local Hit = result.Instance
	print(Hit.Parent) -- Prints Splatter
	
end

function Bullet.Fire(player, weapon, mousePosition, firePoint)
	local WeaponFolder = Weapons:FindFirstChild(weapon)
	if not WeaponFolder then return end
	
	local Config = WeaponFolder.Weapon:FindFirstChild("Config")
	if not Config then return end
	
	local SPEED = Config:GetAttribute("Speed")
	local GRAVITY = Config:GetAttribute("Gravity")
	
	BulletTemplate.BrickColor = player.TeamColor -- Set bullet color to team color
	
	CastParams.FilterDescendantsInstances = {
		player.Character,
		Splatter
	}
	
	-- Set up cast behavior
	local CastBehavior = FastCast.newBehavior()
	CastBehavior.RayCastParams = CastParams
	CastBehavior.Acceleration = Vector3.new(0, -GRAVITY, 0)
	CastBehavior.CosmeticBulletContainer = Bullets
	CastBehavior.CosmeticBulletProvider = BulletCache
	print(CastBehavior)
	-- Projectile math
	local Origin = firePoint
	local Direction = (mousePosition - Origin).Unit
	
	Caster:Fire(Origin, Direction, SPEED, CastBehavior) -- Fire shot
end

Caster.RayHit:Connect(OnRayHit)

Is there a way to make a homing type projectile
This is basicly what i have going on but the Raycast is not getting updated so it jerkes around when it finds the target

function OnRayUpdated(cast, segmentOrigin, segmentDirection, length, segmentVelocity, cosmeticBulletObject)
-- Whenever the caster steps forward by one unit, this function is called.
-- The bullet argument is the same object passed into the fire function.
if cosmeticBulletObject == nil then return end
local bulletLength = cosmeticBulletObject.Size.Z / 2 -- This is used to move the bullet to the right spot based on a CFrame offset
local baseCFrame = CFrame.new(segmentOrigin, segmentOrigin + segmentDirection)
cosmeticBulletObject.CFrame = baseCFrame * CFrame.new(0, 0, -(length - bulletLength))
local t = cast.UserData["Target"]
local c = cast.UserData["Player"]

if(t == nil) then
	for i,v in pairs(workspace:GetDescendants()) do
		if(v:findFirstChild("Humanoid") and math.abs((v.HumanoidRootPart.Position - cosmeticBulletObject.Position).Magnitude) <= 15) then
			cosmeticBulletObject.CFrame = CFrame.new(cosmeticBulletObject.Position,v.HumanoidRootPart.Position)
			print(v)
		end
	end
end