I’ve been working on a 2D raycast-based platformer physics system, and I keep running into the issue of which order to check for collision. If I check for floors then walls, the player will “stand” on the wall for a frame, since it sees it as a floor before the wall sensors get a chance to push the player out. If I check for walls then floors, I have the opposite problem: the wall sensors see the floor and push the player around before the floors sensors can push them out. Here’s a rough layout of the sensors for reference:
Green for floor, magenta for ceiling, and red/blue for wall
Hmm. I don’t usually mess with raycasts much, but i think the same method for dealing with collision objects in the tutorials would probably work here, if i understand your problem. Hard to know without a code example, but are you trying to “resolve” collisions with the result of each raycast? In the kinematic collision example, because collisons can happen more than once per frame (and multiple rays can collide per frame as well, if you’re standing on ground but also touching a wall), the idea would be to calculate some variable/property (self.correction in the example) for each ray, which would be cumulatively updated for each ray, and then only applied once in update (self.position = self.position + self.correction, go.set_position(self.position).
Sorry, I didn’t explain it very well. The rays correct the player’s position perfectly, but they do so at incorrect times. For example, if the player ran into a wall with enough speed, the floor sensors would take priority over the wall sensors, causing the player to “stand” on the wall for a moment before getting pushed out, instead of just being pushed out like they should. I’m looking for a way to ignore/disable sensors when that happens. There doesn’t seem to be any value in the raycast response that could solve this. Here’s the code for the floor sensors:
Code
local function floor_sensor(x_off, length, ray_color, pos)
local from = vmath.vector3(pos.x pos.y - x_off, pos.z)
local to = vmath.vector3(pos.x + x_off, pos.y - length, pos.z)
local ray = physics.raycast(from, to, {hash("world")})
local data = {}
if ray ~= nil then
data.found_tile = true
data.x_pos = ray.position.x
data.y_pos = ray.position.y
data.pos = ray.position
to = ray.position
data.new_pos = vmath.vector3(0, length, 0) + ray.position + x_off
data.fraction = ray.fraction
else
data.found_tile = false
end
if game.debug then
msg.post("@render:", "draw_line", { start_point = from, end_point = to, color = color_convert.hex(data.found_tile and ray_color or "000000", 1) } )
end
return data
end
function update(self, dt)
...
local a = floor_sensor(-9, 20, "5af000", pos)
local b = floor_sensor(9, 20, "64ffa2", pos)
if a.found_tile or b.found_tile then
player.grounded = true
if a.found_tile and b.found_tile then
-- Use whichever sensor found the closest tile
if a.fraction <= b.fraction then
pos = a.new_pos
elseif b.fraction < a.fraction then
pos = b.displace
end
elseif a.found_tile then
pos = a.new_pos
elseif b.found_tile then
pos = b.new_pos
end
if not player.state[1].grounded then
on_land()
end
else
player.grounded = false
end
...
end