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

how do i make larger hitbox for the projectile?

FastCast uses Segmented Raycasts, so every frame a new Raycast is produced so it can simulate things like Physics and penetration.

If you want to get the Distance you’ll need to get some sort of reading between the start and end points.

I’m not entirely sure if you need FastCast for this, it seems a bit overkill. You can easily make this yourself with 30-40 minutes of time. But whatever floats your boat.

I don’t think you can, unless you want to seriously slow down the performance. The system uses Raycasts for hit detection. Raycasts, by definition, have infinitely small width and height, they are just lines. You can use spacial queries or functions like :GetPartInPart, but like I said, spacial queries aren’t really cheap, and doing that on top of Raycasts might cause issues.

Greetings,

I Have a problem with FastCast which that the RayHit function is not working which means I cannot detect hits.

local RunService = game:GetService("RunService")
local Debris = game:GetService("Debris")
local TweenService = game:GetService("TweenService")
local FastCast = require(script.FastCastRedux)
local Caster = FastCast.new()

Caster.LengthChanged:Connect(function(casterThatFired, lastPoint, rayDir, displacement, segmentVelocity, cosmeticBulletObject)
	local Position = lastPoint + (rayDir * displacement)
	cosmeticBulletObject.Position = Position
end)

Caster.RayHit:Connect(function(casterThatFired, result: RaycastResult, segmentVelocity, cosmeticBulletObject)	
	print(cosmeticBulletObject)
	print("Anything.")
	local Target = result.Instance.Parent
	if Target:FindFirstChild("Humanoid") then
		Target.Humanoid:TakeDamage(30)
	end
end)

The script is a part of a larger script inside a module script.

I found something goofy, i’m just asking if FastCast is counting with the new FPS limit cap extention, cause it looks like not, caster.LengthChanged runs faster when client is set to 240 fps and slower if set to 60fps, please any patch?

trying to add this to a drone but i cant get the shots to move, some grabbed from the example gun, still nothing

Direction is:
image

1 Like

Hey, I have a question. Why do we need to split a ray cast into smaller pieces to get smooth movement? And also what is the smooth movement for? Tweening of bullets?
Also, what is meant by bullet lag or jittering?

What is different from a single ray cast?
Is this module meant for bullets that have a curved trajectory?


This makes tons of problems for some reason, tho only when i use 1 caster and i disconnect every connection 1 by 1 in the caster

this is the line that errs

You can’t have a “slow” moving bullet with only one raycast being used as the hit detection depends on the rays. Due to that a lot of raycasts are being used to follow the cosmetic bullet. This way an accurate detection of hits can be accomplished. The possibility of a curved trajectory is pretty much just an added bonus.

Oh okay, I got it now, So we can also detect how many in-line hits have occurred, Right? Like if there are two targets in one line and we shoot through one, we can also detect the other one behind that too.

Why exactly would you want to archieve that?

To make bullet pierce through multiple targets or players if aligned correctly?

What does “WARNING: Exceeded maximum pierce test budget for a single ray segment (attempted to test the same segment 100 times!)” exactly mean? I have no clue why it happens.

This is the function I’m using for the RayHit event and CanPierceFunction property:

function handleRayHitfunction(cast : {}, raycastResult : RaycastResult, segmentVelocity : Vector3, cosmeticBulletObject : BasePart?)
	if raycastResult ~= nil then
		local player = game:GetService("Players"):GetPlayerFromCharacter(cast["UserData"]["Owner"])
		if typeof(player) == "Instance" and player:IsA("Player") then
			ure_vfxEvent:FireClient(game:GetService("Players"):GetPlayerFromCharacter(cast["UserData"]["Owner"]), {StopProjectile = {cast["UserData"]["Id"]}})
		end
		
		local damage = calculateDamage(cast, raycastResult)
		
		local gunSettings = cast["UserData"]["Settings"]
		
		if gunSettings["ExplosiveAmmunition"] == true then
			_G.SimulateExplosion(cast["UserData"]["Owner"], raycastResult.Position, gunSettings["ExplosionData"])
		end
		
		if typeof(raycastResult.Instance) == "Instance" and raycastResult.Instance:IsA("BasePart") then
			
			local direction = (raycastResult.Position - segmentVelocity).Unit
			local penetrationDepth = (direction * raycastResult.Instance.Size).Magnitude
			cast["UserData"]["StudsPierced"] += penetrationDepth + (penetrationDepth + (materialPenetrationPercentage[raycastResult.Material] or 0))
			
			local model = raycastResult.Instance:FindFirstAncestorOfClass("Model")
			if typeof(model) == "Instance" and model:IsA("Model") then
				local placementFolder, ownerValue = _G.GetPlacementFolderAndOwner(model)
				local humanoid = model:FindFirstChildOfClass("Humanoid")
				if typeof(humanoid) == "Instance" and humanoid:IsA("Humanoid") then
					_G.DamageHumanoid(cast["UserData"]["Owner"], humanoid, damage, "Bullet", {
						HitPart = raycastResult.Instance,
						Origin = raycastResult.Position,
						Pierce = gunSettings["ArmorPierce"]
					})
				elseif typeof(placementFolder) == "Instance" and placementFolder:IsA("Folder") and placementFolder.Parent == workspace.Map.Placements then
					model:SetAttribute("Health", math.clamp(model:GetAttribute("Health") - damage, 0, math.huge))
				end
			end
			
			print(cast)
			if typeof(cast) == "table" and typeof(cast["UserData"]) == "table" then
				if table.find(cast["UserData"]["PiercedObjects"], raycastResult.Instance) then
					return true
				end
				
				if cast["UserData"]["StudsPierced"] <= (cast["UserData"]["Settings"]["PenetrationDepth"] or 0) then
					table.insert(cast["UserData"]["PiercedObjects"], raycastResult.Instance)
					warn("PIERCING!")
					return true
				else
					warn("Not enough power (reminaining, probably)")
				end
			else
				warn("Nothing left but its name")
			end
		else
			warn("none")
		end
	else
		warn("none")
	end
	
	return false
end

Also, when I hit a character, the cast table is empty for some reason?

Thanks for any responses!

Hey, I’ve encountered a strange problem. It seems that when firing for long enough, the visual bullet will deviate from the ray cast path. My bullet is a model, not anchored, collide false, touch false. It worsens the longer it shoots.
1014

should probably be anchored then

Ran into an issue that’s present even in the example gun - character resetting causes all active casts from the tool to freeze and stop functioning. Everything is shown in the video. This applies to bullets that were fired before the reset too.

Also have you thought of making a dedicated discord server for fastcast? There’s a lot of people who use it and it would be good to have a centralized place for support and discussion other than the devforum.

Aren’t projectiles supposed to be on client? How would that lag compensation work if Player A shoots his projectile and then the server telling other clients to do so as well?

when calling the pierce function, it should give ray’s next direction so i can shoot another ray, and calculate distance between projectile entry and exit points to get the amount penetrated, then i can decide to penetrate if its not very long, also i should be able to lower bullet velocity (or up the gravity) after penetration to simulate the friction.

i believe it should be anchored