a
This commit is contained in:
commit
9a3bc05131
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
||||
module kisekinopureya.com.tr/go-raycasting
|
||||
|
||||
go 1.24.1
|
||||
|
||||
require github.com/veandco/go-sdl2 v0.4.40
|
||||
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/veandco/go-sdl2 v0.4.40 h1:fZv6wC3zz1Xt167P09gazawnpa0KY5LM7JAvKpX9d/U=
|
||||
github.com/veandco/go-sdl2 v0.4.40/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
||||
259
main.go
Normal file
259
main.go
Normal file
@ -0,0 +1,259 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
72
worldMap/worldMap.go
Normal file
72
worldMap/worldMap.go
Normal file
@ -0,0 +1,72 @@
|
||||
package worldMap
|
||||
|
||||
const (
|
||||
mapWidth = 24
|
||||
mapHeight = 24
|
||||
texWidth = 64
|
||||
texHeight = 64
|
||||
)
|
||||
|
||||
var level = [mapWidth][mapHeight]int{
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 4, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 4, 0, 0, 0, 0, 5, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 4, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 4, 0, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
}
|
||||
|
||||
func GetMap() [24][24]int {
|
||||
return level
|
||||
}
|
||||
|
||||
var texture = make([][]uint32, 8)
|
||||
|
||||
func GetTextures() [][]uint32 {
|
||||
for i := range texture {
|
||||
texture[i] = make([]uint32, texWidth*texHeight)
|
||||
}
|
||||
var tex0, tex5 int
|
||||
for x := range texWidth {
|
||||
for y := range texHeight {
|
||||
xorcolor := (x * 256 / texWidth) ^ (y * 256 / texHeight)
|
||||
ycolor := y * 256 / texHeight
|
||||
xycolor := y*128/texHeight + x*128/texWidth
|
||||
if x != y && x != texWidth-y {
|
||||
tex0 = 1
|
||||
} else {
|
||||
tex0 = 0
|
||||
}
|
||||
texture[0][texWidth*y+x] = uint32(65536 * 254 * tex0) //flat red texture with black cross
|
||||
texture[1][texWidth*y+x] = uint32(xycolor + 256*xycolor + 65536*xycolor) //sloped greyscale
|
||||
texture[2][texWidth*y+x] = uint32(256*xycolor + 65536*xycolor) //sloped yellow gradient
|
||||
texture[3][texWidth*y+x] = uint32(xorcolor + 256*xorcolor + 65536*xorcolor) //xor greyscale
|
||||
texture[4][texWidth*y+x] = uint32(256 * xorcolor)
|
||||
if x%16 != 0 && y%16 != 0 {
|
||||
tex5 = 1
|
||||
} else {
|
||||
tex5 = 0
|
||||
} //xor green
|
||||
texture[5][texWidth*y+x] = uint32(65536 * 192 * tex5) //red bricks
|
||||
texture[6][texWidth*y+x] = uint32(65536 * ycolor) //red gradient
|
||||
texture[7][texWidth*y+x] = uint32(128 + 256*128 + 65536*128) //flat grey texture
|
||||
}
|
||||
}
|
||||
return texture
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user