Laden...

Rendering Struktur

Erstellt von Fab96 vor 19 Jahren Letzter Beitrag vor 19 Jahren 3.015 Views
F
Fab96 Themenstarter:in
66 Beiträge seit 2004
vor 19 Jahren
Rendering Struktur

Hi, ich bin grad dabei mir so eine art kleine GameLibary zu erstellen für 2D Games(später mehr?)

Bin momentan noch nicht sehr weit, hab aber für keyboardhandling usw. aber schon ideen und im kleinenumfang auch fertig.

Aber momentan bin ich schwer am überlegen wie ich das mit dem Rendern am besten und flexibelsten mache.
Vorgestellt hab ich es mir so das ich bei jeder Texture sprite, font eine Render methode habe und ich sie einfach render indem ich sie aufrufe, nur wie bekomm ich die zwischen Begin und EndScene ?

Es müsst ja irgendwie dynamisch gehen indem ich eine Liste aller zu rendernen Objecte habe und sie dann beim Rendern je nachdem ob sichtbar oder nicht gerendert wird.

Mein Prob ist nun wie ichdas am einfachsten umsetze oder ob es nicht eine sicherlich bessere idee gibt.

Bin für jede Anregung dankbar.

P
939 Beiträge seit 2003
vor 19 Jahren

Wie wäre es mit dem Visitor Design Pattern?

Das Pattern ist gut geeignet, um Operationen auf Datenstrukturen zu definieren. Es ist sehr angenehm damit zu programmieren, da man sich keine Gedanken zu machen braucht, welche Methode für eine Operation auf einem Daten-Objekt aufgerufen werden muss - if oder switch-Anweisungen gibt es nicht. Man ruft auf einem Daten-Objekt Accept auf und übergibt die auszuführende Operation (den Visitor) als Parameter.

Ich habe das Visitor Design Pattern für deinen Fall mal als UML-Diagramm gezeichnet (und dabei gleich ein bisschen Visual Paradigm ausprobiert):

Die Accept-Methoden der Daten-Objekte, die wie gesagt die Operationen entgegennehmen, werden folgendermaßen implementiert:

public class Sprite : IModelPart {
  public void Accept(IModelVisitor v) {
    v.VisitSprite(this);
  }
}
public class Obstacle : IModelPart {
  public void Accept(IModelVisitor v) {
    v.VisitObstacle(this);
  }
}
public class Label : IModelPart {
  public void Accept(IModelVisitor v) {
    v.VisitLabel(this);
  }
}

Die Visit-Methoden in den Operationen (den Visitors) bekommen als Parameter das Daten-Objekt, auf dem die Operation angewendet werden soll. In deinem Fall das Sprite oder Label, das gerendert werden soll. Was sonst noch benötigt wird, z.B. ein Direct3D-Device, muss dem konkreten Visitor über Properties mitgeteilt werden.

Ein Client kann das ganze nun verwenden. Im Diagramm ist Beispielcode für eine RenderWorld-Methode angegeben.

Gruss
Pulpapex

F
Fab96 Themenstarter:in
66 Beiträge seit 2004
vor 19 Jahren

uff danke, sieht ganz gut aus, auch wenn ich wenn ich ehrlich bin sogut wie nix versteh 😉

Kenne mich in sachen Interfaces und Pattern leider kaum aus, sollt ich aber wohl mal machen, sonst werd ich wohl nie möglichst nah am optimum coden können.

Könntest du den aufbau eventuell nochmal kurz erklären ?
Auf jedenfall schonmal danke, ich werd mich daran auf jedenfall ortientieren und fehlendes wissen versuchen nachzuarbeiten.

PS: eventuell gibts ein Buch oder so in dierichtung(Architektur) was man empfehlen könnt?

M
456 Beiträge seit 2004
vor 19 Jahren

Der Hauptsinn in diesem Pattern liegt darin, deine Daten, also Sprites und Co., von deinem eigentlichem Rendering zu entkoppeln. Von IModelVisitor kann man eigene Renderobjekte erzeugen. Das bedeutet für dich, dass dein Rendeing unahängig von der Grafik-API geschieht. Du könntest einen OpenGL, Direct3D, GDI-Renderer oder sonstwas implementieren. Das Visitor Pattern hat natürlich auch ein paar Nachteile: Das Pattern ist recht aufwändig zu verwalten, wenn man es mal mit Multimethoden vergleicht:

http://nice.sourceforge.net/visitor.html

Dafür erlaubt es eine recht gute Trennung von Daten und Operationen (in dem Fall Rendering) auf diese.

Eine ganz gute Übersicht für Pattern gibt's hier:

http://www.dofactory.com/Patterns/Patterns.aspx

Für Pattern allgemein, ist wohl das GOF-Book zu empfehlen:

http://c2.com/cgi/wiki?DesignPatternsBook

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.

F
Fab96 Themenstarter:in
66 Beiträge seit 2004
vor 19 Jahren

uff danke, alles irgendwie komplex ohne ein wirkliches beispiel zu haben, aber danke werd versuchen mir das einzuhämmern 😉

P
939 Beiträge seit 2003
vor 19 Jahren

Die Namensgebung der Methoden ist anfangs verwirrend, wenn man das Visitor-Pattern nicht kennt. Das liegt daran, dass das Pattern es erlaubt, beliebige, neue Operationen auf den Daten-Objekten (Sprite, Label) zu definieren, die wenig bis gar nichts mit einander zu tun haben, für die man aber einheitliche Methodennamen benötigt. Neben der Render-Operation könnte es z.B. eine Operation zum Neuberechnen von Objekt-Positionen nach physikalischen Gesetzen geben oder eine Operation, die Werte für Statistiken sammelt usw.

Wenn es wirklich nur ums Rendern geht, kann die Namensgebung deutlicher gemacht werden, das Prinzip bleibt aber das selbe.

Das ganze mal in Code, zuerst die renderbaren Objekte:

// Interface für renderbare Objekte.
public interface IRenderable {
  void RenderWith(IRenderer r);
}

// Sprite-Klasse, bewegliche Vordergrundobjekte.
public class Sprite : IRenderable {

  // Sprite vom übergebenen Renderer rendern lassen.
  // Welcher Renderer das ist und wo er herkommt,
  // ist uninteressant.
  public void RenderWith(IRenderer r) {

    // Die zugehörige Render-Methode aufrufen.
    // Sich selbst als Parameter übergeben.
    r.RenderSprite(this);
  }
}

// Label-Klasse, Text-Overlays.
public class Label : IRenderable {

  // Label vom übergebenen Renderer rendern lassen.
  public void RenderWith(IRenderer r) {
    r.RenderLabel(this);
  }
}

Renderer: Klassen zum Rendern der Objekte. Es können beliebig viele,
verschiedene Renderer definiert werden. Für jedes renderbare
Objekt muss eine Render-Methode vorgesehen werden.

// Interface für Renderer.
public interface IRenderer {
  void RenderSprite(Sprite s);
  void RenderLabel(Label l);
}

// Eine Renderer-Implementierung für Direct3D.
// Die Klasse definiert Render-Methoden
// für die verschiedenen Objekte. Wo die Objekte
// herkommen ist uninteressant.
public class D3DRenderer : IRenderer {

  // Das Direct3D-Device.
  public Microsoft.DirectX.Direct3D.Device Device {
    // get; set;
  }

  public void RenderSprite(Sprite s) {
    // Hier der Code zum Sprite-Rendern in D3D.
  }

  public void RenderLabel(Label l) {
    // Hier der Code zum Label-Rendern in D3D.
  }
}

RenderWorld: der D3DRenderer auf die renderbaren Objekte angewendet:

// Eine Klasse, die das ganze verwendet.
public class Client {

  private World world;
  private D3DRenderer d3dRenderer = new D3DRenderer();

  // Die Spielwelt
  public World World {
    get { return world; }
    set { world = value; }
  }

  // Der Renderer
  public D3DRenderer D3DRenderer {
    get { return d3dRenderer; }
  }

  // ----------------------------------------
  // Methode zum Rendern der Spielwelt.
  // so wird das Visitor-Pattern angewendet.
  // ----------------------------------------
  public void RenderWorld() {

    D3DRenderer.Device.BeginScene();

    // Nacheinander alle Objekte in der Spielwelt rendern lassen.
    foreach(IRenderable renderObject in World.Parts) {
       renderObject.RenderWith(D3DRenderer);
    }

    D3DRenderer.Device.EndScene();
  }
}

// Spielwelt-Klasse.
public class World {

  private List parts = new ArrayList();

  // Eine Liste mit allen Objekten in der Spielwelt.
  // (mir fällt kein guter Name ein)
  public List Parts {
    get { return parts; }
  }
}

Ich weiss, sieht nach viel Code aus, ist es aber nicht. Das meiste sind die Kommentare. 😉

Gruss
Pulpapex

F
Fab96 Themenstarter:in
66 Beiträge seit 2004
vor 19 Jahren

So ich hab das rendern nun so halbwegs fertig und wollte hier mal die umsetzung posten, sieist nicht so ideal wie die oben aber ich denke man kann mit ihr arbeiten.

Also ich hab einfach eine Form wo ich auch render, im render hab ruf ich die Render Methode des gameScreenManagers auf, die wiederum ruft den Obersten GameScreen auf dem Stack wo die gamescreens drin sind auf.

Im GameScreen wird nun die Run methode ausgeführt in der momentan nur so sache ndrin sind wie font.WriteText();

dadurch wird der text gerendert.

Was ich noch einbauen muss ist eine LOgik klasse mit der bestimmte schritte/ticks habe an denen ich die spiellogik ausrichte, da sie logik auch in der run methode ist.

Was haltet ihr davon ? ich denke ist nicht ideal, aber es funktioniert.

BIn für jede kritik dankbar