I’m trying to create a projectile system that simulates with raycasts, on each RenderStep.
I’ve just implemented air resistance into my system, but for higher velocities and drag coefficients, my projectiles behave strangely, and velocity prints as {nan, nan, nan}
I’m not really sure at all where these values come from, I thought they could only come from divide-by-zero errors, but I don’t divide by anything anywhere in my script.
(This function is a method of a class I’m creating, as far as I can tell this is the only relevant part of the script)
function METATABLE:CastShot(origin, direction, muzzleVelocity, dragCoefficient)--start is a position, goal is a position
local onlyRaycastParams = RaycastParams.new()
onlyRaycastParams.FilterType = Enum.RaycastFilterType.Exclude
for i, v in LocalPlayer.Character:GetDescendants() do
onlyRaycastParams:AddToFilter(v)
end
local startTime = tick()
if not dragCoefficient then dragCoefficient = 0.01 end
local verticalAcceleration = -34.9958
local lastRay = nil
local lastOrigin = nil
local lastEndpoint = origin
local endpointVelocity = direction * muzzleVelocity
local RenderStepped
RenderStepped = RunService.RenderStepped:Connect(function(dT)
--[[This loop calculates the bullet's path based on a raycast fired in every renderstep.
The reason the steps seem weirdly sized is because I wrote them on paper in mental steps,
not based on how difficult they would be to code.]]
local timeSinceStart = tick() - startTime
if timeSinceStart > 15 then
RenderStepped:Disconnect()
end
--1. Find origin point (Endpoint of last ray)
local thisOrigin = lastEndpoint
--2. Find velocity at last endpoint.
local velocity = endpointVelocity
--3. Solve for acceleration, based on wind resistance and gravity.
local accelerationDueToGravity = Vector3.new(0, verticalAcceleration, 0)
local attitude = (velocity.Unit)
local density = 1.3--This is intended to be tweaked to make gameplay more realistic, but should not change during gameplay.
local drag = (0.5) * density * (velocity.Magnitude^2) * dragCoefficient
print(drag)
local airResistance = attitude * -drag
local acceleration = airResistance + accelerationDueToGravity
--4. Modify velocity based off calculated acceleration.
velocity = velocity + (acceleration * dT)
--5. Solve for displacement (ray direction) based off calculated velocity.
local displacement = velocity * dT
--6. Cast Ray
local renderStepRayCast = Raycast2:VisualRay(thisOrigin, displacement, onlyRaycastParams)
--7. Code that executes if the ray has hit something.
if renderStepRayCast then
RenderStepped:Disconnect()
end
--8. Update Relevant Variables
lastOrigin = lastEndpoint
if renderStepRayCast then lastEndpoint = renderStepRayCast.Position else
lastEndpoint = thisOrigin + displacement
end
endpointVelocity = velocity
end)
end
If anyone wants to test the full script themselves, here are the necessary modules, to be put into ReplicatedStorage.
GunCast.lua (3.0 KB)
Raycast2.lua (1.5 KB)
The method is called by creating a Guncast.new() object, and then calling :CastShot on it, with origin working like raycast, BUT DIRECTION IS A UNIT VECTOR
If you are unable to replicated my NaN error, I get it when calling
caster:CastShot(Vector3.new(0, 15, 70), Vector3.new(10, 0, 0).Unit, 3000, 0.2)