Ich bin sehr neu in der Spieleentwicklung, aber nicht in der Programmierung.
Ich spiele (wieder) mit einem Pong-Spiel, das JavaScript- canvas
Elemente verwendet.
Ich habe ein Paddle
Objekt mit folgenden Eigenschaften erstellt ...
width
height
x
y
colour
Ich habe auch ein Pong
Objekt, das Eigenschaften wie hat ...
width
height
backgroundColour
draw()
.
Die draw()
Methode setzt derzeit die zurück canvas
und hier ist eine Frage aufgetaucht.
Sollte das Paddle
Objekt eine draw()
Methode haben, die für das Zeichnen verantwortlich ist, oder sollte die Methode draw()
des Pong
Objekts für das Zeichnen der Akteure verantwortlich sein (ich nehme an, dass dies der richtige Begriff ist, korrigieren Sie mich bitte, wenn ich falsch bin).
Ich dachte mir, dass es von Vorteil wäre, sich Paddle
selbst zu zeichnen, wenn ich zwei Objekte instanziiere, Player
und Enemy
. Wenn es nicht in den Pong
's wäre draw()
, müsste ich zweimal ähnlichen Code schreiben.
Was ist hier die beste Praxis?
Vielen Dank.
quelle
Antworten:
Schauspieler selbst zeichnen zu lassen, ist aus zwei Hauptgründen kein gutes Design:
1) Es verstößt gegen das Prinzip der Einzelverantwortung , da diese Akteure vermutlich eine andere Aufgabe hatten, bevor Sie Render-Code in sie hineingeschoben haben.
2) es erschwert die Verlängerung; Wenn jeder Darstellertyp eine eigene Zeichnung implementiert und Sie die Art und Weise ändern müssen, in der Sie generell zeichnen , müssen Sie möglicherweise viel Code ändern. Das Vermeiden von Übernutzung der Vererbung kann dies bis zu einem gewissen Grad, jedoch nicht vollständig, lindern.
Es ist besser für Ihren Renderer, die Zeichnung zu handhaben. Schließlich bedeutet es, ein Renderer zu sein. Die draw-Methode des Renderers sollte ein "render description" -Objekt enthalten, das alles enthält, was Sie zum Rendern eines Objekts benötigen. Verweise auf (wahrscheinlich gemeinsam genutzte) Geometriedaten, instanzspezifische Transformationen oder Materialeigenschaften wie Farbe usw. Es zeichnet das dann und kümmert sich nicht darum, was diese Render-Beschreibung "sein soll".
Ihre Darsteller können sich dann an einer Render-Beschreibung festhalten, die sie selbst erstellt haben. Da es sich bei den Akteuren in der Regel um logische Verarbeitungstypen handelt, können sie nach Bedarf Statusänderungen an der Render-Beschreibung vornehmen. Wenn ein Akteur beispielsweise Schaden nimmt, kann er die Farbe seiner Render-Beschreibung auf Rot setzen, um dies anzuzeigen.
Dann können Sie einfach jeden sichtbaren Akteur iterieren, seine Render-Beschreibungen in den Renderer eingeben und ihn seine Sache machen lassen (im Grunde genommen können Sie dies sogar noch weiter verallgemeinern).
quelle
actor.draw(renderer,x,y)
alsrenderer.draw(actor.getAttribs(),x,y)
.struct RenderDetail { glVAO* vao; int shader; int texture; Matrix4f* transform; }
Mehr oder Weniger für meinen Renderer. Auf diese Weise ist es dem Renderer egal, was die Daten darstellen, er verarbeitet sie nur. Anhand dieser Informationen kann ich dann auch entscheiden, ob die Reihenfolge der Draw-Aufrufe sortiert werden soll, um die Anzahl der GPU-Aufrufe insgesamt zu verringern.Das Besuchermuster kann hier hilfreich sein.
Was Sie tun können, ist eine Renderer-Oberfläche, die weiß, wie jedes Objekt gezeichnet wird, und eine "Zeichne dich selbst" -Methode in jedem Akteur, die festlegt, welche (bestimmte) Renderer-Methode aufzurufen ist, z
Auf diese Weise ist es immer noch einfach, auf eine andere Grafikbibliothek oder ein anderes Framework zu portieren
Graphics2D
.Ein weiterer Vorteil: Der Renderer kann unabhängig von jedem Akteurcode getestet werden
quelle
In Ihrem Beispiel möchten Sie, dass die Pong-Objekte draw () implementieren und sich selbst rendern.
Obwohl Sie bei einem Projekt dieser Größe keine nennenswerten Gewinne bemerken, lohnt es sich, die Spielelogik und ihre visuelle Darstellung (Rendering) zu trennen.
Damit meine ich, du hättest deine Spielobjekte, die update () sein können, aber sie haben keine Ahnung, wie sie gerendert werden, sie beschäftigen sich nur mit der Simulation.
Dann hätten Sie eine PongRenderer () -Klasse, die einen Verweis auf ein Pong-Objekt hat, und sie übernimmt dann das Rendern der Pong () -Klasse. Dies könnte das Rendern der Paddles oder eine PaddleRenderer -Klasse umfassen, die sich darum kümmert.
Die Trennung von Bedenken ist in diesem Fall ziemlich natürlich, was bedeutet, dass Ihre Klassen weniger aufgebläht sein können und es einfacher ist, die Darstellung der Dinge zu ändern. Es muss nicht mehr der Hierarchie folgen, die Ihre Simulation durchführt.
quelle
Wenn Sie dies mit
Pong
draw () tun würden, müssten Sie den Code nicht duplizieren - rufen Sie einfach diePaddle
draw () - Funktion für jedes Ihrer Paddles auf. Also in deinerPong
Auslosung () hättest duquelle
Jedes Objekt sollte eine eigene Zeichenfunktion enthalten, die über den Spielaktualisierungscode oder den Zeichencode aufgerufen werden sollte. Mögen
Dies ist kein Code, sondern dient nur der Veranschaulichung, wie das Zeichnen von Objekten erfolgen soll.
quelle