Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Das Gurke

Community-Fossil

  • »Das Gurke« ist der Autor dieses Themas

Beiträge: 1 996

Wohnort: Pinneberg

Beruf: Schüler

  • Private Nachricht senden

1

01.06.2008, 12:04

[Gelöst] [C#] Design mit Interfaces / Basisklassen

Ich bin gerade (mal wieder) an einem Punkt angelangt, an dem ich Mehrfachvererbung tierisch vermisse. Allerdings komme ich ja ursprünglich aus der C++ Ecke und hab mir C# mehr so im Vorbeigehen angeeignet. Es ist also möglich, dass ich irgendein Feature übersehe.

Die Situation:
Einige Spielobjekte meines Spiels sollten sich von zwei Klassen ableiten, geht so schonmal nicht :( Die beiden "erwünschten" Basisklassen nennen sich "Resource" und "Renderable" und werden von zwei verschiedenen Managerklassen benötigt. Ich hab dazu mal ein Diagramm erstellt:

(Link)


Area soll nun sowohl eine Resource sein (wird ja schließlich aus Dateien geladen) als auch Renderable (soll ja auf dem Bildschirm angezeigt werden können).

Nun erlauben Schnittstellen dummerweise nicht die Verwendung von Feldern. Diese werden aber von den beiden Klassen benutzt. Ich könnte ja nur auf die Eigenschaften zurückgreifen, müsste dann aber in jeder abgeleiteten Klasse den gleichen Code kopieren. Das erinnert mich irgendwie nicht an OOP ... Und obendrein erlauben Interfaces auch keine Definition von einzelnen Methoden oder ähnlichem, ich müsste also darauf verzichten, gewisse oft genutzte "Komfortmethoden" direkt in die Basisklasse zu implementieren.

Da ich nicht vermute, dass ich der einzige mit so einem Problem bin, denke / hoffe ich mal, dass ich irgendetwas übersehen habe. C# ist eben nicht C++ und ich habe erstmal versucht meinen Ansatz aus C++ zu übertragen. Was ja nicht funktioniert :(

Wie umgeht man diese Situation denn in C#?

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

2

01.06.2008, 12:19

Umgehen kannst du die Situation in dem du dein Design eben an Interfaces anpasst. Das ist bei C# der Alternativweg zu Mehrfachvererbung.
@D13_Dreinig

Das Gurke

Community-Fossil

  • »Das Gurke« ist der Autor dieses Themas

Beiträge: 1 996

Wohnort: Pinneberg

Beruf: Schüler

  • Private Nachricht senden

3

01.06.2008, 13:31

Aber wie gehe ich denn dann damit um, wenn ich die gleiche Grundfunktionalität aus zwei Bereichen in eine Klasse pressen möchte? Interfaces erlauben mir ja keine Definitionen :( Und ich will doch nicht x-mal die Gleichen Interfaces implementieren xD

Naja, dann muss ich mir zur not ne "Zwischenklasse" a la RenderableResource oder so machen. Mir kommt das nur so ... gefrickelt vor :(

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

4

01.06.2008, 15:05

Du könntest das Simulated Multiple Inheritance Pattern verwenden. Die Frage ist, ob du nicht einfach dein Design an "normale" C# Mittel anpassen solltest. Wir entwickeln schon Jahre lang mit C# und kamen bislang immer ohne Mehrfachvererbung aus...

Naja, hier schnell das Pattern:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public abstract class Renderable
    {
    }

    public abstract class Resource
    {
    }

    internal class InternalRes : Resource
    {
        internal Area mArea;

        public static implicit operator Area( InternalRes res )
        {
            return res.mArea;
        }
    }

    public class Area : Renderable
    {
        internal InternalRes mDerivedRes;

        public Area()
        {
            mDerivedRes = new InternalRes();
            mDerivedRes.mArea = this;
        }

        public static implicit operator Resource( Area area )
        {
            return area.mDerivedRes;
        }
    }
@D13_Dreinig

grek40

Alter Hase

Beiträge: 1 491

Wohnort: Dresden

  • Private Nachricht senden

5

01.06.2008, 15:30

Hmm, weiss ja nich, wie umfangreich das ganze werden soll, aber evtl würde ja folgendes gehen:

interface IRenderable und IResource

class Renderable und Resource erben von den jeweiligen interfaces

class Graphicsmanager und Resourcemanager erben wie bisher

class Area erbt von IRenderable und IResource
Renderable und Resource (oder auch gleich Graphicsmanager und Resourcemanager?) als Variablen in Area erstellen und dann mit der Interfaceimplementation eine Anbindung an die Objekte liefern.

Das Gurke

Community-Fossil

  • »Das Gurke« ist der Autor dieses Themas

Beiträge: 1 996

Wohnort: Pinneberg

Beruf: Schüler

  • Private Nachricht senden

6

01.06.2008, 15:42

Danke für eure Antworten! David scheint mir da noch am ehesten Recht zu haben, ich muss mir mal anschauen was genau an meiner Lösung nicht 'C# gemäß' ist.

Mir kommt allerdings grad noch der Gedanke, Renderable einfach direkt von Resource abzuleiten, da es keine Renderfähigen Objekte geben sollte, denen keine Resource zugrunde liegt. Ich bin am Überlegen und werd euch das Ergebnis wissen lassen ;)

koschka

Community-Fossil

Beiträge: 2 862

Wohnort: Dresden

Beruf: Student

  • Private Nachricht senden

7

01.06.2008, 15:53

Also das Render Teil kann durchaus ein Interface sein, den jede Resource wird sicher anders gerendert, da gibt es keine Gemeinsamkeiten...

Skalierung, Matrizen setzen u.s.w. kann der Graphikmanager machen, somit macht Renderable keinen Sinn als abstrakte Klasse.


Desweiteren sollen sicher nicht alle Resourcen gerendert werden können! Warum den auch?... Texturen sind durchaus Resourcen und Modelle auch... Modelle sollen gerendert werden, aber Texturen doch nicht, wenn dann Sprites oder ähnliches. Deshalb sehe ich den Resourcenbegriff wesenltich weiter als du.

Eine neue Idee:
Die es ermöglicht Resourcen und Zeichenbare Objekte zu trennen, den wie schon gesagt ist ein zeichenbares Objekt noch lange keine Resource

(Link)



Im übrigen könnte die Textur Klasse durchaus abstrakt sein, das kommt auf die Definition an ...
Das Modell ist sicher nicht komplett, aber es ist als Denkansatz gedacht, ... man könnte auch die IRenderable und die IResource zu einem Observer machen, indem sich zum Beispiel die Resourcen selber validieren können (wenn man z.B. Alt+Tab drück werden alle invalidiert und wenn man die Resourcen wieder braucht ruft man in der Klasse Resources "Validate" auf und alle Resourcen laden sich, insofern sie invalid sind)

Das Gurke

Community-Fossil

  • »Das Gurke« ist der Autor dieses Themas

Beiträge: 1 996

Wohnort: Pinneberg

Beruf: Schüler

  • Private Nachricht senden

8

01.06.2008, 16:15

Ja du hast Recht, meine "Lösung" war echt sehr kurz gedacht.

Bei mir ist Renderable momentan eine Klasse, weil die Benamsung wahrscheinlich sehr unglücklich ist. Ich arbeite nicht im dreidimensionalen Raum, es geht hier im folgenden also nur um 2D Sprites.

Renderables sind eigentlich eher Renderbereiche. Der Graphik Manager hat eine geordnete Liste aller dieser Bereiche, und diese werden für z.B. folgendes genutzt:
[list]Darstellung des Spielfelds (Area)
Darstellung grundlegender Spielinformationen wie Lebensenergie etc, kleinere Overlays quasi
Menüs
Bilder ("Cut Scenes")[/list]Das ganze erinnert möglicherweise ein wenig an einzeln nutzbare Gamestates, die mehr oder weniger beliebig miteinander kombiniert werden können. Einige dieser States können dabei blockierend wirken und somit die Eingabe oder auch die Darstellung anderer States blockieren.

Renderable nur deshalb, weil diese Dinge vom Grafik Manager irgendwie direkt zum Rendern aufgefordert werden.

Und ich habe mich noch nicht zu einem Interface durchringen können, weil ich zumindest auch die Größe als Eigenschaft der Renderables speichern wollte. Aber gut, vielleicht sollte ich diese Dinge auch übergeben.

Meine Idee basiert im wesentlichen auf diesem Artikel: http://creators.xna.com/en-us/samples/gamestatemanagement

koschka

Community-Fossil

Beiträge: 2 862

Wohnort: Dresden

Beruf: Student

  • Private Nachricht senden

9

01.06.2008, 17:34

Also Renderbale würde ich als Interface behalten, da es schlichtweg alle Klassen markiert die sich irgendwie zeichnen und du kannst immer einen Manager haben der alle zu zeichnenden Klassen zeichnet (siehe Entwurf oben)

Resourcen brauchst du ja aber trotzdem.

Der Entwurf oben lässt sich 1:1 mit einem 2D Tile Based Entwurf komponieren, allein in dem mann die Klasse Graphics schlichtweg erweitert!
Man hat dann eben nicht nur eine Aggregation zu Renderable sondern n viele... eine für den Bottom Layer, dann für den dadrüber u.s.w., je nachdem wieviel Layer du eigentlich haben willst und brauchst.

Das Zeichnen zeichnet dann eben erst alle in bottomLayerRenderables dann die normalLayerRenderables u.s.w.

Die eigentlichen Zellen und Figuren müssen das ja nicht wissen auf welchem Layer sie gezeichnet werden, das muss ja nur die Klasse Graphics wissen.


(Link)

Das Gurke

Community-Fossil

  • »Das Gurke« ist der Autor dieses Themas

Beiträge: 1 996

Wohnort: Pinneberg

Beruf: Schüler

  • Private Nachricht senden

10

01.06.2008, 17:58

Danke, du hast mich endgültig überzeugt =) Renderable wird ein Interface mit folgender Signatur:

C-/C++-Quelltext

1
2
3
4
    public interface Renderable
    {
        void Render(RenderTarget2D target);
    }

Ungewohnt, aber allemal praktikabel.

Mal am Rande: Koschka, womit erstellst du deine Diagramme?

Werbeanzeige