Orientierungspunkt einer "Kamera" mittig platziere

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

M0rgenstern

Betreff: Orientierungspunkt einer "Kamera" mittig platziere

BeitragSo, März 04, 2012 19:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo Community,
Ich stehe jetzt seit zwei Tagen extrem auf dem Schlauch und bräuchte mal einen anständigen Schubser um darunter zu kommen.
Undzwar: Ich bin dabei soetwas wie eine Kamera in 2D zu programmieren. Also ein Objekt, dass bewegt werden kann und das somit den sichtbaren Teil des Spielgeschehens anzeigt. Alles außerhalb des Kamerabereiches wird nicht gezeichnet (und unter Umständen auch nicht berechnet).
Das funktioniert auch soweit ganz gut.
Aber: Der, ich nenne es mal Orientierungspunkt, der Kamera liegt in der linken oberen Bildschirmecke.
Das heißt, um den Bildschirminhalt so angezeigt zu bekommen, wie ich ihn ohne Kamera angezeigt bekäme, muss ich die Kamera mit den Koordinaten X=0 und Y=0 initialisieren und nicht mit Bildschirmbreite/2 und Bildschirmhöhe/2.
Letzteres wäre aber nötig, denn: Die Kamera kann an ein Objeckt gehangen werden, damit sie automatisch auf diesem Objekt fokussiert bleibt und sich somit mit dem Objekt mitbewegt.
Zeichnet man dann dieses Objekt korrekt, so befindet es sich oben links in der Bildschirmecke und nicht in der Bildschirmmitte (ja, man könnte die Koordinaten beim Zeichnen einfach auf die Bildschirmmitte setzen, aber das ist nicht Sinn und Zweck der Sache).

Die Klasse für die Kamera sieht momentan so aus:
BlitzMax: [AUSKLAPPEN]
Type TCamera
Field _v2dPosition:TVector2D 'Position der Kamera
Field _v2dSize:TVector2D 'Größe der Kamera
Field _v2dMovementSpeed:TVector2D 'Geschwindigkeit der Kamera
Field _tdAttachedDrone:TDrone 'Objekt dem gefolgt wird.

Method Position:TVector2D()
Return _v2dPosition
End Method

Method SetPosition(pv2dPosition:TVector2D)
_v2dPosition = pv2dPosition
End Method

Method Size:TVector2D()
Return _v2dSize
End Method

Method SetSize(pv2dSize:TVector2D)
_v2dSize = pv2dSize
End Method

Method MovementSpeed:TVector2D()
Return _v2dMovementSpeed
End Method

Method SetMovementSpeed(pv2dMovementSpeed:TVector2D)
_v2dMovementSpeed = pv2dMovementSpeed
End Method

'Kamera zum Steuern mit den Pfeiltasten erstellen
Function Create:TCamera(pv2dPosition:TVector2D, pv2dMovementSpeed:TVector2D, pv2dSize:TVector2D)
Local cam:TCamera = New TCamera

Local v2dPos:TVector2D = TVector2D.Create(pv2dPosition.X(), pv2dPosition.Y())
Local v2dSpeed:TVector2D = TVector2D.Create(pv2dMovementSpeed.X(), ..
pv2dMovementSpeed.Y())
Local v2dSize:TVector2D = TVector2D.Create(pv2dSize.X(), pv2dSize.Y())

cam.SetPosition(v2dPos)
cam.SetMovementSpeed(v2dSpeed)
cam.SetSize(v2dSize)
cam._tdAttachedDrone = Null

Return cam
End Function

'Kamera erstellen die einem Objekt folgt
Function CreateAttached:TCamera(pDrone:TDrone, pv2dSize:TVector2D)
Local cam:TCamera = New TCamera
Local v2dSize:TVector2D = TVector2D.Create(pv2dSize.X(), pv2dSize.Y())

cam.SetSize(v2dSize)
cam.SetPosition(TVector2D.Zero())
cam.Position().SetX(pDrone.fX)
cam.Position().SetY(pDrone.fY)
cam.SetMovementSpeed(TVector2D.Zero())
cam._tdAttachedDrone = pDrone

Return cam
End Function

'Die Position eines Objektes in Abhängigkeit von der Kamera berechnen.
'An dieser berechneten Position wird das Objekt dann gezeichnet.
Method CalculateWorldPosition:TVector2D(pv2dObjectPosition:TVector2D)
Local v2dWorldPos:TVector2D = TVector2D.Create(pv2dObjectPosition.X(), pv2dObjectPosition.Y())
Local v2:TVector2D = TVector2D.Create(Position().X(), Position().Y()) 'Position der Kamera zwischenspeichern
v2dWorldPos.Sub(v2) 'Vektor subtrahieren
Return v2dWorldPos
End Method

'Ob das Objekt im sichtbaren Bereich liegt und somit gezeichnet werden darf.
Method MayBeDrawed:Byte(pv2dObjectWorldPosition:TVector2D, pv2dObjectSize:TVector2D)
If (pv2dObjectWorldPosition.X() >= - (pv2dObjectSize.X() / 2.0) And pv2dObjectWorldPosition.X() <= (Size().X() + pv2dObjectSize.X() / 2.0)) Then
If(pv2dObjectWorldPosition.Y() >= - (pv2dObjectSize.Y() / 2.0) And pv2dObjectWorldPosition.Y() <= (Size().Y() + pv2dObjectSize.Y() / 2.0)) Then
Return True
EndIf
End If
Return False
End Method

'Bewegt die Kamera mit den Pfeiltasten
Method Move()
If(KeyDown(KEY_UP)) Then
Position().SubY(CalcFrameIndependentSpeed(MovementSpeed().Y()))
EndIf
If(KeyDown(KEY_DOWN)) Then
Position().AddY(CalcFrameIndependentSpeed(MovementSpeed().Y()))
EndIf
If(KeyDown(KEY_LEFT)) Then
Position().SubX(CalcFrameIndependentSpeed(MovementSpeed().X()))
EndIf
If(KeyDown(KEY_RIGHT)) Then
Position().AddX(CalcFrameIndependentSpeed(MovementSpeed().X()))
EndIf
End Method

'Entscheidet was mit der Kamera passieren soll.
Method Update()
If(_tdAttachedDrone <> Null) Then
Position().SetX(_tdAttachedDrone.fX)
Position().SetY(_tdAttachedDrone.fY)
Else
Move()
EndIf
End Method
End Type


Ich denke, dass die Kommentare das ganze erklären (wenn nicht fragt nach).
(Und ja, es fehlt ein Getter/Setter und der Code ist noch nicht ganz aufgeräumt. Das mache ich wenn die Klasse funktioniert. Dann schreibe ich sie nochmal schön neu.)

Ich weiß, dass die Lösung dazu ganz simple Mathematik sein muss. Aber ich komm einfach nicht drauf, was ich wo anders berechnen muss.
Es gibt übrigens noch einen Grund, aus dem ich den Bezugspunkt der Kamera mittig platzieren möchte: Man kann ja die Größe des sichtbaren Bereiches angeben. Das heißt momentan ist es so, dass nur rechts und unten ein Rand sein kann. Es soll aber auch möglich sein, dass es links und oben einen Rand gibt, was so ja momentan nicht funktioniert.

Ich hoffe, jemand wird schlau aus meinem Gefasel und kann mir helfen.
Wäre wirklich super.

Lg, M0rgenstern
 

PhillipK

BeitragSo, März 04, 2012 19:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Da du ja in Blitzmax programmierst, würde ich ogl einbeziehen.

Ob es mit der DirectX schnittstelle etwas vergleichbares gibt, weiß ich nicht. Allerdings:
BlitzMax: [AUSKLAPPEN]
Function StartOrthoGL(Width:Int, Height:Int, depth:Int = 0, hertz:Int = 60)
EndGraphics()
SetGraphicsDriver(GLMax2DDriver())
'GLGraphics(Width, Height, depth, hertz) 'OpenGL fenster initialisieren - danke blitzmax! :)
Graphics(Width, Height, depth, hertz)'mod by annixa (für max2d kompatibilität)

glMatrixMode(GL_PROJECTION) ' Projektionsmatrix auswählen.
glLoadIdentity() 'Zurücksetzen der Matrix

glOrtho(-Width / 2, Width / 2, Height / 2, -Height / 2, -4096, 4096)

glMatrixMode(GL_MODELVIEW)

End Function

ist eine Funktion, die ich sehr häufig verwende. Sie ersetzt den Graphics aufruf und setzt den 0 punkt in die mitte des Bildschirms. Ich persönlich finde es so angenehmer, obgleich man für Gui etc eine eigene Matrix nutzen sollte, oder zumindest den glOrtho aufruf erneut tätitgen, um den nullpunkt nach oben/links zu setzen.

Eine andere lösung die "einfach" ist, fällt mir grade nicht ein.
Ausser eventuell 2 Const zu setzen (mit den werten width/2 und height/2) und diese von allem zu zeichnenden abzuziehen. (oder zu addieren? ich weiß es grade nicht Very Happy kann nicht denken^^)

Ps: Diese funktion hab ich grade aus Annixa's und meinem BCC57 geklaubt. Ich verwende pur ogl, sie brauchte allerdings auch zugriff auf Max2d für die GUI, deshalb der 'mod' mit manuellem Treiber setzen. Oderso. Keine ahnung mehr Very Happy

ZEVS

BeitragSo, März 04, 2012 19:30
Antworten mit Zitat
Benutzer-Profile anzeigen
@PhillipK (und damit auch Annixa): Du solltest dir den Befehl SetOrigin mal anschauen, vielleicht hilft das...
OpenGL ist eine ganz gute Idee. Mit glTranslatef kannst du den Origin in die Mitte verschieben und dann mit glRotatef rotieren. Damit lagerst du die Rechnung an die GPU aus, was auch Performance spart.
BlitzMax: [AUSKLAPPEN]
SetGraphicsDriver GLMax2DDriver()
Graphics 800, 600
glTranslatef 400, 300, 0 '<- Origin
Local timer:TTimer = CreateTimer(60)
Local rotation# = 0.0
Repeat
WaitTimer timer
rotation :+ 1
SetOpenGLRotation rotation
Cls
DrawText "Hello World", 0, 0
Flip 0
Until KeyHit(KEY_ESCAPE) Or AppTerminate()

Function SetOpenGLRotation(rot#)
Global rotation#
glRotatef rot-rotation, 0, 0, 1
rotation = rot
End Function

Der Mainloop sollte auch ohne OpenGL-Verständnisse verständlich sein.

ZEVS

Xeres

Moderator

BeitragSo, März 04, 2012 19:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn die Kamera auf 0,0 eingestellt ist, muss sie 0,0 in der Mitte anzeigen. Also ist der Offset -Size/2.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

M0rgenstern

BeitragSo, März 04, 2012 22:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Hey Leute.
Vielen Dank für die Antworten.

@PhillipK und @ ZEVS:
Mit openGL hab ich mich bisher noch nie beschäftigt.
Ich muss auch sagen, dass ich finde, es wäre ein wenig Overkill dafür OGL zu benutzen. Könnte auch an mir liegen, ich seh nicht, welche Vorteile das allgemein bringen würde.

@Xeres:
Dankeschön. Genau das war es.
Keine Ahnung, wie ich so sehr auf dem Schlauch stehen konnte.

Lg, M0rgenstern
 

PhillipK

BeitragSo, März 04, 2012 23:10
Antworten mit Zitat
Benutzer-Profile anzeigen
@ZEVs: SetOrigin ist mir durchaus bekannt. Nur verfolge ich einen kleinen kontrollwahn, weswegen ich lieber selbst alles mit OGL erstelle.

M0rgenstern:
Wenn ich annixa richtig verstanden habe, lassen sich damit auch alle normalen befehle verwenden. Nur das halt explizit der OGL treiber verwendet wird, nicht der DirectX treiber. Deswegen hatte ich auch diese funktion kopiert, bei meiner habe ich GraphicsGL verwendet, was nur direkten OGL gebrauch zulässt. Die variante finde persönlich besser, was aber wirklich geschmacks sache ist. Ich hab lange nichtsmehr mit normalen bmx befehlen gemacht, weswegen ich garnichtmehr weiß, was da anders wäre *hust* Und ich bin so ein schussel, offsets addieren vergesse ich andauernd ^^

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group