Hallo Community,
ich bin über meinen alten Code eines Raycasters gestoßen und dachte mir, ich teile ihn mal mit euch.
Das war damals nur ein Testprojekt, da ich verstehen wollte wie das Raycasten funktioniert.
Hier ein Post von damals: https://www.blitzforum.de/foru...=raycaster
Was geht alles?
verschiedene Wandtexturen
Boden und Decke
Kollisionen
Schattierte Seiten
Der Code ist alles am Stück geschrieben, keine Klassen/Funktionen etc. da es nur ein Test war.
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict
Const SCREEN_W:Int = 1200 Const SCREEN_H:Int = 720 Const TEX_W:Int = 128 Const TEX_H:Int = 128 Const MAP_W:Int = 24 Const MAP_H:Int = 24 Const FOV:Float = Pi*0.4
Local texWall1:TPixmap = LoadPixmap("assets/wall_1.png") Local texWall2:TPixmap = LoadPixmap("assets/wall_2.png") Local texWall3:TPixmap = LoadPixmap("assets/wall_3.png") Local texWall4:TPixmap = LoadPixmap("assets/wall_4.png")
Local texFloor1:TPixmap = LoadPixmap("assets/floor_1.png") Local texCeiling1:TPixmap = LoadPixmap("assets/ceiling_1.png")
Local player:TImage = LoadImage("assets/weapon.png")
Local drawBuffer:TPixmap = CreatePixmap(SCREEN_W, SCREEN_H, PF_RGBA8888)
Local posX:Float = 32 Local posY:Float = 12
Local dirX:Float = -1 Local dirY:Float = 0
Local planeX:Float = 0 Local planeY:Float = 0.66
Local time:Float = 0
Local oldTime:Float = 0 Local timer:TTimer = CreateTimer(60)
Local worldMap: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,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]
Graphics(SCREEN_W, SCREEN_H)
HideMouse() MoveMouse(SCREEN_W / 2, SCREEN_H / 2)
While Not (AppTerminate() Or KeyDown(KEY_ESCAPE))
Local mouseSpeedX:Int = MouseXSpeed() MoveMouse(SCREEN_W / 2, SCREEN_H / 2) MouseXSpeed()
For Local x:Int = 0 To SCREEN_W-1 Local camX:Float = 2 * x / Float(SCREEN_W) -1 Local rayDirX:Float = dirX + planeX * camX Local rayDirY:Float = dirY + planeY * camX Local mapX:Int = Int(posX) Local mapY:Int = Int(posY) Local sideDistX:Float Local sideDistY:Float Local deltaDistX:Float = Abs(1 / rayDirX) Local deltaDistY:Float = Abs(1 / rayDirY) Local perpWallDist:Float Local stepX:Int Local stepY:Int Local hit:Int Local side:Int If (rayDirX < 0) stepX = -1 sideDistX = (posX - mapX) * deltaDistX Else stepX = 1 sideDistX = (mapX + 1.0 - posX) * deltaDistX EndIf If (rayDirY < 0) stepY = -1 sideDistY = (posY - mapY) * deltaDistY Else stepY = 1 sideDistY = (mapY + 1.0 - posY) * deltaDistY EndIf While (hit = 0) If (sideDistX < sideDistY) sideDistX :+ deltaDistX mapX :+ stepX side = 0 Else sideDistY :+ deltaDistY mapY :+ stepY side = 1 EndIf If(worldMap[mapY * MAP_W + mapX] > 0) hit = 1 Wend If (side = 0) perpWallDist = (mapX - posX + (1 - stepX) / 2) / rayDirX Else perpWallDist = (mapY - posY + (1 - stepY) / 2) / rayDirY EndIf Local lineH:Int = Int(SCREEN_W / perpWallDist) Local drawStart:Int = -lineH / 2 + SCREEN_H / 2 If(drawStart < 0) drawStart = 0 Local drawEnd:Int = lineH / 2 + SCREEN_H / 2 If(drawEnd >= SCREEN_H) drawEnd = SCREEN_H - 1 Local wallX:Float If (side = 0) wallX = posY + perpWallDist * rayDirY Else wallX = posX + perpWallDist * rayDirX EndIf wallX :- Floor(wallX) Local texX:Int = Int(wallX * Float(TEX_W)) If(side = 0 And rayDirX > 0) texX = TEX_W - texX - 1 If(side = 1 And rayDirY < 0) texX = TEX_W - texX - 1 For Local y:Int = drawStart To drawEnd-1 Local d:Int = y * 256 - SCREEN_H * 128 + lineH * 128 Local texY:Int = ((d * TEX_H) / lineH) / 256 If texY < 0 Then texY = 0 If texY > TEX_H Then texY = TEX_H Local argb:Int Select (worldMap[mapY * MAP_W + mapX]) Case 1 argb = ReadPixel(texWall1, texX, texY) Case 2 argb = ReadPixel(texWall2, texX, texY) Case 3 argb = ReadPixel(texWall3, texX, texY) Case 4 argb = ReadPixel(texWall4, texX, texY) Default argb = ReadPixel(texWall1, texX, texY) End Select If (side = 1) argb = (argb Shr 1) & 8355711 WritePixel(drawBuffer, x, y, argb) Next Local floorXWall:Float Local floorYWall:Float If (side = 0 And rayDirX > 0) floorXWall = mapX floorYWall = mapY + wallX ElseIf (side = 0 And rayDirX < 0) floorXWall = mapX + 1.0 floorYWall = mapY + wallX ElseIf (side = 1 And rayDirY > 0) floorXWall = mapX + wallX floorYWall = mapY Else floorXWall = mapX + wallX floorYWall = mapY + 1.0 EndIf Local distWall:Float Local distPlayer:Float Local currentDist:Float distWall = perpWallDist distPlayer = 0.0 If (drawEnd < 0) Then drawEnd = SCREEN_H For Local y:Int = drawEnd+1 To SCREEN_H-1 currentDist = SCREEN_H / (2.0 * y - SCREEN_H) Local weight:Float = (currentDist - distPlayer) / (distWall - distPlayer) Local currentFloorX:Float = weight * floorXWall + (1.0 - weight) * posX Local currentFloorY:Float = weight * floorYWall + (1.0 - weight) * posY Local texX:Int Local texY:Int texX = Int(currentFloorX * TEX_W) Mod TEX_W texY = Int(currentFloorY * TEX_H) Mod TEX_H Local argb:Int = ReadPixel(texFloor1, texX , texY) WritePixel(drawBuffer, x, y, argb) argb:Int = ReadPixel(texCeiling1, texX, texY) WritePixel(drawBuffer, x, SCREEN_H-y, argb) Next Next DrawPixmap(drawBuffer, 0, 0) DrawImage(player, SCREEN_W / 2 - ImageWidth(player) / 2, SCREEN_H - ImageHeight(player)+2)
oldTime = time time = TimerTicks(timer) Local frameTime:Float = (time - oldTime) / 1000.0 DrawText(1.0 / frameTime, 5, 5) Local moveSpeed:Float = frameTime * 50.0 Local rotSpeed:Float = frameTime * 30.0 Local viewSpeed:Float = frameTime * mouseSpeedX * 150.0
If (KeyDown(KEY_W)) posX :+ dirX * moveSpeed posY :+ dirY * moveSpeed If(worldMap[Int(posY) * MAP_W + Int(posX + dirX * moveSpeed)] <> 0) Or (worldMap[Int(posY + dirY * moveSpeed) * MAP_W + Int(posX)] <> 0) posX :- dirX * moveSpeed posY :- dirY * moveSpeed EndIf EndIf If (KeyDown(KEY_S)) posX :- dirX * moveSpeed posY :- dirY * moveSpeed If(worldMap[Int(posY) * MAP_W + Int(posX - dirX * moveSpeed)] <> 0) Or (worldMap[Int(posY - dirY * moveSpeed) * MAP_W + Int(posX)] <> 0) posX :+ dirX * moveSpeed posY :+ dirY * moveSpeed EndIf EndIf If (KeyDown(KEY_A)) posX :+ -dirY * moveSpeed posY :+ dirX * moveSpeed If(worldMap[Int(posY) * MAP_W + Int(posX + -dirY * moveSpeed)] <> 0) Or (worldMap[Int(posY + dirX * moveSpeed) * MAP_W + Int(posX)] <> 0) posX :- -dirY * moveSpeed posY :- dirX * moveSpeed EndIf EndIf If (KeyDown(KEY_D)) posX :- -dirY * moveSpeed posY :- dirX * moveSpeed If(worldMap[Int(posY) * MAP_W + Int(posX + -dirY * moveSpeed)] <> 0) Or (worldMap[Int(posY + dirX * moveSpeed) * MAP_W + Int(posX)] <> 0) posX :+ -dirY * moveSpeed posY :+ dirX * moveSpeed EndIf EndIf If (mouseSpeedX <> 0) Local oldDirX:Float = dirX; dirX = dirX * Cos(-viewSpeed) - dirY * Sin(-viewSpeed); dirY = oldDirX * Sin(-viewSpeed) + dirY * Cos(-viewSpeed); Local oldPlaneX:Float = planeX; planeX = planeX * Cos(-viewSpeed) - planeY * Sin(-viewSpeed); planeY = oldPlaneX * Sin(-viewSpeed) + planeY * Cos(-viewSpeed); EndIf
Flip;Cls;Wend;End
Damit ihr es ausprobieren könnt, benötigt ihr die assets ebenso.
Erstellt euch einen Ordner mit dem Namen "assets" im Rootverzeichnis (wo sich die bmx-Datei befindet) und kopiert folgende Bilder hinein:
wall_1.png
wall_2.png
wall_3.png
wall_4.png
floor_1.png
ceiling_1.png
weapon.png
Die Texturen sind nicht von mir. Verwendet sie daher nicht in Projekten die ihr veröffentlichen möchtet.
Die Berechnung für Boden/Decke ist leicht fehlerhaft. Wer es hinbekommt, darf die Lösung hier gerne posten.
PS: nur im Release-Modus kompilieren, beim Debug-Modus ruckelt es.
Gruß
Trust
|