Raycast Simulation (Projectiles without a part)

I want to achieve a legit projectile ray simulation, my code works just fine but I believe I’m doing this the wrong way.
I also want to add in a projectile drop. You can also help me improve my code, thank you!

local RaycastParam = RaycastParams.new()
RaycastParam.FilterType = Enum.RaycastFilterType.Blacklist
function module.create(Origin, Character, Direction, Speed)
	local Connection, Player = nil, game.Players:GetPlayerFromCharacter(Character)
	RaycastParam.FilterDescendantsInstances = {workspace.Terrain, workspace.Terrain, workspace.Projectiles, Character}
	local LifeTime = 0
	local Direction = Origin.LookVector
	local Position = Origin.Position
	Connection = RunService.Heartbeat:Connect(function(Delta)
		Position += Direction * Speed/2
		Direction += Origin.LookVector * Speed/2
		if (LifeTime > 3.5) then
			if Connection then
				Connection:Disconnect() 
				Connection = nil
			end
		end
		LifeTime += Delta
		local RaycastResult = workspace:Raycast(Position, Direction * Speed, RaycastParam)
		if RaycastResult  then
			local Inst = RaycastResult.Instance
			local RayPos = RaycastResult.Position
			local RayNormal = RaycastResult.Normal
			if Inst.Parent:FindFirstChildWhichIsA("Humanoid") then
				if Inst.Name == "Head" then
					Inst.Parent.Humanoid:TakeDamage(20)
				else
					Inst.Parent.Humanoid:TakeDamage(10)
				end
				Player.REvents.DamageHit:FireClient(Player, tick(), RayPos)
				game.ReplicatedStorage.ClientRemotes.BulletHit:FireAllClients("HumanoidHit" ,Inst, RayPos, RayNormal, Enum.Material.Plastic)
				if Connection then
					Connection:Disconnect() 
					Connection = nil
				end
			else
				if Inst.Material == Enum.Material.Glass then
					game.ReplicatedStorage.ClientRemotes.BulletHit:FireAllClients("TerrainImpact" ,Inst, RayPos, RayNormal, Enum.Material.Glass)
					game.ReplicatedStorage.ClientRemotes["3DSound"]:FireAllClients("4757900430", Inst, false, 3)
					Inst.CanCollide = false
				else
					game.ReplicatedStorage.ClientRemotes.BulletHit:FireAllClients("TerrainImpact" ,Inst, RayPos, RayNormal, Enum.Material.Plastic)
				end
				if Connection then
					Connection:Disconnect() 
					Connection = nil
				end
			end
		end
	end)
end

So, you are trying to make an invisible projectile that does damage? I’m confused. Also,

What do you mean by this?

What I mean by projectile drop is a bullet drop, slowly going down. I don’t want to use parts for my projectiles/bullets, so I use raycasting to simulate a projectile.

1 Like

I’d recommend looking into fast cast:

I don’t like to use code from open sourced modules, I like to code things on my own to gain more control over them. But thank you for suggesting that.

you could start with the origin of the bullet, get the direction it should move and set a velocity for it.
Then add the velocity to the position every frame multiplied by the delta time.
Raycast between the previous point and the new one and if you hit something then the bullet has hit.

1 Like

Here is some general code with the physics that should give you a general idea of how to do something like this:

local function getPoint(initialVelocity, gravity, time)
    local x = initialVelocity.X * time
    local y = initialVelocity.Y * time + 0.5 * gravity * time * time
    local z = initialVelocity.Z * time
    return Vector3.new(x, y, z)
end

local direction -- unit direction vector3
local speed -- speed of bullet
local initialVelocity = direction * speed
local origin -- some origin position
local gravity -- amount of y axis acceleration (ex -198.7)
local segmentTimeLength -- amount of simulated time per segment
local params -- raycast params
local maxTime -- max time raycast lasts (time is simulated in this case)

local lastPosition = origin
local result
local finished = false
local simulationTime = 0
-- Note break statement ends while true loop
while true do
   simulationTime += segmentTimeLength
   local delta = getPoint(initialVelocity, gravity, simulationTime)
   local result = Workspace:RayCast(lastPosition, delta, params)
   lastPosition += delta
   if result then
        result = true
        break
   end
   if simulationTime > maxTime then
      break
   end
end

Note that instead of simulating time you can use Heartbeat. Simulating time basically makes the bullet arc like it’s affected by gravity but still hit instantly, which is sometimes preferable.

Also note I wrote that code quickly, so I might have flipped some signs and stuff :sweat_smile:

2 Likes