Broken collisions on alpha collision based raycaster

,

I am using the Windows lua SDK and I am having issues with the raycaster I've been trying to make as a test project. This is the first real project I am doing on the playdate without any tutorials. I have some amount of prior coding experience, but not with lua.

After shooting out the ray into a direction, it is supposed to give back the traveled distance after the first alpha collision with the map.

I used alpha collision so I can always edit the map without having to define the hitboxes of every single wall/object. The collisions didn't work as intended, and after adding a fillRect function for debugging that draws a rectangle on every collision of the ray and the map (I also removed the part that breaks out of the loop after the collision for a clearer image of what's wrong) it turns out that for some reason besides the regular collions, the raycaster detects two more collisions shifted to the right by some offset.

An image of what the map should look like next to what the raycaster sees. Everything is rendered two times more shifted to the right with some offset

This is the code for the raycaster in its current state:

local function raycast(playerX, playerY, playerAngle, FOV, RES, rayStep, rayLength)

	for i = 0, RES do
		local rayAngle = playerAngle - FOV / 2 + (i * FOV) / RES

		local raydx = math.cos(math.rad(rayAngle)) * rayStep
		local raydy = math.sin(math.rad(rayAngle)) * rayStep

		local rayProgress = 0
		local hit = false

		raySprite:moveTo(playerX, playerY)
		while (rayProgress <= rayLength) do
			raySprite:moveBy(raydx,raydy)
			if raySprite:alphaCollision(mapSprite) then
				gfx.fillRect(raySprite.x - 1, raySprite.y - 1, 2, 2) --Draws boxes on collision for debugguing
				--hit = true
				--The traveled distance would just be rayProgress here
			end
			if (hit == true) then break end
			rayProgress += rayStep
		end
	end
end

The weird thing is that I have used the same method to detect collisions between the player and the map, with the difference that they work just as intended.

playerSprite:moveBy(dx, dy)
		if playerSprite:alphaCollision(mapSprite) then
			playerSprite:moveBy(-dx, -dy)
		end

Also this is the full code right now, if it helps

import "CoreLibs/object"
import "CoreLibs/graphics"
import "CoreLibs/sprites"

local pd <const> = playdate
local gfx <const> = pd.graphics

local mapSprite = nil
local playerSprite = nil
local raySprite = nil

local FOV = 70
local RES = 100
local rayStep = 3
local rayLength = 300

local playerSpeed = 4
local rotSpeed = 5
local playerAngle = 270

local function init()
	local mapImage = gfx.image.new("images/map")
	mapSprite = gfx.sprite.new(mapImage)
	mapSprite:setCollideRect(0, 0, mapSprite:getSize())
	mapSprite:moveTo(200,120)
	mapSprite:add()

	local playerImage = gfx.image.new("images/player")
	playerSprite = gfx.sprite.new(playerImage)
	playerSprite:setCollideRect(0, 0, playerSprite:getSize())
	playerSprite:moveTo(200,120)
	playerSprite:add()

	local rayImage = gfx.image.new("images/ray")
	raySprite = gfx.sprite.new(rayImage)
	raySprite:setCollideRect(0, 0, raySprite:getSize())
	raySprite:moveTo(200,120)
	raySprite:add()
end

local function raycast(playerX, playerY, playerAngle, FOV, RES, rayStep, rayLength)

	for i = 0, RES do
		local rayAngle = playerAngle - FOV / 2 + (i * FOV) / RES

		local raydx = math.cos(math.rad(rayAngle)) * rayStep
		local raydy = math.sin(math.rad(rayAngle)) * rayStep

		local rayProgress = 0
		local hit = false

		raySprite:moveTo(playerX, playerY)
		while (rayProgress <= rayLength) do
			raySprite:moveBy(raydx,raydy)
			if raySprite:alphaCollision(mapSprite) then
				gfx.fillRect(raySprite.x - 1, raySprite.y - 1, 2, 2) --Draws boxes on collision for debugguing
				--hit = true
				--The traveled distance would just be rayProgress here
			end
			if (hit == true) then break end
			rayProgress += rayStep
		end
	end
end

init()

function pd.update()
	if pd.buttonIsPressed(pd.kButtonUp) then
		gfx.sprite.update()
		local dx = math.cos(math.rad(playerAngle)) * playerSpeed
		local dy = math.sin(math.rad(playerAngle)) * playerSpeed
		playerSprite:moveBy(dx, dy)
		if playerSprite:alphaCollision(mapSprite) then
			playerSprite:moveBy(-dx, -dy)
		end
		raycast(playerSprite.x, playerSprite.y, playerAngle, FOV, RES, rayStep, rayLength)
	end

	if pd.buttonIsPressed(pd.kButtonLeft) then
		gfx.sprite.update()
		playerAngle -= rotSpeed
		raycast(playerSprite.x, playerSprite.y, playerAngle, FOV, RES, rayStep, rayLength)
	end
	if pd.buttonIsPressed(pd.kButtonRight) then
		gfx.sprite.update()
		playerAngle += rotSpeed
		raycast(playerSprite.x, playerSprite.y, playerAngle, FOV, RES, rayStep, rayLength)
	end
end

I've tried many different things, but none of them did any help. If any more information is needed, let me know!