Failed alpha collision

I am using Playdate SDK Version 2.5.0 on a Mac.

Alpha collisions are not recognized between a circle and the bottom and right lines of a sprite consisting of four lines that form a square. Alpha collisions are recognized between the circle and the top and left lines. I expect alpha collisions to be recognized between the circle and all lines.

This seems like a bug. Maybe it's caused by an off-by-one error or a mishandled floating point number? Or am I doing something wrong?

Here is a gif showing failed alpha collisions with the bottom and right lines.
failed_alpha_collision

Here is a gif showing successful alpha collisions with all lines where the bottom and right lines are brought in by 1 pixel.
alpha_collision

Here is the code to reproduce the issue. Replace the line drawing with the commented out line drawing to see alpha collisions with all lines work.

import "CoreLibs/graphics"

local CELL_SIZE <const> = 39
local HALF_CELL_SIZE <const> = CELL_SIZE / 2
local LAST_CELL_PIXEL_INDEX <const> = CELL_SIZE - 1

local COLUMNS <const> = 10
local ROWS <const> = 6
local BOARD_PIXEL_WIDTH <const> = CELL_SIZE * COLUMNS
local BOARD_PIXEL_HEIGHT <const> = CELL_SIZE * ROWS
local BOARD_X <const> = (400 - BOARD_PIXEL_WIDTH) / 2
local BOARD_Y <const> = (240 - BOARD_PIXEL_HEIGHT) / 2

local CELL_X <const> = CELL_SIZE * (COLUMNS - 1)
local CELL_Y <const> = CELL_SIZE * (ROWS - 1)
local CELL_RIGHT <const> = CELL_X + LAST_CELL_PIXEL_INDEX
local CELL_ALMOST_RIGHT <const> = CELL_RIGHT - 1
local CELL_BOTTOM <const> = CELL_Y + LAST_CELL_PIXEL_INDEX
local CELL_ALMOST_BOTTOM <const> = CELL_BOTTOM - 1

local PLAYER_SIZE <const> = 14
local PLAYER_X <const> = CELL_X + BOARD_X + HALF_CELL_SIZE
local PLAYER_Y <const> = CELL_Y + BOARD_Y + HALF_CELL_SIZE

local MOVE_SPEED <const> = 1

local REPORT_X <const> = 400 - CELL_SIZE
local REPORT_Y <const> = 200 - CELL_SIZE - PLAYER_SIZE

local playerImage <const> = playdate.graphics.image.new(PLAYER_SIZE, PLAYER_SIZE)
local playerSprite <const> = playdate.graphics.sprite.new(playerImage)

local boardImage <const> = playdate.graphics.image.new(BOARD_PIXEL_WIDTH, BOARD_PIXEL_HEIGHT, playdate.graphics.kColorClear)
local boardSprite <const> = playdate.graphics.sprite.new(boardImage)

playdate.graphics.pushContext(playerImage)
playdate.graphics.fillCircleInRect(0, 0, PLAYER_SIZE, PLAYER_SIZE)
playdate.graphics.popContext()

playdate.graphics.pushContext(boardImage)
playdate.graphics.drawLine(CELL_X, CELL_Y, CELL_RIGHT, CELL_Y)
playdate.graphics.drawLine(CELL_RIGHT, CELL_Y, CELL_RIGHT, CELL_BOTTOM)
playdate.graphics.drawLine(CELL_RIGHT, CELL_BOTTOM, CELL_X, CELL_BOTTOM)
playdate.graphics.drawLine(CELL_X, CELL_BOTTOM, CELL_X, CELL_Y)
-- playdate.graphics.drawLine(CELL_X, CELL_Y, CELL_ALMOST_RIGHT, CELL_Y)
-- playdate.graphics.drawLine(CELL_ALMOST_RIGHT, CELL_Y, CELL_ALMOST_RIGHT, CELL_ALMOST_BOTTOM)
-- playdate.graphics.drawLine(CELL_ALMOST_RIGHT, CELL_ALMOST_BOTTOM, CELL_X, CELL_ALMOST_BOTTOM)
-- playdate.graphics.drawLine(CELL_X, CELL_ALMOST_BOTTOM, CELL_X, CELL_Y)
playdate.graphics.popContext()

boardSprite:setCenter(0, 0)
boardSprite:setCollideRect(0, 0, BOARD_PIXEL_WIDTH, BOARD_PIXEL_HEIGHT)
boardSprite:moveTo(BOARD_X, BOARD_Y)
boardSprite:add()

playerSprite:setCollideRect(0, 0, PLAYER_SIZE, PLAYER_SIZE)
playerSprite:moveTo(PLAYER_X, PLAYER_Y)
playerSprite:add()

playdate.graphics.setColor(playdate.graphics.kColorClear)

function playdate.update()
	local dx = 0
	local dy = 0

	if playdate.buttonIsPressed(playdate.kButtonLeft) then
		dx -= MOVE_SPEED
	end

	if playdate.buttonIsPressed(playdate.kButtonRight) then
		dx += MOVE_SPEED
	end

	if playdate.buttonIsPressed(playdate.kButtonUp) then
		dy -= MOVE_SPEED
	end

	if playdate.buttonIsPressed(playdate.kButtonDown) then
		dy += MOVE_SPEED
	end

	playerSprite:moveBy(dx, dy)

	playdate.graphics.sprite.update()

	local overlappingSprites <const> = playerSprite:overlappingSprites()
	local alpha = false

	for i = 1, #overlappingSprites do
		if playerSprite:alphaCollision(overlappingSprites[i]) then
			alpha = true
		end
	end

	playdate.graphics.drawText(tostring(alpha), REPORT_X, REPORT_Y)
end
1 Like

Any thoughts? I just submitted a game to Catalog, but it has a bug because of this.