Perspektive ohne Krümmung im Raycaster

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

Also... auf jeden Fall holt ihr mich gerade in den Bereich der Möglichkeiten zurück, vor allem was vorberechnen angeht. Anscheinden bin ich abgestumpft :| .

@Kaeru: Falsch. Das lässt sich schlecht realisieren, da ich z.b. auch negative Gradzahlen abfrage, bzw. den normalen 0 bis 2PI-Bereich über-, oder unterschreite. In Quickbasic konnte ich das immer recht gut mi DIM(-360 TO 360) oder so erledigen, aber hier kommen für mich zuviele Umrechnungen dazu, also ein für mich momentan zu großer Aufwand (ja, ich weiß, Performace-technisch wahrscheinlich interessant auszutesten, aber es gibt auch noch andere Sachen, die ich verbessern könnte und die vorerst schneller zu realisieren sind). Aber wenn ich mir das so ansehe, ist es vielleicht gut, das später aufzugreifen.

@PI und Konstante: Das ist mir eigentlich relativ egal, da ich mit beiden Varianten keine Verbesserung des Geschwindigkeit erlangt habe. Ach übrigens rufe ich die Funktion sowieso nur in der Steuerungsschleife auf, also ist das wophl kaum das große Performance-Problem.

@AndyX: Das Tutorial kenne ich, daraus hab ich ja hier und jetzt diese "quick'n dirty"-Vorlage geschrieben, entsprechend nicht mit den Funktionen dort. Aber du hast recht, es sollte viel schneller gehen, diese Wände "anzuspringen", als dass alle selbst berechnet werden. Entweder ich baue das ganze so ein, oder ich lege einfach eine größeren Spungwert für "dist+1" ein.

@all: Wie wird das dann aber z.b. bei DOOM gemacht? Dort können auch schräge Wände benutzt werden, es wird ja kein Raster verwendet, in dass sich das ganze einpasst. Denn könnte ich auch bei meinen kleinen Maßstäben bleiben, würde aber nur kleine, miteinandergekoppelte Räume machen. Der Editor ist dafür kein Problem, schließlich kann ich das ja auch mit einfach Vektoren machen. Nur wird sich da das weiter oben angesprochene Rastersystem sich da nicht gut machen. Was ist euer Rat?
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> Aber wenn ich mir das so ansehe, ist es vielleicht gut, das später aufzugreifen.

kleiner tipp:

wenn du dein array nach einer 2er-potenz dimensionierst,
also 256,512,1024 oder 2048 für den vollkreis,
dann musst du zwar den winkel anders behandeln,
(im endeffekt nur den faktor ändern, nämlich anstatt pi/180 einfach pi/512 für 1024)
dann kann dein winkel jeden long-wert annehmen, und du greifst mit
SinArray(Winkel & 1023) darauf zu... ;)


...warum soll denn ein vollkreis nich 1024° haben...?

alles ne frage der definition, die 360° kommen eh aus der mystik...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

Darum gings mir in der Regel eigentlich nicht, sondern um das Umwandeln der negativen Werte. Das hatte ich schonmal in meine Spiel "Tricorne" verwendet, aber das es nicht ganz funktionierte kann man daran sehen, dass die Gegner ab und zu einfach nach unten trudelten... Aber trotzdem danke für die Info ;) .

Ich hab mir einfach mal die Vorberechnungen vorgenommen, und siehe da: Es funktioniert anstandslos und fix. Jetzt muss ich nur noch die Sache mit dem Sinus-Vorberechnen, aber das bekomm ich auch noch alles unter einen Hut. Ich bedanke mich für eure -wie immer- kompetente Hilfe!

Code: Alles auswählen

Global mapx.l, mapy.l, mapz.l
Global fps.l, time.l, screenDC.l

Global playerx.l, playery.l, playerz.f
Global playerfov.l, playermove.l, playerturn.l

Global screenx.l, screeny.l, screenwallfactor.l, screenx2.l, screeny2.l

Global flag_lightbreak.b

#PI = 3.141592
Procedure.f atosin(angle.w)
  s.f = (#PI / 180) * angle
  ProcedureReturn s
EndProcedure


;*************************
#std_wall_height_percent = 15.4167
;*************************


flag_lightbreak = #True


screenx = 320
screenx2 = screenx/2
screeny = 240
screeny2 = screeny/2
screenwallfactor = screeny + (#std_wall_height_percent / 100) * screeny

mapz = 32
mapx = 10*mapz
mapy = 10*mapz

playerx = 1*mapz
playery = 1*mapz
playerz = atosin(85)

playerfov = atosin(45)
playermove = mapz / 5
playerturn = 5

Dim map.l(mapx,mapy)


#color_wall = $999999

Procedure cast(z,distlen,correction.f);, angle.f) ;"correction" ist die korrekturvariable der perspektive
  Protected pix.f, color.l
  pix.f = mapz / distlen * screenwallfactor 
  pix.f / correction
  Box(z,screeny2-Int(pix)/2, 1,Int(pix), #color_wall)
EndProcedure

Procedure render()
  Protected angle.f, dist.l
  Protected rx.l, ry.l, z.l
  Protected pfovhalf.f, astep.f
  Protected leftsidedir.f ,rightsidedir.f ;vorberechnung der gradanzahl
  Protected anglesin.f, anglecos.f ;vorberechnung des sinus' und cosinus'
  
  pfovhalf.f = playerfov / 2
  astep.f = playerfov / screenx
  
  angle = playerz - pfovhalf
  
  For z=0 To screenx-1
    angle + astep
    dist=0
    leftsidedir = angle - playerz ;gradanzahl für die linke seite vorberechnen...
    rightsidedir = playerz - angle;gradanzahl für dierechte seite vorberechnen...
    anglesin = Sin(angle)
    anglecos = Cos(angle)
    Repeat
      dist+1
      rx = playerx + anglesin * dist
      ry = playery + anglecos * dist
      If rx>=0 And ry>=0 And rx<mapx And ry<mapy
          If map(rx,ry) = 1
            If z <= screenx2 - 1
              c.f = Cos(leftsidedir)
            ElseIf z >= screenx2
              c.f = Cos(rightsidedir)
            EndIf
            cast(z, dist, c.f)
            Break
          EndIf
      Else
        Break
      EndIf
    ForEver
  Next
EndProcedure

Procedure load()
  For zy=0 To mapy
    For zx=0 To mapx
        If zy=0 Or zy=mapx-1 Or zx=0 Or zx=mapy-1
          map(zx, zy) = 1
        EndIf
    Next
  Next
EndProcedure

load()
InitSprite()
EP_InitFXLib()
InitKeyboard()

OpenWindow(0,0,0,screenx,screeny,#PB_Window_SystemMenu, "rm3")
OpenWindowedScreen(WindowID(), 0,0, screenx,screeny, 0,0,0)
;OpenScreen(screenx,screeny,32,"rm3")

Repeat
  event = WindowEvent()
  ClearScreen(0,0,0)
  ExamineKeyboard()
  
  If KeyboardPushed(#PB_Key_Left)
    playerz - atosin(playerturn)
  ElseIf KeyboardPushed(#PB_Key_Right)
    playerz + atosin(playerturn)
  EndIf
  
  If KeyboardPushed(#PB_Key_Up)
    playerx + (Sin(playerz) * playermove)
    playery + (Cos(playerz) * playermove)
  ElseIf KeyboardPushed(#PB_Key_Down)
    playerx - (Sin(playerz) * playermove)
    playery - (Cos(playerz) * playermove)
  EndIf
  
  If KeyboardReleased(#PB_Key_PageUp)
    playerfov + 5
  ElseIf KeyboardPushed(#PB_Key_PageDown)
    playerfov - 5
  EndIf
  
  screenDC=StartDrawing(ScreenOutput())
    time=ElapsedMilliseconds()
    render()
    Debug ElapsedMilliseconds()-time
    DrawText("ANGLE:" + Str(playerz/(#PI/180)) + "-FPS:" + Str(EP_FPS()))
  StopDrawing()
  
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape) Or event=#PB_Event_CloseWindow
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

nur nebenbei....
das AND funktioniert auch bei negativen werten anstandslos... ;)
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

?
Also wenn ich das jetzt richtig verstanden habe, sollte hierbei theoretisch ein Winkel rauskommen und keine 0... Denn ich hab ja mein Array mit den 1024 Feldern, hab atosin auf 512 umgestellt und verwende dafür "anstandslo" -wie du behauptest- eine negative Zahl...

Code: Alles auswählen

#PI = 3.141592
Procedure.f atosin(angle.w)
  s.f = (#PI / 512) * angle
  ProcedureReturn s
EndProcedure

Dim s(1024)
Dim c(1024)
For z=0 To 512
s(z)=Sin(atosin(z))
c(z)=Cos(atosin(z))
Next

Debug s(-475 & 1024)
Tut mir leid, aber daraus werde ich jetzt pberhaupt nicht schlau... Zumal doch & sowieso theoretisch nur 0 oder 1 ausgibt.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

äh... nich & 1024... das bit is uninteressant...

&1023 um die unteren bits anzusprechen

damit erhältst du praktisch Winkel modulo 1024... nur viel viel schneller

dein array richtest du von 0 bis 1023 ein

0 = 0° ( 1024 wäre 360° )
256 = 90°
512 = 180°
768 = 270°

usw.usf.

das stimmt bei dir ja so... das array müsste funzen...
[edit]
äh.. nein... mach mal 0 to 1023


außerdem kannst du den Cos aus dem gleichen array holen wie den Sin

Code: Alles auswählen

x = SinArray(Winkel & 1023)
y = SinArray((Winkel+256) & 1023)
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

Du kannst sagen, was du willst, da kommt trotzdem nur 0 oder 1 raus. Das dürfte dann theoretisch auch nur ein 2-Feld-Array sein. Kann es sein, dass du da einen einfachen Logikfehler drinn hast? Egal, wie du den AND-Operator verwendest, z.b. in deinem Beispiel (Winkel & 1023) kommt auch nur 0 oder 1 raus...

Edit: MODULA ist ja wieder was ganz anderes. Sprich dich aus!
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

nein... bei AND 1023 kommen zahlen von 0 bis 1023 raus.

denn:

1023 = 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 + 512

also damit prüfe ich die 10 untersten bits auf einmal

also erhalte ich durch Zahl&1023 eben das gleiche wie Zahl%1024

es funktioniert eben nur mit zweierpotenzen

a % 2^x

geht schneller mit

a & (2^x-1)
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

Ach, ich Dähmlack, von wegen alles richtig, ich hab nur vergessen, dem Array Float als Datentyp zu geben... Jaja, ist schon gut, ich seh meinen Fehler ein.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

argl.. das hab ich grad überlesen...

ich dachte schon, das wär ein cast-problem, weil ja ne schleifenvariable int sein muss...

aber durch deine proc wärs ja gelöst gewesen...

geht btw auch, wenn man die #pi als erstes, und die schleifenvariable als letztes schreibt...

dann wird der ausdruck float-gecastet...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Antworten