Looking for help with daabbc library

Wow I wish that I came back here to read this sooner. Yesterday I bashed my head into the wall trying to get it perfect with just overlap testing.

I switched to using the sort variant of query so I could get the closest collision.

function M.query_player()
    local result, count = daabbcc.query_id_sort(M.group, M.player_aabb_id, collision_bits.GROUND)
    return result, count
end

This handles most of the collision.

function check_collisions(self, pos)
    local query_result, result_count = collision.query_player()

    if not query_result and (self.wall_contact_left or self.wall_contact_right) then
        print("No query result")
        self.wall_contact_left = false
        self.wall_contact_right = false
    end

    if query_result and result_count > 0 then
        local first_collision = query_result[1]
        local aabb_id = first_collision.id
        local data = collision.ground_data[aabb_id]

        if data and data.type == "GROUND" then
            local y_offset = 18
            local x_offset = 15.01
            local tile_top = data.y + data.height
            local tile_bottom = data.y
            local tile_left = data.x
            local tile_right = data.x + data.width

            -- Check for above and below collisions
            local is_above_tile = pos.y >= tile_top
            local is_below_tile = pos.y + (54 / 2) < tile_bottom
            local is_right_of_tile = pos.x - (46 / 2) < tile_right and pos.x > tile_left
            local is_left_of_tile = pos.x + (46 / 2) + 1000000 > tile_left and pos.x < tile_right


            -- Handle collision from above (landing)
            if is_above_tile then
                -- print("Hit from above")
                pos.y = tile_top + y_offset
                self.ground_contact = true
                msg.post("/camera#controller", "follow_player_y", { toggle = false })
                self.velocity.y = 0

            -- Handle collision from below
            elseif is_below_tile then
                -- print("Hit from below")
                pos.y = tile_bottom - (y_offset * 2)
                self.velocity.y = 0
                self.is_jumping = false

            -- Handle left collision
            elseif is_right_of_tile then
                -- print("Hit from the left")
                pos.x = tile_right + x_offset
                self.velocity.x = 0
                self.wall_contact_left = true

            -- Handle right collision
            elseif is_left_of_tile then
                -- print("Hit from the right")
                pos.x = tile_left - (x_offset * 2) - 1
                self.velocity.x = 0
                self.wall_contact_right = true
            end
        else
            print("Unknown collision!")
        end
    end
    
    return pos
end

This mostly works but due to the way the collision is handled, it causes oscillating self.wall_contact_* values which has a variety of undesired effects for my game.

So it came to me when I woke up this morning that a combination of raycasting and overlap testing would do the trick.

function M.raycast_player(player_pos, sprite_flipped, max_distance)
    local player_height = 54
    local direction = sprite_flipped and -1 or 1

    local ray_offsets = {
        0,                       -- center
        player_height / 2 - 10,  -- top
        -player_height / 2 + 10  -- bottom
    }

    local results = {}

    for _, offset in ipairs(ray_offsets) do
        local ray_start = vmath.vector3(player_pos.x, player_pos.y + offset, 0)
        local ray_end = vmath.vector3(player_pos.x + direction * max_distance, player_pos.y + offset, 0)

        local result, count = daabbcc.raycast(M.group, ray_start.x, ray_start.y, ray_end.x, ray_end.y, collision_bits.GROUND)
        
        table.insert(results, {result = result, count = count, ray_start = ray_start, ray_end = ray_end})
    end

    if debug then
        local blue = vmath.vector4(0, 0, 1, 1)

        for _, ray_data in ipairs(results) do
            debug_draw_raycast(ray_data.ray_start, ray_data.ray_end, blue)

            if ray_data.count then
                for _, aabb_id in ipairs(ray_data.result) do
                    local tile = M.ground_data[aabb_id]
                    if tile then
                        debug_draw_aabb({ tile }, blue, tile_draw_x_offset, tile_draw_y_offset)
                    end
                end
            end
        end
    end

    return results
end



function M.update_wall_contact(player, player_pos)

    local raycast_results = M.raycast_player(player_pos, player.sprite_flipped, 26)

    player.wall_contact_left = false
    player.wall_contact_right = false

    for _, result in ipairs(raycast_results) do
        if result.result then
            if player.sprite_flipped then
                player.wall_contact_left = true
            else
                player.wall_contact_right = true
            end
        end
    end
end

It’s a mess but it works.

I think Pawel’s solution is more robust so I will probably study that once I run into issues with this one.

Thanks to selim for the library. It’s hard to figure out but once you do its not bad, like anything I guess.

nevermind the low quality video.

1 Like