Seite 2 von 3

Verfasst: 29.10.2006 15:36
von AndyX
Update! Sprites :D

(Framerate leider nur ~45 bei 320x240 :( )

Code: Alles auswählen

Macro floor(x)
  Round(x,0)
EndMacro
Macro ColorRGB(r,g,b)
  ((r&$FF)+((g&$FF)<<8)+((b&$FF)<<16))
EndMacro
Structure Sprite
  x.f
  y.f
  texture.l
EndStructure
Structure structDist
  dist.f
  Nb.l
EndStructure

#numSprites = 18
#mapWidth = 23
#mapHeight = 23
#texWidth = 63
#texHeight = 63
w = 320
h = 240

Global Dim worldMap.l(#mapWidth,#mapHeight)
Global Dim buffer.l(w,h)
Global Dim texture.l(11,#texWidth,#texHeight)

Restore wrldmap
For j = 0 To #mapHeight
  For i = 0 To #mapWidth
    Read worldMap(i,j)
  Next i
Next j

Global Dim sprite.Sprite(#numSprites)
sprite(0)\x = 20.5
sprite(0)\y = 11.5
sprite(0)\texture = 10
sprite(1)\x = 18.5
sprite(1)\y = 4.5
sprite(1)\texture = 10
sprite(2)\x = 10
sprite(2)\y = 4.5
sprite(2)\texture = 10
sprite(3)\x = 10
sprite(3)\y = 12.5
sprite(3)\texture = 10
sprite(4)\x = 3.5
sprite(4)\y = 6.5
sprite(4)\texture = 10
sprite(5)\x = 3.5
sprite(5)\y = 20.5
sprite(5)\texture = 10
sprite(6)\x = 3.5
sprite(6)\y = 14.5
sprite(6)\texture = 10
sprite(7)\x = 14.5
sprite(7)\y = 20.5
sprite(7)\texture = 10
sprite(8)\x = 18.5
sprite(8)\y = 10.5
sprite(8)\texture = 9
sprite(9)\x = 18.5
sprite(9)\y = 11.5
sprite(9)\texture = 9
sprite(10)\x = 18.5
sprite(10)\y = 12.5
sprite(10)\texture = 9
sprite(11)\x = 21.5
sprite(11)\y = 1.5
sprite(11)\texture = 8
sprite(12)\x = 15.5
sprite(12)\y = 1.5
sprite(12)\texture = 8
sprite(13)\x = 16
sprite(13)\y = 1.8
sprite(13)\texture = 8
sprite(14)\x = 16.2
sprite(14)\y = 1.2
sprite(14)\texture = 8
sprite(15)\x = 3.5
sprite(15)\y = 2.5
sprite(15)\texture = 8
sprite(16)\x = 9.5
sprite(16)\y = 15.5
sprite(16)\texture = 8
sprite(17)\x = 10
sprite(17)\y = 15.1
sprite(17)\texture = 8
sprite(18)\x = 10.5
sprite(18)\y = 15.8
sprite(18)\texture = 8

Global Dim spriteDistance.structDist(#numSprites)
Global Dim Zbuffer.f(w)

posX.f = 8
posY.f = 5
dirX.f = -1
dirY.f = 0
planeX.f = 0
planeY.f = 0.66
time = 0
oldTime = 0

InitKeyboard()
InitSprite()
OpenScreen(w,h,32,"3D")
StartDrawing(ScreenOutput())
DrawingMode(1)
DrawText(10,10,"wird geladen...",RGB(0,255,0))
StopDrawing()
FlipBuffers()

LoadSprite(8,"barrel.bmp")
LoadSprite(0,"bluestone.bmp")
LoadSprite(1,"colorstone.bmp")
LoadSprite(2,"eagle.bmp")
LoadSprite(9,"greenlight.bmp")
LoadSprite(3,"greystone.bmp")
LoadSprite(4,"mossy.bmp")
LoadSprite(10,"pillar.bmp")
LoadSprite(5,"purplestone.bmp")
LoadSprite(6,"redbrick.bmp")
LoadSprite(7,"wood.bmp")

For i = 0 To 10
  StartDrawing(SpriteOutput(i))
  For x = 0 To #texWidth
    For y = 0 To #texHeight
      c = Point(x,y)
      texture(i,x,y) = c
    Next y
  Next x
  StopDrawing()
Next i

Repeat
  For x = 0 To w
    cameraX.f = 2 * x / w - 1
    rayPosX.f = posX
    rayPosY.f = posY
    rayDirX.f = dirX + planeX * cameraX
    rayDirY.f = dirY + planeY * cameraX
    mapx = Int(rayPosX)
    mapy = Int(rayPosY)
    sideDistX.f
    sideDistY.f
    deltaDistX.f = Sqr(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX))
    deltaDistY.f = Sqr(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY))
    perpWallDist.f
    stepX.l
    stepY.l
    hit.l = 0
    side.l
    If rayDirX < 0
      stepX = -1
      sideDistX = (rayPosX - mapx) * deltaDistX
    Else
      stepX = 1
      sideDistX = (mapx + 1.0 - rayPosX) * deltaDistX
    EndIf
    If rayDirY < 0
      stepY = -1
      sideDistY = (rayPosY - mapy) * deltaDistY
    Else
      stepY = 1
      sideDistY = (mapy + 1.0 - rayPosY) * deltaDistY
    EndIf
    While hit = 0 
      If sideDistX < sideDistY
        sideDistX + deltaDistX
        mapx + stepX
        side = 0
      Else
        sideDistY + deltaDistY
        mapy + stepY
        side = 1
      EndIf               
      If worldMap(mapx,mapy) > 0
        hit = 1
      EndIf
    Wend
    If side = 0
      perpWallDist = Abs((mapx - rayPosX + (1 - stepX) / 2) / rayDirX)
    Else
      perpWallDist = Abs((mapy - rayPosY + (1 - stepY) / 2) / rayDirY)
    EndIf
    lineHeight = Abs(Int(h / perpWallDist))
    drawStart = -lineHeight / 2 + h / 2
    If drawStart < 0
      drawStart = 0
    EndIf
    drawEnd = lineHeight / 2 + h / 2
    If drawEnd >= h
      drawEnd = h - 1
    EndIf
    texNum = worldMap(mapx,mapy) - 1
    wallX.f
    If side = 1
      wallX = rayPosX + ((mapy - rayPosY + (1 - stepY) / 2) / rayDirY) * rayDirX
    Else
      wallX = rayPosY + ((mapx - rayPosX + (1 - stepX) / 2) / rayDirX) * rayDirY
    EndIf
    wallX - floor(wallX)
    texX = Int(wallX * #texWidth)
    If(side = 0 And rayDirX > 0)
      texX = #texWidth - texX - 1
    EndIf
    If(side = 1 And rayDirY < 0)
      texX = #texWidth - texX - 1
    EndIf
    For y = drawStart To drawEnd 
      d = y * 256 - h * 128 + lineHeight * 128
      texY = ((d * #texHeight) / lineHeight) / 256
      color = texture(texNum,texX,texY)
      If side = 1
        color = (color >> 1) & 8355711
      EndIf
      buffer(x,y) = color            
    Next y
    Zbuffer(x) = perpWallDist
    floorXWall.f
    floorYWall.f
    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
    distWall.f
    distPlayer.f
    currentDist.f  
    distWall = perpWallDist
    distPlayer = 0.0
    If drawEnd < 0
      drawEnd = h
    EndIf
    For y = drawEnd + 1 To h
      currentDist = h / (2.0 * y - h)
      weight.f = (currentDist - distPlayer) / (distWall - distPlayer)
      currentFloorX.f = weight * floorXWall + (1.0 - weight) * posX
      currentFloorY.f = weight * floorYWall + (1.0 - weight) * posY
      floorTexX.l
      floorTexY.l
      floorTexX = Int(currentFloorX * #texWidth) % #texWidth
      floorTexY = Int(currentFloorY * #texHeight) % #texHeight
      buffer(x,y) = (texture(3,floorTexX,floorTexY) >> 1) & 8355711
      buffer(x,h - y) = texture(7,floorTexX,floorTexY)
    Next y 
  Next x
  
  For i = 0 To #numSprites
    spriteDistance(i)\Nb = i
    spriteDistance(i)\dist = ((posX - sprite(i)\x) * (posX - sprite(i)\x) + (posY - sprite(i)\y) * (posY - sprite(i)\y))
  Next i
  SortStructuredArray(spriteDistance(),1,OffsetOf(structDist\dist),#PB_Sort_Float)
  For i = 0 To #numSprites
    spriteX.f = sprite(spriteDistance(i)\Nb)\x - posX
    spriteY.f = sprite(spriteDistance(i)\Nb)\y - posY
    invDet.f = 1.0 / (planeX * dirY - dirX * planeY)
    transformX.f = invDet * (dirY * spriteX - dirX * spriteY)
    transformY.f = invDet * (-planeY * spriteX + planeX * spriteY)
    spriteScreenX = Int((w / 2) * (1 + transformX / transformY))
    spriteHeight = Abs(Int(h / (transformY)))
    drawStartY = -spriteHeight / 2 + h / 2
    If drawStartY < 0
      drawStartY = 0
    EndIf
    drawEndY = spriteHeight / 2 + h / 2
    If drawEndY >= h
      drawEndY = h - 1
    EndIf
    spriteWidth = Abs(Int(h / (transformY)))
    drawStartX = -spriteWidth / 2 + spriteScreenX
    If drawStartX < 0
      drawStartX = 0
    EndIf
    drawEndX = spriteWidth / 2 + spriteScreenX
    If drawEndX >= w
      drawEndX = w - 1
    EndIf
    For stripe = drawStartX To drawEndX
      texX = Int(256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * #texWidth / spriteWidth) / 256
      If transformY > 0 And stripe > 0 And stripe < w And transformY < Zbuffer(stripe) 
        For y = drawStartY To drawEndY
          d = y * 256 - h * 128 + spriteHeight * 128
          texY = ((d * #texHeight) / spriteHeight) / 256
          color = texture(sprite(spriteDistance(i)\Nb)\texture,texX,texY)
          If color <> 0
            buffer(stripe,y) = color
          EndIf
        Next y
      EndIf
    Next stripe
  Next i
  
  StartDrawing(ScreenOutput())
  For x = 0 To w-1
    For y = 0 To h-1
      Plot(x,y,buffer(x,y))
      buffer(x,y) = 0
    Next y
  Next x
  oldTime = time
  time = ElapsedMilliseconds()
  frameTime.f = (time - oldTime) / 1000.0
  DrawingMode(1)
  DrawText(0,0,StrF(1.0 / frameTime),RGB(255,255,255))
  StopDrawing()
  FlipBuffers()
  moveSpeed.f = frameTime * 5.0
  rotSpeed.f = frameTime * 3.0 
  ExamineKeyboard()
  If KeyboardPushed(#PB_Key_Up)
    If(worldMap(Int(posX + dirX * moveSpeed),Int(posY)) = #False)
      posX + dirX * moveSpeed
    EndIf
    If(worldMap(Int(posX),Int(posY + dirY * moveSpeed)) = #False)
      posY + dirY * moveSpeed
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Down)
    If(worldMap(Int(posX - dirX * moveSpeed),Int(posY)) = #False)
      posX - dirX * moveSpeed
    EndIf
    If(worldMap(Int(posX),Int(posY - dirY * moveSpeed)) = #False)
      posY - dirY * moveSpeed
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_A)
    If(worldMap(Int(posX - planeX * moveSpeed),Int(posY)) = #False)
      posX - planeX * moveSpeed
    EndIf
    If(worldMap(Int(posX),Int(posY - planeY * moveSpeed)) = #False)
      posY - planeY * moveSpeed
    EndIf
  ElseIf KeyboardPushed(#PB_Key_D)
    If(worldMap(Int(posX + planeX * moveSpeed),Int(posY)) = #False)
      posX + planeX * moveSpeed
    EndIf
    If(worldMap(Int(posX),Int(posY + planeY * moveSpeed)) = #False)
      posY + planeY * moveSpeed
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Right)
    oldDirX.f = dirX
    dirX = dirX * Cos(-rotSpeed) - dirY * Sin(-rotSpeed)
    dirY = oldDirX * Sin(-rotSpeed) + dirY * Cos(-rotSpeed)
    oldPlaneX.f = planeX
    planeX = planeX * Cos(-rotSpeed) - planeY * Sin(-rotSpeed)
    planeY = oldPlaneX * Sin(-rotSpeed) + planeY * Cos(-rotSpeed)
  EndIf
  If KeyboardPushed(#PB_Key_Left)
    oldDirX.f = dirX
    dirX = dirX * Cos(rotSpeed) - dirY * Sin(rotSpeed)
    dirY = oldDirX * Sin(rotSpeed) + dirY * Cos(rotSpeed)
    oldPlaneX.f = planeX
    planeX = planeX * Cos(rotSpeed) - planeY * Sin(rotSpeed)
    planeY = oldPlaneX * Sin(rotSpeed) + planeY * Cos(rotSpeed)
  EndIf
Until KeyboardPushed(1)

End
DataSection
wrldmap:
Data.l 8,8,8,8,8,8,8,8,8,8,8,4,4,6,4,4,6,4,6,4,4,4,6,4
Data.l 8,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,4
Data.l 8,0,3,3,0,0,0,0,0,8,8,4,0,0,0,0,0,0,0,0,0,0,0,6
Data.l 8,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6
Data.l 8,0,3,3,0,0,0,0,0,8,8,4,0,0,0,0,0,0,0,0,0,0,0,4
Data.l 8,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,6,6,0,6,4,6
Data.l 8,8,8,8,0,8,8,8,8,8,8,4,4,4,4,4,4,6,0,0,0,0,0,6
Data.l 7,7,7,7,0,7,7,7,7,0,8,0,8,0,8,0,8,4,0,4,0,6,0,6
Data.l 7,7,0,0,0,0,0,0,7,8,0,8,0,8,0,8,8,6,0,0,0,0,0,6
Data.l 7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,4
Data.l 7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,6,0,6,0,6
Data.l 7,7,0,0,0,0,0,0,7,8,0,8,0,8,0,8,8,6,4,6,0,6,6,6
Data.l 7,7,7,7,0,7,7,7,7,8,8,4,0,6,8,4,8,3,3,3,0,3,3,3
Data.l 2,2,2,2,0,2,2,2,2,4,6,4,0,0,6,0,6,3,0,0,0,0,0,3
Data.l 2,2,0,0,0,0,0,2,2,4,0,0,0,0,0,0,4,3,0,0,0,0,0,3
Data.l 2,0,0,0,0,0,0,0,2,4,0,0,0,0,0,0,4,3,0,0,0,0,0,3
Data.l 1,0,0,0,0,0,0,0,1,4,4,4,4,4,6,0,6,3,3,0,0,0,3,3
Data.l 2,0,0,0,0,0,0,0,2,2,2,1,2,2,2,6,6,0,0,5,0,5,0,5
Data.l 2,2,0,0,0,0,0,2,2,2,0,0,0,2,2,0,5,0,5,0,0,0,5,5
Data.l 2,0,0,0,0,0,0,0,2,0,0,0,0,0,2,5,0,5,0,5,0,5,0,5
Data.l 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5
Data.l 2,0,0,0,0,0,0,0,2,0,0,0,0,0,2,5,0,5,0,5,0,5,0,5
Data.l 2,2,0,0,0,0,0,2,2,2,0,0,0,2,2,0,5,0,5,0,0,0,5,5
Data.l 2,2,2,2,1,2,2,2,2,2,2,1,2,2,2,5,5,5,5,5,5,5,5,5
EndDataSection

Verfasst: 29.10.2006 15:47
von RSBasic
Hi, ich habe eine Frage zu den Beispiel. Ich habe das getestet und finde das sehr gut, aber warum nimmt man keine 640 x 480 oder höhrere Bildschirmauflösungen?

Verfasst: 29.10.2006 15:52
von AndyX
weil dann die Framerate unter 30 geht :wink: d.h. das ganze ruckelt und läuft nicht mehr flüssig.

Würde es irgendwas bringen, wenn man das ganze mit Asm optimiert? oder kann mans sonst irgendwie schneller machen?

Verfasst: 29.10.2006 15:59
von RSBasic
@AndyX
Wie, hat man leider unter PB 4.00 keine Möglichkeiten mehr als 30 Frames/sek. laufen zu bringen?

Verfasst: 29.10.2006 16:06
von AndyX
doch schon, aber die ganzen Berechnungen dauern ja auch eine Weile.

Verfasst: 29.10.2006 17:11
von Kekskiller
Theoretisch sollte man das doch mit Sprite3D optimieren können, oder? Ich meine damit, dass man die Wände als deformiertes Sprite darstellt. Man müsste nur ne Liste erstellen, wo die Wände der Entfernung vom Spieler aus gespeichert werden. Ich habe das mit meiner Vektorengine auch so gemacht - hab einfach nur die Sichtbaren mit etwas Geometrie rausgefiltert. So müsst man ja theoretisch etwas mehr Geschwindigkeit reinbringen können... Nur das Errechnen der vier Punkte der Sprite3D wäre ein wenig Rechnerei.

Wäre cool, wenn das gehen würde :allright: . Aber ist wohl auch ne ganze Menge Arbeit.

Verfasst: 29.10.2006 18:02
von Kaeru Gaman
eine optimierungsmöglichkeit wäre auch, BitBlt zu verwenden statt DirectDraw.

Verfasst: 29.10.2006 18:06
von Hellhound66
@kekskiller:
Dann kannste auch gleich richtiges 3D nutzen und die Karte das machen lassen.

@andy:
Die Bremse in deinem Code sind vor allem die Dims. Da wird jedesmal die relative Adresse ausgerechnet. Wenn du das mit direkten Speicherzugriffen machst, und unnötige Berechnungen aus den Schleifen rausmachst, kannste locker nochmal 300-800% rausholen.

Verfasst: 29.10.2006 23:07
von pg
Nicht schlecht. Die DIM's sind nicht die Bremse. Aber anstelle Plot kann mit PokeW und einem 16- bit Screen gerendert werden (ohne Bitmap konvertierung). Anstelle die Bitmaps in DIM's einzulesen ist es einfacher die Adresse des DrawingBuffer des entsprechenden Sprites zu verwenden. Bei Loadsprite sollte dann #PB_Sprite_Memory verwendet werden. So sollte es möglich sein weit mehr als 100 Frames/s zu erreichen (je nach PC). Bei meiner Engine hab ich's so gemacht.

Verfasst: 29.10.2006 23:20
von Kaeru Gaman
das ist im kern nichts anderes, als Hellhound meinte...