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 } } } } } }