I am using a modified version of the displacement formula to simulate projectile physics.
local function x(x0, v0, a, t)
return x0 + v0 * t + 0.5 * a * t^2
end
local function v(v0, a, t)
return v0 + a * t
end
function physics:step(time)
self.position = Vector3.new(
x(self.position.X, self.velocity.X, self.acceleration.X, time),
x(self.position.Y, self.velocity.Y, self.acceleration.Y, time),
x(self.position.Z, self.velocity.Z, self.acceleration.Z, time)
)
self.velocity = Vector3.new(
v(self.velocity.X, self.acceleration.X, time),
v(self.velocity.Y, self.acceleration.Y, time),
v(self.velocity.Z, self.acceleration.Z, time)
)
end
i have a wrapper object which is supposed to add more functionality to the physics module.
local _physics = self._physics
_physics.acceleration = self.acceleration
_physics.position = self.position
_physics.velocity = self.velocity
_physics:step(time)
local raycastResult = workspace:Raycast(self.position, _physics.position - self.position, self.raycastParams)
if raycastResult then
end
initially, for collisions i thought about using raycasts but then i realised this would not work if the time i step by is too large.
The obvious solution is to break down a large step to smaller increments and update the physics that way.
however, I want to know if there is any way that I could skip this? is there any way I can simulate collisions without having to raycast tiny steps all the time?
Try raycasting backwards from the tip of the projectile the amount it would move in one increment.
Say it travels 4 studs/increment. If you raycast backwards from the tip of the bullet 5 studs (to be safe) then if the bullet passes through an item it should register the hit fairly accurately.
that is still raycasting multiple times. I was thinking to break things up into simply their volumes and checking the position values for the physics object to check at what time would it reach an intersection. this however sounds very complicated and so im wondering if it even is feasible at all.
Yes, since if you have moving objects it’d be hard to predict where their volumes should be when they might intersect.
For example if you had a fast moving object that changed direction suddenly into the path of the projectile before it was expected then it’d miss the object.
You could do GetPartsInPart, but again, you’d have to check any one of these methods each step to see if there would be, or is, a hit.
I have a feeling we could maybe implement “curved raycasts”. Currently, raycasts are limited to linear motion due to how much less complex those math equations are to compute. We will have to define the plane/s in which we will be checking for intersections. The issue is that we will be very limited to what we can do since roblox doesn’t allow us (but should) to see further information into the geometry of objects and meshes (WHICH THEY SHOULD).
Your can design your functions to work with vectors instead of numbers. This would allow you to adjust the position and velocity of the object in two lines of code, with zero code duplication
i have a lastposition variable that is at first the initial position of the projectile and is set at the end of every frame that the projectile is updated so that the direction argument passed into the raycast function is just currentposition - lastposition which also happens to account for any skipped/laggy frames
this is stripped boilerplate code from a recent project that you can probably see what’s going on
--- time, bullet, collisions are made in-house and can be found here
--- https://github.com/00826/konbini
local lastposition = start
local alreadyhit = table.create(Players.MaxPlayers)
local c; c = Time.framerule(Bullet.Framerate, function()
local framedata = Bullet.ballisticsolve(linear, Bullet.Framerate)
do --- player
end
do --- env
local maphit = Collisions.raycast("Whitelist", lastposition, framedata.Position - lastposition, {workspace.Map})
if maphit then
if c then c:Disconnect() end
--- ...
end
end
lastposition = framedata.Position
if framedata.Elapsed > Config.time then
if c then c:Disconnect() end
end
end)
also the t^2 can be unwrapped to t*t and if you do sincerely care about squeezing performance then you wouldn’t be using oop because it doesn’t benefit from luau optimizations
In your code you are doing what I intend to avoid. You are using a small increment and raycasting between the last and next position. My intention isn’t to cut down on the number of raycasts but to further improve the accuracy of the kinematics. You can’t model a projectile’s motion with a linear ray perfectly unless the acceleration is 0.
In your code I did find an interesting method I could maybe utilize, BasePart:GetClosestPointOnSurface().
if you really care about the most perfectly accurate position of the impact, then you could do curved raycasting(idk anything about that) or:
you could use the stepped raycast method, but only to determine the part that is hit(so you don’t have to check every part as a volume), and then solve for the time which the bullet enters the bounds
At this point I think that trying to implement raycast physics is no good. It has too many issues with accuracy and only works at the fixed time step rate of 60hz. I think I will go with a physics approach using my physics/trajectory module for validating positions on the server while the ball is simulated on the clients.
So far i am having some issues with a truncation error that seems to be an engine bug. i will make a post on this later.