260 lines
7.1 KiB
Go
260 lines
7.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
worldMap "kisekinopureya.com.tr/go-raycasting/worldMap"
|
|
)
|
|
|
|
const (
|
|
screenWidth = 640
|
|
screenHeight = 480
|
|
fontPath = "assets/test.ttf"
|
|
fontSize = 16
|
|
debug = true
|
|
texWidth = 64
|
|
texHeight = 64
|
|
)
|
|
|
|
func verLine(x int32, drawStart int32, drawEnd int32, color sdl.Color, window *sdl.Window) {
|
|
surface, err := window.GetSurface()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
for y := drawStart; y < drawEnd; y++ {
|
|
pixel := sdl.MapRGBA(surface.Format, color.R, color.G, color.B, color.A)
|
|
surface.FillRect(&sdl.Rect{X: x, Y: y, W: 1, H: 1}, pixel)
|
|
}
|
|
window.UpdateSurface()
|
|
}
|
|
|
|
func main() {
|
|
|
|
level := worldMap.GetMap()
|
|
|
|
var buffer [screenHeight][screenWidth]uint32
|
|
texture := worldMap.GetTextures()
|
|
var renderer *sdl.Renderer
|
|
|
|
if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
|
|
panic(err)
|
|
}
|
|
defer sdl.Quit()
|
|
|
|
window, err := sdl.CreateWindow("go raycasting", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, screenWidth, screenHeight, sdl.WINDOW_SHOWN)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer window.Destroy()
|
|
|
|
renderer, err = sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
var posX float64 = 3 //22 //x and y start position
|
|
var posY float64 = 4 //12
|
|
|
|
var dirX float64 = -1
|
|
var dirY float64 = 0 //initial direction vector
|
|
|
|
var planeX float64 = 0
|
|
var planeY float64 = 0.66 //the 2d raycaster version of camera plane
|
|
|
|
var time float64 = 0 //time of current frame
|
|
var oldTime float64 = 0 //time of previous frame
|
|
|
|
running := true
|
|
for running {
|
|
for x := range screenWidth {
|
|
var cameraX float64 = (float64)(2*x/screenWidth - 1)
|
|
var rayDirX = dirX + planeX*cameraX
|
|
var rayDirY = dirY + planeY*cameraX
|
|
var mapX int = int(posX)
|
|
var mapY int = int(posY)
|
|
|
|
var sideDistX float64
|
|
var sideDistY float64
|
|
|
|
var deltaDistX float64
|
|
if rayDirX == 0 {
|
|
deltaDistX = 1e30
|
|
} else {
|
|
deltaDistX = math.Abs(1 / rayDirX)
|
|
}
|
|
|
|
var deltaDistY float64
|
|
if rayDirY == 0 {
|
|
deltaDistY = 1e30
|
|
} else {
|
|
deltaDistY = math.Abs(1 / rayDirY)
|
|
}
|
|
|
|
var perpWallDist float64
|
|
|
|
var stepX int
|
|
var stepY int
|
|
|
|
var hit int = 0 //was there a wall hit?
|
|
var side int //was a NS or a EW wall hit?
|
|
//calculate step and initial sideDist
|
|
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
|
|
}
|
|
//perform DDA
|
|
for hit == 0 {
|
|
//jump to next map square, either in x-direction, or in y-direction
|
|
if sideDistX < sideDistY {
|
|
sideDistX += deltaDistX
|
|
mapX += stepX
|
|
side = 0
|
|
} else {
|
|
sideDistY += deltaDistY
|
|
mapY += stepY
|
|
side = 1
|
|
}
|
|
//Check if ray has hit a wall
|
|
if level[mapX][mapY] > 0 {
|
|
hit = 1
|
|
}
|
|
}
|
|
|
|
if side == 0 {
|
|
perpWallDist = (sideDistX - deltaDistX)
|
|
} else {
|
|
perpWallDist = (sideDistY - deltaDistY)
|
|
}
|
|
|
|
var lineHeight int = (int)(screenHeight / perpWallDist)
|
|
|
|
var pitch int = 100
|
|
|
|
//calculate lowest and highest pixel to fill in current stripe
|
|
var drawStart int = -lineHeight/2 + screenHeight/2 + pitch
|
|
if drawStart < 0 {
|
|
drawStart = 0
|
|
}
|
|
var drawEnd int = lineHeight/2 + screenHeight/2 + pitch
|
|
if drawEnd >= screenHeight {
|
|
drawEnd = screenHeight - 1
|
|
}
|
|
|
|
var texNum int = 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))
|
|
|
|
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
|
|
}
|
|
|
|
step := 1.0 * float64(texHeight) / float64(lineHeight)
|
|
// Starting texture coordinate
|
|
texPos := (float64(drawStart) - float64(pitch) - float64(screenHeight)/2 + float64(lineHeight)/2) * step
|
|
for y := drawStart; y < drawEnd; y++ {
|
|
// Cast the texture coordinate to integer, and mask with (texHeight - 1) in case of overflow
|
|
texY := int(texPos) & (texHeight - 1)
|
|
texPos += step
|
|
color := texture[texNum][texHeight*texY+texX]
|
|
//make color darker for y-sides: R, G and B byte each divided through two with a "shift" and an "and"
|
|
if side == 1 {
|
|
color = (color >> 1) & 8355711
|
|
}
|
|
buffer[y][x] = color
|
|
}
|
|
|
|
//draw the pixels of the stripe as a vertical line
|
|
for y := range screenHeight {
|
|
for x := range screenWidth {
|
|
renderer.SetDrawColor((uint8(buffer[y][x]>>16) & 255), uint8((buffer[y][x]>>8)&255), uint8(buffer[y][x]&255), uint8((buffer[y][x]>>24)&255))
|
|
renderer.DrawPoint(int32(x), int32(y))
|
|
}
|
|
}
|
|
renderer.Present()
|
|
|
|
oldTime = time
|
|
time = float64(sdl.GetTicks64())
|
|
var frameTime = (time - oldTime) / 1000.0
|
|
var moveSpeed float64 = frameTime * 5.0 //the constant value is in squares/second
|
|
var rotSpeed float64 = frameTime * 3.0
|
|
fmt.Println(1.0 / frameTime)
|
|
|
|
window.UpdateSurface()
|
|
|
|
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
|
switch e := event.(type) {
|
|
case *sdl.QuitEvent: // NOTE: Please use `*sdl.QuitEvent` for `v0.4.x` (current version).
|
|
println("Quit")
|
|
running = false
|
|
break
|
|
case *sdl.KeyboardEvent:
|
|
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
|
|
}
|
|
break
|
|
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
|
|
}
|
|
break
|
|
case sdl.K_d:
|
|
var oldDirX float64 = dirX
|
|
dirX = dirX*math.Cos(-rotSpeed) - dirY*math.Sin(-rotSpeed)
|
|
dirY = oldDirX*math.Sin(-rotSpeed) + dirY*math.Cos(-rotSpeed)
|
|
var oldPlaneX float64 = planeX
|
|
planeX = planeX*math.Cos(-rotSpeed) - planeY*math.Sin(-rotSpeed)
|
|
planeY = oldPlaneX*math.Sin(-rotSpeed) + planeY*math.Cos(-rotSpeed)
|
|
fmt.Println("rotating right")
|
|
break
|
|
case sdl.K_a:
|
|
var oldDirX float64 = dirX
|
|
dirX = dirX*math.Cos(rotSpeed) - dirY*math.Sin(rotSpeed)
|
|
dirY = oldDirX*math.Sin(rotSpeed) + dirY*math.Cos(rotSpeed)
|
|
var oldPlaneX float64 = planeX
|
|
planeX = planeX*math.Cos(rotSpeed) - planeY*math.Sin(rotSpeed)
|
|
planeY = oldPlaneX*math.Sin(rotSpeed) + planeY*math.Cos(rotSpeed)
|
|
fmt.Println("rotating left")
|
|
break
|
|
case sdl.K_ESCAPE:
|
|
running = false
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|