kisekinopureya 4520f2b9f7
All checks were successful
commit-lint / commit-lint (push) Successful in 33s
feat(tools): toggleable fps counter
2025-07-23 17:57:43 +03:00

266 lines
7.2 KiB
Go

package main
import (
"log"
"math"
"unsafe"
"github.com/veandco/go-sdl2/sdl"
"kisekinopureya.com.tr/go-raycasting/tools"
"kisekinopureya.com.tr/go-raycasting/worldMap"
)
const (
screenWidth = 640
screenHeight = 480
screenScale = 1
texWidth = 64
texHeight = 64
mapWidth = 24
mapHeight = 24
)
var posX, posY, dirX, dirY, planeX, planeY float64 = 2, 2, -1, 0, 0, 0.66
var renderFps = false
func render(renderer *sdl.Renderer, texture *sdl.Texture, pixels []uint32) {
err := texture.Update(nil, unsafe.Pointer(&pixels[0]), screenWidth*4)
if err != nil {
log.Printf("Texture update failed: %v", err)
}
// Clear renderer, copy texture, present frame
renderer.Clear()
renderer.Copy(texture, nil, nil)
renderer.Present()
}
func main() {
level := worldMap.GetMap()
if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
log.Fatalf("SDL Initialization failed: %v", err)
}
defer sdl.Quit()
window, err := sdl.CreateWindow("Raycaster", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, screenWidth, screenHeight, sdl.WINDOW_SHOWN)
if err != nil {
log.Fatalf("Window creation failed: %v", err)
}
defer window.Destroy()
renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC)
if err != nil {
log.Fatalf("Renderer creation failed: %v", err)
}
defer renderer.Destroy()
texture, err := renderer.CreateTexture(sdl.PIXELFORMAT_ARGB8888, sdl.TEXTUREACCESS_STREAMING, screenWidth, screenHeight)
if err != nil {
log.Fatalf("Texture creation failed: %v", err)
}
defer texture.Destroy()
textures, err := worldMap.LoadTextures(renderer)
if err != nil {
log.Fatalf("Texture creation failed: %v", err)
}
tools.InitFont("assets/DejaVuSans.ttf", 24)
pixels := make([]uint32, screenWidth*screenHeight)
running := true
for running {
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
switch e := event.(type) {
case *sdl.QuitEvent:
running = false
case *sdl.KeyboardEvent:
if e.Type == sdl.KEYDOWN {
moveSpeed := 0.1
rotSpeed := 0.05
switch e.Keysym.Sym {
case sdl.K_w:
if level[int(posX+dirX*moveSpeed)][int(posY)] == 0 {
posX += dirX * moveSpeed
}
if level[int(posX)][int(posY+dirY*moveSpeed)] == 0 {
posY += dirY * moveSpeed
}
case sdl.K_s:
if level[int(posX-dirX*moveSpeed)][int(posY)] == 0 {
posX -= dirX * moveSpeed
}
if level[int(posX)][int(posY-dirY*moveSpeed)] == 0 {
posY -= dirY * moveSpeed
}
case sdl.K_d:
oldDirX := dirX
dirX = dirX*math.Cos(-rotSpeed) - dirY*math.Sin(-rotSpeed)
dirY = oldDirX*math.Sin(-rotSpeed) + dirY*math.Cos(-rotSpeed)
oldPlaneX := planeX
planeX = planeX*math.Cos(-rotSpeed) - planeY*math.Sin(-rotSpeed)
planeY = oldPlaneX*math.Sin(-rotSpeed) + planeY*math.Cos(-rotSpeed)
case sdl.K_a:
oldDirX := dirX
dirX = dirX*math.Cos(rotSpeed) - dirY*math.Sin(rotSpeed)
dirY = oldDirX*math.Sin(rotSpeed) + dirY*math.Cos(rotSpeed)
oldPlaneX := planeX
planeX = planeX*math.Cos(rotSpeed) - planeY*math.Sin(rotSpeed)
planeY = oldPlaneX*math.Sin(rotSpeed) + planeY*math.Cos(rotSpeed)
case sdl.K_F1:
if renderFps {
renderFps = false
} else {
renderFps = true
}
}
}
}
}
// Floorcasting logic
for y := 0; y < screenHeight; y += screenScale {
rayDirX0 := dirX - planeX
rayDirY0 := dirY - planeY
rayDirX1 := dirX + planeX
rayDirY1 := dirY + planeY
p := y - screenHeight/2
if p == 0 {
continue // avoid division by zero
}
posZ := 0.5 * float64(screenHeight)
rowDistance := posZ / float64(p)
floorStepX := rowDistance * (rayDirX1 - rayDirX0) / float64(screenWidth)
floorStepY := rowDistance * (rayDirY1 - rayDirY0) / float64(screenWidth)
floorX := posX + rowDistance*rayDirX0
floorY := posY + rowDistance*rayDirY0
for x := 0; x < screenWidth; x++ {
cellX := int(floorX)
cellY := int(floorY)
tx := int(float64(texWidth)*(floorX-float64(cellX))) & (texWidth - 1)
ty := int(float64(texHeight)*(floorY-float64(cellY))) & (texHeight - 1)
floorX += floorStepX
floorY += floorStepY
floorTexture := 3
ceilingTexture := 6
var color uint32 = textures[floorTexture][texWidth*ty+tx]
color = (color >> 1) & 0x7F7F7F // darken
pixels[y*screenWidth+x] = color
color = textures[ceilingTexture][texWidth*ty+tx]
color = (color >> 1) & 0x7F7F7F
pixels[(screenHeight-y-1)*screenWidth+x] = color
}
}
// Raycasting logic
for x := 0; x < screenWidth; x += screenScale {
rayDirX := dirX + planeX*(2*float64(x)/float64(screenWidth)-1)
rayDirY := dirY + planeY*(2*float64(x)/float64(screenWidth)-1)
mapX, mapY := int(posX), int(posY)
deltaDistX := math.Abs(1 / rayDirX)
deltaDistY := math.Abs(1 / rayDirY)
var sideDistX, sideDistY float64
var stepX, stepY int
if rayDirX < 0 {
stepX = -1
sideDistX = (posX - float64(mapX)) * deltaDistX
} else {
stepX = 1
sideDistX = (float64(mapX) + 1.0 - posX) * deltaDistX
}
if rayDirY < 0 {
stepY = -1
sideDistY = (posY - float64(mapY)) * deltaDistY
} else {
stepY = 1
sideDistY = (float64(mapY) + 1.0 - posY) * deltaDistY
}
var perpWallDist float64
hit := false
var side int
for !hit {
if sideDistX < sideDistY {
mapX += stepX
perpWallDist = sideDistX
sideDistX += deltaDistX
side = 0
} else {
mapY += stepY
perpWallDist = sideDistY
sideDistY += deltaDistY
side = 1
}
if level[mapX][mapY] > 0 {
hit = true
}
}
if hit {
lineHeight := int(screenHeight / perpWallDist)
drawStart := -lineHeight/2 + screenHeight/2
if drawStart < 0 {
drawStart = 0
}
drawEnd := lineHeight/2 + screenHeight/2
if drawEnd >= screenHeight {
drawEnd = screenHeight - 1
}
wallType := level[mapX][mapY] - 1
var wallX float64 //where exactly the wall was hit
if side == 0 {
wallX = posY + perpWallDist*rayDirY
} else {
wallX = posX + perpWallDist*rayDirX
}
wallX -= math.Floor(wallX)
//x coordinate on the texture
var texX int = int(wallX * float64(texWidth))
if side == 0 && rayDirX > 0 {
texX = texWidth - texX - 1
}
if side == 1 && rayDirY < 0 {
texX = texWidth - texX - 1
}
var step float64 = 1.0 * float64(texHeight) / float64(lineHeight)
// Starting texture coordinate
var texPos float64 = float64(drawStart-screenHeight/2+lineHeight/2) * step
// Draw vertical line
for y := drawStart; y < drawEnd; y++ {
var texY int = int(texPos) & (texHeight - 1)
texPos += step
var color uint32 = textures[wallType][texHeight*texY+texX]
if side == 1 {
color = (color >> 1) & 8355711
}
pixels[y*screenWidth+x] = color
}
}
}
if renderFps {
tools.FpsCounter(pixels, screenWidth, screenHeight)
}
// Render updated scene
render(renderer, texture, pixels)
}
}