C# Fragen zu Wator-Simulation

!Anonymous

Cadet 4th Year
Registriert
Feb. 2012
Beiträge
92
Hey Leute,
ich wollte eine Wator-Simulation programmieren, also sowas hier, und dazu habe ich ein paar Fragen:
Um die verschiedenen Farben für Fische, Haie und Wasser darzustellen, bieten sich da am besten Labels oder Rectangles an, oder was ist für die Performance am besten?
Sollte ich das ganze in einem Timer laufen lassen?

Es kommen bestimmt noch ein paar Fragen dazu :D

Ich benutze C# 20120 Express Edition mit einer WPF-Anwendung wegen dem Grid.

MfG
 
c# ist lange her aber gibts da nicht ne klasse für grafische anwendungen? canavs oder so? oder bringe ich das grad mit java durcheinander?
 
Interessante Sache, kannte ich bisher noch nicht.

Meine Idee:
Du solltest erst einmal deine Daten von allem visuellen trennen. Die Struktur der Daten würde ich wie folgt machen: Du erstellst eine Klasse (ein Quadrat deines Spielfeldes) mit vier Objekten vom Typ der erstellten Klasse - je ein Feld pro Himmelsrichtung. Dann brauchst du noch ein Objekt mit dem Typ einer Spielfigur.

Die Spielfigur erstellst du später auch als Klasse. Diese kann entweder Hai, Fisch oder Wasser sein (könnte man als String in der Klasse hinterlegen). Sie enthält Informationen zum Fressstand und alles nötige für den Spielablauf. Positionen würde ich dort nicht hinterlegen.

Jetzt weiter zu deinen Quadraten. Du baust dir dein Spielfeld einmal während der Initialisierung zusammen indem du Quadrate erzeugst und zu einem großen Feld zusammenkettest. Hierzu benötigst du deine 4 Verweise mit den Himmelsrichtungen. Wie genau du das angehst, ist egal.

Bewegung entsteht dadurch, dass du einem Verweis des Quadrates folgst, das Spielfigur-Objekt deines Quadrates auf das Zielfeld schreibst und dann das Objekt deines Ausgangsfeldes löschst. Was bei Kollisionen passiert, steht in den Regeln geschrieben. All das kannst du in einer Methode "move" umsetzen. Ich würde der Klasse Quadrat eine solche Methode bereitstellen.

Um dein Spielfeld kannst du jetzt eine weitere Klasse bauen, welche die wichtigen Aufgaben erfüllt. Sie steuert die Bewegungen und die Grafik. Für die Bewegungen würde ich wie du vorschlägst, einen Timer verwenden. Bei jedem Tick durchläuft die Klasse einfach alle Quadrate und führt "move" aus.

Das Zeichnen wird nicht stark auf die Performance gehen. Du könntest ein Schachbrett aus Labels, Panels etc. erstellen, welche die Farbe wechseln. Diese wären relativ einfach anzusteuern. Zeichnen mit Rectangles empfinde ich als sehr unangenehm, weil du dir die Positionen irgendwo merken muss. Ist aber wohl eine Glaubenssache.

Ui...viel geschrieben. Da hab ich mich etwas mitreißen lassen ;)
 
Zuletzt bearbeitet:
Ja es gibt eine Canvas-Klasse, die ist aber eher eine Zeichenvorlage zum Zeichnen von Rectangles oder Kreisen glaube ich.
Ergänzung ()

Smagjus schrieb:
Interessante Sache, kannte ich bisher noch nicht.

Meine Idee:
Du solltest erst einmal deine Daten von allem visuellen trennen. Die Struktur der Daten würde ich wie folgt machen: Du erstellst eine Klasse (ein Quadrat deines Spielfeldes) mit vier Objekten vom Typ der erstellten Klasse - je ein Feld pro Himmelsrichtung. Dann brauchst du noch ein Objekt mit dem Typ einer Spielfigur.

Die Spielfigur erstellst du später auch als Klasse. Diese kann entweder Hai, Fisch oder Wasser sein (könnte man als String in der Klasse hinterlegen). Sie enthält Informationen zum Fressstand und alles nötige für den Spielablauf. Positionen würde ich dort nicht hinterlegen.

Jetzt weiter zu deinen Quadraten. Du baust dir dein Spielfeld einmal während der Initialisierung zusammen indem du Quadrate erzeugst und zu einem großen Feld zusammenkettest. Hierzu benötigst du deine 4 Verweise mit den Himmelsrichtungen. Wie genau du das angehst, ist egal.

Bewegung entsteht dadurch, dass du einem Verweis des Quadrates folgst, das Spielfigur-Objekt deines Quadrates auf das Zielfeld schreibst und dann das Objekt deines Ausgangsfeldes löschst. Was bei Kollisionen passiert, steht in den Regeln geschrieben. All das kannst du in einer Methode "move" umsetzen. Ich würde der Klasse Quadrat eine solche Methode bereitstellen.

Um dein Spielfeld kannst du jetzt eine weitere Klasse bauen, welche die wichtigen Aufgaben erfüllt. Sie steuert die Bewegungen und die Grafik. Für die Bewegungen würde ich wie du vorschlägst, einen Timer verwenden. Bei jedem Tick durchläuft die Klasse einfach alle Quadrate und führt "move" aus.

Das Zeichnen wird nicht stark auf die Performance gehen. Du könntest ein Schachbrett aus Labels, Panels etc. erstellen, welche die Farbe wechseln. Diese wären relativ einfach anzusteuern. Zeichnen mit Rectangles empfinde ich als sehr unangenehm, weil du dir die Positionen irgendwo merken muss. Ist aber wohl eine Glaubenssache.

Ui...viel geschrieben. Da hab ich mich etwas mitreißen lassen ;)

xD das hört sich ja schon mal sehr gut an. Ich hatte gedacht ich erstelle ein enum-Array, in dem ich für jede Zelle in meinem Spielfeld den Status (also Wasser, Fisch oder Hai) speichere, was hältst du davon?

Deswegen noch eine Frage: Kann man ein zweidimensionales Array erstellen, in dem jede Variable entweder eine Variable der Klasse Wasser, Fisch, oder Hai sein kann? Dann könnte man in diesem Array nämlich zu jeder Zelle auf meinem Spielfeld die nötigen Daten, wie die Breedtime speichern.
 
Zuletzt bearbeitet:
!Anonymous schrieb:
Deswegen noch eine Frage: Kann man ein zweidimensionales Array erstellen, in dem jede Variable entweder eine Variable der Klasse Wasser, Fisch, oder Hai sein kann? Dann könnte man in diesem Array nämlich zu jeder Zelle auf meinem Spielfeld die nötigen Daten, wie die Breedtime speichern.

Code:
Feld[] meinArray = new Feld[AnzahlDerFelder];
meinArray[0] = new Feld();

oder so ähnlich. (geht natürlich auch 2dimensional)
Feld ist dann ne Klasse, die halt alles wichtige Speichern kann.

Grafik vllt. interessant.
http://openbook.galileocomputing.de/visual_csharp/visual_csharp_17_001.htm
 
Zuletzt bearbeitet:
Thx, ich wollte es von vorne herein ohne GDI machen, weil ich mich erstmal damit auseinander setzen müsste^^
 
Für solche grafischen Aspekte würde ich mal Richtung XNA gucken.
 
DasBoeseLebt schrieb:
Code:
Feld[] meinArray = new Feld[AnzahlDerFelder];
meinArray[0] = new Feld();

oder so ähnlich. (geht natürlich auch 2dimensional)
Feld ist dann ne Klasse, die halt alles wichtige Speichern kann.

Grafik vllt. interessant.
http://openbook.galileocomputing.de/visual_csharp/visual_csharp_17_001.htm

Ok, also ich erstelle einfach ein zweidimensionales Array vom Typ "spielfigur" welcher eine eigene Klasse ist. Aber wie kann ich nun am besten in der Klasse "spielfigur" in diese drei Typen (Wasser, Fisch, Hai) unterteilen, damit ich angeben kann welcher Typ meine Zelle ist. Sollte ich einfach eine Variable (evtl. Enum) erstellen, die mir den aktuellen Typ der Zelle speichert, oder kann man da irgendwas durch Unterklassen oder so machen?
 
Ein Enum für die Typen erstellen und in einem Property in der Klasse Spielfigur(wichtig Klassen mit großem Anfangsbuchstaben!) speichern.
 
Hm. also wenn ich das so lese, denke ich an

Spielfigur
|- Wasser
|- Fisch
|- Hai

Code:
<Window.Resources>
    <DataTemplate DataType="{x:Type local:Wasser}">
        <Rectangle Fill="Blue" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:Fisch}">
        <Rectangle Fill="Green" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:Hai}">
        <Rectangle Fill="Red" />
    </DataTemplate>
</Window.Resources>
    
<Grid>
    <ItemsControl ItemsSource="{Binding Figuren}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="{Binding Spalten}" Rows="{Binding Zeilen}" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>

Figuren ist dabei eine ObservableCollection<Spielfigur>. Navigation erfolgt über den Index:
- links: i - 1
- rechts: i + 1
- hoch: i - Spalten
- runter: i + Spalten

Nur so eine Idee ;)
 
!Anonymous schrieb:
Thx, ich wollte es von vorne herein ohne GDI machen, weil ich mich erstmal damit auseinander setzen müsste^^

Naja, musst du wissen. Ist eigentlich nicht schwer und in diesem Beispiel erst recht nicht, da die Feldposition sich gut auf die graphische Position übertragen lässt und man ja quasi nur Rechtecke unterschiedlicher Farbe zeichnet.
 
Ich programmiere erst seit ca. 2 Wochen und verstehe deshalb nicht alles auf Anhieb. Was ihr mir nochmal erklären müsst ist, wie ich mit Enum diese Drei Typen erstelle und dann auch Werte speichern kann, wie z.B. bei den Fischen die Breed Time.
 
2 Wochen sind deutlich wenig als ich erwartet habe. Mit meinem ersten Post konntest du dann wohl nicht viel anfangen. Du scheinst jedenfalls besser mit dem Programmieren zurechtzukommen also so manche hier mit 4 Jahren Erfahrung ;)

Mit Enums kann ich dir leider nicht weiterhelfen. Die verwende ich ungern, weil die Syntax und Handhabung in verschiedenen Programmiersprachen zu verwirrend ist.
 
Smagjus schrieb:
2 Wochen sind deutlich wenig als ich erwartet habe. Mit meinem ersten Post konntest du dann wohl nicht viel anfangen. Du scheinst jedenfalls besser mit dem Programmieren zurechtzukommen also so manche hier mit 4 Jahren Erfahrung ;)

Mit Enums kann ich dir leider nicht weiterhelfen. Die verwende ich ungern, weil die Syntax und Handhabung in verschiedenen Programmiersprachen zu verwirrend ist.

Vielen Dank erstmal :)
Ich habe das meiste davon schon verstanden, habe auch schon ein GameOfLife und Langtons Ameise programmiert. Jedenfalls versuch ichs einfach nochmal ohne Enum^^
 
Direkt eigene Klassen für dieses eher triviale Programm erstellen, ist eigentlich suboptimal.

Für so was würde ich, wie schon DasBoeseLebt schrieb, ein einfaches zweidimensionales Array nehmen. Da die einzelnen Felder in dem Array nur drei Zustände haben, kann man entweder auf simple Datentypen wie Char, Int usw. oder eben auf Enums (die in C# auf Wunsch auch ganze Zahlen (Shorts, Ints, ...) sein dürfen) zurückgreifen.

Das sähe bei mir in etwa so aus:
Code:
namespace Wator
{
    public enum Feld : int
    {
        mitNichts = 0,
        mitFisch = 1,
        mitHai = 2
    }

    public class Spielfeld
    {
        public Feld[,] Welt { get; private set; }
        public int Breite { get; private set; }
        public int Hoehe { get; private set; }

        public Spielfeld(int breite, int hoehe)
        {
            this.Breite = breite;
            this.Hoehe = hoehe;
            this.Welt = new Feld[breite, hoehe];

            this.InitialisiereWelt();
        }

        public void InitialisiereWelt()
        {
            Random rnd = new Random();

            for (int x = 0; x < this.Breite; x++)
                for (int y = 0; y < this.Hoehe; y++)
                    this.Welt[x, y] = (Feld) rnd.Next(2); // spuckt 0, 1 oder 2 aus, die Zahl wird durch den Cast in eine passende Enum-Konstante umgewandelt
        }

        public void Berechne()
        {
            foreach (Feld aktuellesFeld in Welt) // Willst du in dieser Schleife das Welt-Array verändern, musst du den Schleifentyp in mehrere For- oder While-Schleifen zerlegen. Collections, über man mit einer ForEach-Schleife iteriert, dürfen nicht verändert werden.
            {
                if (aktuellesFeld == Feld.mitFisch)
                {
                    // was mit dem Fisch machen
                }
                else if (aktuellesFeld == Feld.mitHai)
                {
                    // was mit dem Hai machen
                }
            }
        }

        // usw.
    }
}
 
e-Laurin schrieb:
Für so was würde ich, wie schon DasBoeseLebt schrieb, ein einfaches zweidimensionales Array nehmen. Da die einzelnen Felder in dem Array nur drei Zustände haben, kann man entweder auf simple Datentypen wie Char, Int usw. oder eben auf Enums (die in C# auf Wunsch auch ganze Zahlen (Shorts, Ints, ...) sein dürfen) zurückgreifen.
Zu der Positionierung deiner Spielfiguren, die du mit dem Array abgehandelt hast, kommen noch weitere Informationen hinzu, wie zum Beispiel "Energie". Wo würdest du diese hinterlegen? Würdest du dafür gleich ein 3 Dimensionales Array aufbauen oder einfach ein zweites 2 Dimensionales?
 
Smagjus schrieb:
Zu der Positionierung deiner Spielfiguren, die du mit dem Array abgehandelt hast, kommen noch weitere Informationen hinzu, wie zum Beispiel "Energie". Wo würdest du diese hinterlegen? Würdest du dafür gleich ein 3 Dimensionales Array aufbauen oder einfach ein zweites 2 Dimensionales?

Die Hauptklasse ist Simulation, die macht alles bezüglich Logik und Grafik.
In der hast du auch das Abbild des Spielfeldes welches durch das Array der Klasse Feld repräsentiert wird.

Feld speichert die Informationen ohne jegliche Logik.
-> Was bin ich (Fisch, Hai, Wasser)
-> Wann sterben ich(...;...; nie)
-> Wann vermehre ich mich (...;...; nie)
usw.

Du brauchst nicht mal Klassen für Fisch, Hai oder Wasser. Halt die Klasse Feld sauber anlegen, mit Get/Set ausstatten etc.


Man muss es nicht unnötig kompliziert machen und man hat halt bisschen OOP mit drin, wie es sich gehört :P
(Ich würde es so machen; oder so ähnlich)
 
Zuletzt bearbeitet:
Ich habe eine weitere Frage: Es macht doch einen Unterschied, ob ich mit der Methode "Move" (welche für jede Zelle überprüft welche Spezies sich in ihr befindet und dann die Aktion nach den Regeln der Wator Simulation ausführt) erst die Reihen und dann die Spalten oder erst die Spalten und dann die Reihen abgehe?
 
Stimmt, das mit der Lebenszeit habe ich übersehen. Das würde ich in der Enum allerdings irgendwie unterbringen oder die Enum rausnehmen und nur mit einem Int arbeiten, in dem Lebenszeit, Fisch/Hai/leer kodiert ist.

Großartig mit Klassen und Objekten arbeiten, würde ich hier nicht. Wenn das Feld nur 800x600 Felder groß ist, dann sind das schon 480.000 Felder. Die Berechnung wird hier schon lahm, wenn es ein Int-Array ist. Bei Objekten schläft das Programm dann ein.


@Anonymous
Natürlich macht es einen Unterschied. Je nachdem bekommt zB ein Hai nichts mehr zu fressen und stirbt, weil er berechnet wurde, bevor ein Fisch plötzlich auf ein Nachbarfeld wandert.
 
Zuletzt bearbeitet:
Zurück
Oben