Suppression Effect With Raycasts

I use simplecast

Whats the best way to go about with adding suppression effects with a gun (while the cast is active, not when it hits an obj)? I cast everything from the client btw

1 Like

I’m not entirely familiar with simplecast and I am not familiar with your implementation but I will share what I am thinking of off the top of my head…

If there is an event that fires each time the cast is updated (bullet moved), you could do a query with WorldRoot:GetPartBoundsInRadius(pos : Vector3, radius : number, overlapParams : OverlapParams) to see if any player are within the radius you set of the projectile. If they are then execute your suppression code.

WorldRoot | Documentation - Roblox Creator Hub

Do you think that’d be the most performant way? I’m really only concerned about optimization, as this wouldnt be a completely integral feature

i’m assuming you have the enemy players’ bullets available on the client you are trying to get suppressed
a simple distance check(IF THE BULLETS ARE MADE OF MULTIPLE RAYS) would work but wouldnt be like world class optimization but thats what i’d do

if it’s just a singular ray, you could compare the ray’s direction to the direction from it’s origin towards the target, and that would be a sort of measure of nearness

there’s also solving for the nearest point on a ray to another point, which is more difficult vector math if you’re up to it(google it)

I dont know if this is a good idea at all… but I did it on the client?

local function OnCastMove(self, castData, oldVec, newVec)
	for _, player in ipairs(game.Players:GetPlayers()) do
		if player ~= Player and player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
			local playerPosition = player.Character.HumanoidRootPart.Position
			local distance = (newVec - playerPosition).Magnitude

			if distance < 10 then
				print(player.Name .. "in range")
			end
		end
	end
end

it would be better to do it on the client being suppressed so that way you don’t have to deal with extra delay or looping though players
it would fit right in with tracer replication(unless they are serversided(yuck))

I’ve approached it a couple of ways but I’m not sure how effective they are:

--Vector based approach
function SimpleCast:_update(dt)
	debug.profilebegin("SimpleCastUpdate")
	local timeNow = os.clock()

	local overlapParams = OverlapParams.new()
	overlapParams.CollisionGroup = "Players"

	local players = game:GetService("Players"):GetPlayers()
	local activePlayers = {}
	for _, player in ipairs(players) do
		if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
			activePlayers[player] = player.Character.HumanoidRootPart.Position
		end
	end

	for index, cast in ipairs(self._casts.Cache) do
		cast.LifeTime = timeNow - cast.StartTime
		local newPosition = SimpleCast.GetPosition(cast.LifeTime, cast.InitVelocity, cast.InitPosition, self._gravity)
		local oldPosition = cast.Object.Position
		local hitObj = self:Raycast(oldPosition, newPosition, 1)

		for player, pos in pairs(activePlayers) do
			local dist = (pos - newPosition).magnitude
			if dist <= 10 and player ~= cast.Caster then
				print(player.Name)
				cast.DetectedPlayers[player.UserId] = true
			end
		end

		if timeNow >= cast.StartTime + 10 or oldPosition.Y <= workspace.FallenPartsDestroyHeight then
			self:CastTerminate(cast)
			continue
		end

		if hitObj then
			self._onCastHit(self, hitObj, cast, newPosition)
			continue
		end

		cast.Object.Position = newPosition
	end

	debug.profileend()
end
-- @Seiiyo inspired approach
function SimpleCast:_update(dt)
	debug.profilebegin("SimpleCastUpdate")
	local timeNow = os.clock()

	local overlapParams = OverlapParams.new()
	overlapParams.CollisionGroup = "Players"

	for index, cast in ipairs(self._casts.Cache) do
		cast.LifeTime = timeNow - cast.StartTime
		local newVec = SimpleCast.GetPosition(cast.LifeTime, cast.InitVelocity, cast.InitPosition, self._gravity)
		local oldVec = cast.Object.Position
		local hitObj = self:Raycast(oldVec, newVec, 1)

		local nearbyParts = workspace:GetPartBoundsInRadius(newVec, 10, overlapParams)
		for _, part in ipairs(nearbyParts) do
			local player = game:GetService("Players"):GetPlayerFromCharacter(part.Parent)
			if player and (player ~= cast.Caster or player ~= self._caster) and not cast.DetectedPlayers[player.UserId] then
				cast.DetectedPlayers[player.UserId] = true
			end

		end

		if timeNow >= cast.StartTime + 10 or oldVec.Y <= workspace.FallenPartsDestroyHeight then
			self:CastTerminate(cast)
			continue
		end

		if hitObj then
			self._onCastHit(self, hitObj, cast, newVec)
			continue
		end

		cast.Object.Position = newVec
	end

	debug.profileend()
end```

between the two approaches you used, I would advise against the GetPartBoundsInRadius because that is almost definitely slower for the same result
it would be surprising if the profiling results prove otherwise

1 Like

Actually, ive found a better way to do it:

the owner of SimpleCast suggests when replicating the cast, you should create and fire a different cast from the receiving clients.

Understanding this- I just modified the _update function. It subtracts caster’s rootpart magnitude from the distance of the castobject, and if within 15 studs, then i handle the effect there.

Thanks regardless tho :+1:

2 Likes