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
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.
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.
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