Zum Inhalt springen

Mehr als ein Objekt einer Klasse erstellen?


Empfohlene Beiträge

Geschrieben

Hallo zusammen,

da mir in diesem Forum beim letzten mal so gut geholfen wurde, wende ich mich mit einer Frage zur oop nochmal an euch. Mein Testprojekt zur oop soll eine Art Spiel werden, wobei das Spiel ansich nicht erstellt werden soll, sondern nur die Idee der Character Erschaffung. Es soll möglich sein mehrer Character aus verschiedenen Rassen und verschiedenen Klassen zu erstellen. Welche dann (wenn ich mich mit dem Speichern von Datein befasst habe), auch abgespeichert und wieder geladen werden können.

In einem Online Rollenspiel ist es zum Beispiel möglich mehrere Character zu erstellen, vielleicht sogar mit verschiedenen Rassen und eventuell sogar diese mit Unterschiedlichen Klassen. Dazu kommen auch noch andere Spieler, welche genauso wie Spieler1 Character aus verschiedenen Rassen mit verscheidenen Klassen erstellen können.

namespace Klassenprojekt2
{
    class Program
    {
        static void Main(string[] args)
        {
            PlayerCharacter playerCharacter = new PlayerCharacter();

            Console.Write("Bitte den Charakternamen eingeben: ");
            playerCharacter.name = Console.ReadLine();

            Console.Write("Bitte das Alter deines Charakters eingeben: ");
            playerCharacter.age = int.Parse(Console.ReadLine());

            Console.WriteLine(playerCharacter.name + " " + playerCharacter.age);

            Console.ReadKey();
        }
    }

    class PlayerCharacter
    {
        public string name;
        public int age;
    }
}

Nach meinem Verständnis erstelle ich in meinem Beispiel allerdings nie ein Neues Objekt, außer beim ersten mal. Jedes mal, wenn ich ein Objekt playerCharacter erstelle, wird das vorherige playerCharacter Objekt ersetzt. Im Internet habe ich gelesen, dass man viele verschiedene Objekte durch die Erstellung einer <List> oder eben einem Arrey erzeugen kann. Wobei in meinem Fall ein Arrey nicht praktikabel wäre, da es ja begrenzt wäre. Meine Frage besteht jetzt darin, ob es der richtige Gedanke wäre, nun das Objekt folgendermaßen zu erzeugen.

    class Program
    {
        static void Main(string[] args)
        {
            List<PlayerCharacter> playerCharacter = new List<PlayerCharacter>();
        }
    }

Mein erster Versuch endete darin das mir eine Fehlermeldung Ausgegeben wurde. Leider habe ich diesen Versuch natürlich nicht gespeichert und kann diese jetzt nicht vorzeigen.

Freundliche Grüße Gewinde 🙂

Geschrieben (bearbeitet)

Hi, Objekte erstellt man immer mit dem new Operator (Den benutzt du aber nur 1x PlayerCharacter playerCharacter = new PlayerCharacter(); ). Wenn man den benutzt wird der Konstruktor der Klasse aufgerufen von der du das Objekt erstellst. Der fehlt bei dir. Solltest du dich mal drüber informieren.

Du müsstest einfach nur mehrere Objekte erstellen -  anschließend kannst du die in Arrays oder Lister packen wie du lustig bist. Das dient aber eher zur Handhabung verschiedener Objete - nicht der Erstellung.  

 

Bearbeitet von bene98
Geschrieben

Richtig. Du kannst folgendes schreiben:

var players = new Player[]
{
    new PlayerCharacter(),
    new PlayerCharacter(),
    new PlayerCharacter()
};

Und schon hättest du ein Array mit 3 Spielern.

Mit dem new-Operator wird ein Objekt im Arbeitsspeicher (genaugenommen im sog. Heap) angelegt. Jedes Objekt hat somit seinen eigenen Speicherbereich und ist deswegen unabhängig von den anderen Objekten. Wenn wir also mit players[0] und players[1] auf die Objekte zugreifen wollen, haben wir unterschiedliche Objekte vom selben Typ.

Geschrieben

Meine beiden Vorredner haben sehr viel bereits ausgeführt, aber was bedeutet das denn nun konrekt für Dein Codebeispiel?

Habe an dieser Stelle einfach einmal versucht, das geschriebene Wissen in Deinem Code umzusetzen, Kommentare einzufügen und die entsprechenden Stellen möglichst einfach und hoffentlich einigermaßen verständlich zu erklären:

using System;

// Damit die Typ List erkannt wird, ist es nötig, deren Namespace dem Compiler bekannt zu machen
using System.Collections.Generic;

namespace Klassenprojekt2
{
    public class Program
    {
        public static void Main(string[] args)
        {
			var players = new List<PlayerCharacter>
			{
				// Achtung: Diese Variante des Erzeugen und Ausfüllen der Objekte funktioniert nur deshalb, weil in der Klasse PlayerCharacter die beiden Eigenschaften als public gekennzeichnet wurden!
				//new PlayerCharacter { name="aaa", age=111 },
				//new PlayerCharacter { name="bbb", age=222 },
				//new PlayerCharacter { name="ccc", age=333 },
			};

			var playerCharacter = new PlayerCharacter();
			
            Console.WriteLine("Bitte den Charakternamen eingeben: ");
            playerCharacter.name = Console.ReadLine();

            Console.WriteLine("Bitte das Alter deines Charakters eingeben: ");
            playerCharacter.age = int.Parse(Console.ReadLine());

			players.Add(playerCharacter);
			
			// Anmerkung: Hier einfach mal googlen wie man die Methode ToString() überschreiben kann
			Console.WriteLine(players[0].name + " " + players[0].age);

			Console.ReadLine();
        }
    }

    class PlayerCharacter
    {
        public string name;
        public int age;
    }
} 

Ein paar Anmerkungen zu den Änderungen:

Es wurde direkt eine Liste für die Speicherung der Objekte verwendet, weil zuvor schon festgestellt worden ist, dass ein Array eine feste Länge hat und erst umständlich vergrößert werden müsste.

@bene98: Es ist hier übrigens nicht erforderlich einen Standardkonstruktor (leeren Konstruktor) in der Klasse PlayerCharacter zu definieren, da dieser beim Kompilieren durch den Compiler unter der Haube hinzugefügt wird.

Ausblick für die weiteren notwendigen Änderungen und das weitere Lernen:

Die Kommentare sollen bereits ein paar Anregungen für weitere mögliche Lernthemen gegeben haben.

Aber an dieser Stelle sollte auch klar geworden sein, dass für das Hinzufügen einer variablen Anzalh von PlayerCharacter-Objekten und entsprechender Abfrage deren Daten vom Benutzer, wohl noch andere Sprachkonstrukte von Nöten sind (Lern-Stichpunkt: Schleifen/Loops).

Geschrieben

Hi, ich weiß das schon . Ich denke, es wäre nur sinnvoller, wenn der Threadersteller ein paar Sachen bei der Geschichte lernen würde. Ist doch eigentlich ein schönes Projekt, was er/sie da hat. Man kann da ne menge über Klassen, Objekte, Methoden Zugriffsmodifikatoren, Container, Vererbung, Polymorphie etc bei lernen. Nur man sollte die Person vielleicht dazu bringen sich mit den Themen zu beschäftigen und es dann testweise umzusetzen anstatt es schon hinzuschreiben.

Geschrieben

Hallo zusammen,

ich habe mir mal einige Gedanken gemacht und erstmal mit der Basisklasse begonnen und etwas mit dem code gespielt. Leider kann ich den gesamten code nicht anhängen, daher mal wieder als schriftliche Ausgabe:

namespace TerraProjekt
{
    enum Breed { Human , Psionic , Experimental}
    enum Gender { neuter , Male , Female}

    class MainPopulation
    {
        private int strength;
        public int Strength { get { return strength; } set => strength = value; }

        private int Stamina { get; set; }

        public MainPopulation (int creatureStrength, int creatureStamina)
        {
            Strength = creatureStrength;
            Stamina = creatureStamina;
        }

        public void WertAusgabe()
        {
            Console.WriteLine("Deine Werte sind: {0} {1}" , strength , Stamina);
        }
    }
}

Ausführung in der Main Methode:

        static void Main(string[] args)
        {
            MainPopulation player = new MainPopulation(50, 100);

            player.WertAusgabe();

            Console.ReadKey();
        }

Die enums im Namespace einfach nicht beachten, die sind für später vorgehalten. Als nächstes versuche ich eine Vererbung in die erste Unterklasse und danach dann als weiteres Experiment die Problematik mehrerer Objekte dieser Klasse. Da ich nicht für jeden Quark ein neues Thema aufmachen möchte, werde ich hier alle Schritte mit eventuellen Fragen u.s.w. reinwerfen und daraus mein ProjektThema machen. Ich hoffe das ist i.O. für euch. Ich würde mich darüber freuen wenn ihr einfach mal drüber schaut und mir ggf. verbesserungsvorschläge geben könntet. Getter und Setter habe ich zwei verschiedene Varianten zum üben benutzt, eigentlich sollte ein Automatischer ja ausreichen. Meine Frage hierzu wäre, wenn man eine Variable direkt über den Konstruktor anspricht (this.strength = creatureStrength). Kann dann der Getter und Setter gänzlich weggelassen werden, da die Zuweisung ja über das Schlüsselwort this erfolgt?

Geschrieben (bearbeitet)

Hallo zusammen,

ich habe die Tage etwas an meinem Projekt getüfftelt und dabei sind natürlich mal wieder einige Fragen aufgetreten. Die eine Frage dreht sich um das besagte Arrey oder die besagte Liste. Erstmal wollte ich diesbezüglich nochmal nachfragen ob ich bene98 Antwort richtig verstehe. Da ich mittels Konstruktor ohnehin immer eine neues ( anders) Objekt als das vorherige erzeuge, ist ein Arrey/List zur erstellung vieler verschiedener Character gar nicht nötig?

Ich möchte dieses Problem (auch wenn gar nicht erforderlich) gerne weiter verfolgen, einfach um dadurch zu lernen und zu verstehen. Ich habe z.B. ein Arrey erstellt welches zur Probe genau 1 index hat (index 0), in dieses habe ich ein Objekt gespeichert und habe mir zur überprüfung das Objekt mittels for-Schleife ausgeben lassen.

            PlayerCharacter[] player = new PlayerCharacter[1];
            player[0] = new PlayerCharacter();

            PlayerCharacter population = new PlayerCharacter();

           // einzelne Methodenaufrufe....

            for(int i = 0; i < player.Length; i++)
            {
                Console.WriteLine(player[i]);
            }

 

Das Ergebnis ProjektTerra.PlayerCharacter finde ich etwas wenig aussagekräftig und daher bin ich mir jetzt nicht wirklich sicher ob der Versuch auch funktioniert hat. Bedeutet diese Ausgabe das die Speicherung erfolgt ist?

 

Bearbeitet von Gewinde
Unfähigkeit im Umgang mit der Tastatur...
Geschrieben (bearbeitet)

Vielleicht hilft es Dir beim Verständnis, wenn Du Dir die angehängten Bilder ansiehst, welche eine SEHR vereinfachte Darstellung des Arbeitsspeicher eines Computers zeigen (in allen Abbildungen durch die Tabelle repräsentiert):

Variablen im Speicher:

vars.png

Wenn man Variablen erzeugt

// Deklaration
int i;

// Deklaration und Initialisierung
int i = 12345;

werden deren Lebensräume (Speicherbereiche) durch das Betriebssystem möglichst effizent zur Verfügung gestellt, so dass spätere Zugriffe möglichst schnell erfolgen können. So belegt z.B. eine Variable vom Typ int 4 Bytes und lebt, ähnlich wie Menschen an einer bestimmten Adresse. Hierbei ist anzumerken, dass Adresse sich immer auf den Anfang des jeweiligen Speicherbereichs bezieht und die Größe des Typs die Länge des belegten Speichers angibt.

Klassen im Speicher:

vars_class.png

Eine Klasse ist einfach nur ein zusammenhängender Speicherblock, welcher alle Klassenvariablen der Reihe nach enthält. Natürlich ist das in Wahrheit erheblich komplexer, wie @Whiz-zarD weiter oben bereits angedeutet hatte. Zum anfänglichen Verständnis sollte dies dennoch ausreichend sein. Für die Abbildung habe ich Deine PlayerCharacter-Klasse von weiter oben verwendet und das xxx (x) soll einfach nur weitere Membervariablen und deren Wert symbolisieren.

Arrays im Speicher:

array_class.png

Hier habe ich versucht ein Array des Typs PlayerCharacter im Speicher darzustellen. Die []-Klammern stellen dabei den Index für den Zugriff auf die jeweiligen Arrayelemente dar. Die restlichen Bestandteile wurden im vorherigen Punkt ausgeführt.

Bearbeitet von el_pollo_diablo
Geschrieben (bearbeitet)

Und nach diesem Erklärungsversuch zu Deinem eigentlichen Post:

vor 7 Stunden schrieb Gewinde:

Da ich mittels Konstruktor ohnehin immer eine neues ( anders) Objekt als das vorherige erzeuge, ist ein Arrey/List zur erstellung vieler verschiedener Character gar nicht nötig?

Da hast Du @bene98 leider falsch verstanden. Jede Deklaration einer Variablen reserviert einen Speicherbereich in der passenden Größe (abhängig vom Variablentyp). Was er meinte ist, dass ein Array, bzw. eine Liste zum einfachen Zugriff auf vielen Variablen des gleichen Typs verwendet wird. Oder anders gesagt, irgendwie musst Du dem Computer ja mitteilen, auf welche Variablen Du zugreifen möchtest... Ohne einen "Container" würde man für jede Variable einen eigenen Variablennamen angeben müssen und bei vielen hundert Variablen mal zig Zugriffen ist das dann doch "etwas" umständlich.

vor 7 Stunden schrieb Gewinde:

            PlayerCharacter[] player = new PlayerCharacter[1];

            player[0] = new PlayerCharacter();

            PlayerCharacter population = new PlayerCharacter();

Diese drei Zeilen würden vereinfacht so dargestellt werden:

array_and_var.png

Der lila Bereich entspräche Deinem player-Array vom Typ PlayerCharacter mit einem einzigen Element. Der gelbe Bereich der Variablen population vom Typ PlayerCharacter.

Hier zeigt sich bereits, dass ein simples Handling (z.B. für das die Ausgabe der beiden eigenständigen Objekte via Console.WriteLine()) zwei getrennte Befehle benötigen würde:

Console.WriteLine(player[0]);
Console.WriteLine(population);

Viel bequemer geht dies dann natürlich unter Verwendung eines Arrays und über eine Schleife, z.B. die for-Variante, welche von Dir bereits gespostet worden ist.

Ich hoffe nun wenigstens etwas Licht ins Dunkel des Speicherkellers gebracht zu haben 😉

Bearbeitet von el_pollo_diablo
Geschrieben

Ich würde an deiner Stelle erst mal noch ein bisschen an der Klasse playerCharacter arbeiten. Hast du mal verschiedene Charakter angelegt und die in eine array List gepackt? Hast du eine to String Methode für die Ausgabe der Eigenschaften des Characters. Kannst du über die Liste iterieren und die Eigenschaften aller Charaktere ausgeben. Haben die Charaktere vielleicht Waffen? Dann könntest du eine klasse Weapon schreiben und einem Charakter eine Waffe zuordnen.

Geschrieben (bearbeitet)
vor 17 Stunden schrieb Gewinde:

Das Ergebnis ProjektTerra.PlayerCharacter finde ich etwas wenig aussagekräftig und daher bin ich mir jetzt nicht wirklich sicher ob der Versuch auch funktioniert hat. Bedeutet diese Ausgabe das die Speicherung erfolgt ist?

Natürlich ist sie erfolgreich, denn das Programm hat dir nichts gegenteiliges mitgeteilt. ;)

Hätte es nicht geklappt, hättest du ein "null" auf der Konsole ausgewiesen bekommen. Mit dem new-Operator befehligst du dem Gargabe Collector eine Instanz deiner Klasse zu erzeugen. D.h. der Gargabe Collector reserviert für dich den Speicher und gibt diesen auch wieder frei, wenn es keine Referenzen mehr auf dieses Objekt gibt. Die Referenz des Objektes speicherst du dann in dein Array.

Um etwas weiter auszuholen, wie die Speicherverwaltung funktioniert:

Es gibt erstmal zwei Arten von Datentypen: Wertetypen und Referenztypen.
Wertetypen sind z.B. int, double, decimal, float, ... Sie haben eine definierte Größe.
Referenztypen sind unsere Objekte. Sie haben eine variable größe. Je nachdem wie wir die Klassen schreiben.

Dann gibt es zwei Arten von Speicherbereichen: Stack und Heap.

Der Stack ist der Bereich, wo deine lokalen Variablen, je nach Zuständigkeitsbereich, abgelegt werden. Beispiel:

public void Methode()
{
    // i ist in der gesamten Methode sichtbar
    // da sie direkt im Methoden-Block deklariert wurde
    int i = 0; 
    
    for(int x = 0; x < 100; x++)
    {
        int j = 0;
        // x und j sind nur im Block der for-Schleife sichtbar
    }
}

Wenn man Methode() aufruft, dann wird für die Methode die Variable i auf den Stack gespeichert. Für die for-Schleife werden die Variablen x und j gespeichert. Innerhalb der Schleife haben wir Zugriff auf i, da die Schleife innerhalb des Zustänidgkeitsbereich der Methode liegt. Ist die Schleife dann durch, dann können die Variablen die innerhalb der for-Schleife deklariert worden sind, wieder entfernt werden (x und j), weil wir sie nicht mehr brauchen und alles, was außerhalb der Schleife ist, kann nicht darauf zugreifen.

Der Name "Stack" kommt daher, dass die Variablen immer auf einen Stapel gelegt werden. Dies ist möglich, weil die Größe einer Variable immer bekannt ist. Auch von Objekten, obwohl ich doch schrieb, dass sie unterschiedlich groß sind. Wieso das so ist, sehen wir gleich.

Der Heap ist für die Objekte zuständig. Wenn wir also ein Objekt mittels dem new-Operator erzeugen, ermittelt der Garbage Collector, wie groß ein Objekt ist und sucht im Heap einen geeigneten Speicherbereich und gibt uns eine sog. Referenz zurück. Die Referenz nicht der Wert des Objektes, sondern eine Speicheradresse. Also die Adresse im Speicher, wo auch unser Objekt liegt. Die Adresse ist je nach 32- oder 64-Bit-Anwendung auch 32- oder 64-Bit lang und somit schließt sich auch der Kreis um den Stack. Wenn wir also nun:

var player = new PlayerCharacter();

aufrufen, dann wird im Stack eine Variable mit dem Namen player gespeichert, die als Wert eine Speicheradresse besitzt.

Etwas ähnliches passiert auch mit deinem Array. Genaugenommen speicherst du also nicht die Objekte in einem Array, sondern lediglich nur die Referenzen und durch die geschickte Syntax ist dann eine sog. explizite Deferenzierung, wie unter C/C++ nicht nötig, denn die Deferenzierung wurde mit Hilfe der sog. Punkt-Notation gelöst. Wenn du jetzt schreibst:

Console.WriteLine(playerArray[0].Name);

Wird mit dem Punkt (.) hinter playerArray[0] die Adresse dereferenziert. D.h. wir haben dann Zugriff auf die Eigenschaften/Methoden des Objektes. Mit der Dereferenzierung teilen wir also mit, dass wir den Inhalt des Speicherbereichs haben wollen.

Ich hoffe, dass es erstmal so verständlich.

 

Dass die Konsole "ProjektTerra.PlayerCharacter" ausgibt ist auch richtig. Die Methode WriteLine() ruft von deinem Objekt wiederrum die ToString()-Methode auf. Diese Methode steht jeder Klasse zur Verfügung und die Standard-Implementierung ist halt, dass der vollqualifizierte Name der Klasse zurückgegeben wird. Mit Hilfe des Schlüsselwortes override kannst du aber diese auch überschreiben:

public class PlayerCharacter
{
    public override string ToString()
    {
        // Deine Implementierung
    }
}
Bearbeitet von Whiz-zarD
  • 2 Wochen später...
Geschrieben

Guten Tag zusammen,

ich habe mal wieder etwas rumgewerkelt und einige Vorschläge versucht in meinem Code einzubringen. Dieses Mal habe ich die angesprochene ToString() eingefügt und eine Schnittstelle verwendet. Außerdem habe ich die Verarbeitung der Charaktere mittels Arrey eingebunden.

Bei der ToString() gibt es soweit keine weiteren Fragen, ich denke diese ist leicht verständlich und funktioniert auch wunderbar in meinem Code. Hier lasse ich mir zum Schluss den Erschaffenen Charakter mit Namen und Eigenschaften ausgeben.

Mit dem Arrey habe ich noch so meine Probleme, welche allerdings eher auf noch nicht verstandenen Lernstoff zurückzuführen ist.

Wenn ich einen Charakter in ein Arrey speichere und diesen dann mittels For-Schleife und ToString() ausgeben lassen möchte, wird mir dieser auch ausgegeben, allerdings ohne dabei die Werte des Charakters zu verarbeiten.

            BasicCharacter character = new BasicCharacter();

            character.GetName();
            character.GetGenus();
            character.GetSex();
            character.GetHealth(character.Toughness);
            //Console.WriteLine(character.ToString());

            BasicCharacter[] characters = new BasicCharacter[1];
            characters[0] = new BasicCharacter();

            
            for(int i = 0; i < characters.Length; i++)
            {
              Console.WriteLine(characters[i].ToString());
            }

 

Das Ergebnis ist wie folgt:

Dein Charakter ist ein Human und sein Geschlecht ist neuter und sein Name ist .
Deine Attribute sind:
Healthbar: 0
Psipool: 0
Toughness: 0
Strength: 0
Agility: 0
Intelligent: 0
Sense: 0
Psionic: 0

Eigentlich sollten dort Rasse, Geschlecht, Name und die berechneten Werte stehen.

Wenn ich den Code ohne Arrey und nur mittels ToString() laufen lasse, sieht das Ergebnis folgendermaßen aus:

Dein Charakter ist ein Human und sein Geschlecht ist Male und sein Name ist Testfigur.
Deine Attribute sind:
Healthbar: 1000
Psipool: 0
Toughness: 200
Strength: 200
Agility: 200
Intelligent: 100
Sense: 200
Psionic: 200

Genau so sollte er nach euren vorgaben eigentlich auch aussehen. Daher denke ich, dass die ToString() funktiniert und bei den Arreys noch Nachholbedarf besteht.

Geschrieben

Ich glaube, dein Problem ist nicht das Array, sondern dass du das Prinzip der Objektorientierung noch nicht verstanden hast.

Ich glaube, dass auch deine Methoden GetName(), GetGenus(), GetSex() und GetHealth() keine Getter sind, sondern Setter. Es macht keinen Sinn, einfach Getter aufzurufen. Was machen dann diese Methoden? Setzen sie evtl. deine Statuswerte?

Mit der Codezeile

BasicCharacter character = new BasicCharacter();

erzeugst du ein Objekt vom Typ BasicCharacter aber mit der Zeile

characters[0] = new BasicCharacter(); 

erzeugst du ein weiteres Objekt. Beide Objekte sind aber unterschiedlich. Es sind also nicht die selben Objekte. Wenn du also im Array das selbe Objekt speichern möchtest, was du im oberen Code zuvor erzeugt hast, dann musst du

characters[0] = character;

schreiben.

Geschrieben

Ich würd dir empfehlen mal irgenwo einen Grunkurs zu machen in C#.

Ich habe so was immer bei codecademy gemacht-  ich denke danach siehst du schon deutlich klarer was da nicht funktioniert.

Geschrieben

Bei meinen Versuchen ist noch ein weiteres Problem aufgetreten. Ich habe in meinem Code die Methode GetHealth() eingefügt, welche mir wärend der Erstellung die Lebenspunkte des Charakters errechnen soll und diese natürlich in dem Attribute Healthbar abspeichern soll. Im Moment funktioniert die Methode folgendermaßen:

    class BasicCharacter : IPopulation
    {

                  .......

                   public int Healthbar { get; set; }

                  ........

                

                  public int GetHealth(int _toughness)
                 {
                       Healthbar = _toughness * 5;

                        return Healthbar;
                  }

Dieses Ergebnis stellt mich allerdings noch nicht zufrieden, da ich für diese Methode etwas anderes im Sinn hatte. Mit dieser Methode sollen die Lebenspunkte des Charakters in Abhängigkeit der Rasse (Genus) berechnet werden und dann im Attribute Healthbar gespeichert werden. Meine Idee dazu war folgende gewesen.

 

      public int Healthbar { get { return Healthbar;} set { GetHealth(Toughness);}

 

        public int GetHealth(int _toughness)
        {
            if(CharGenus == Genus.Human)
            {
                Healthbar = _toughness * 10;
            }
            else if(CharGenus == Genus.Experimental)
            {
                Healthbar = _toughness * 50;
            }else if(CharGenus == Genus.Psionic)
            {
                Healthbar = _toughness * 10;
            }

            return Healthbar;
        }

Allerdings führt diese Variante immer zu einer StackOverflowException. Wärend ich hier geschrieben habe, konnte ich das Problem lösen. Die Methode GetHealth(character.Touhgness) wird nun nach dem Konstruktor aufgerufen und ausgeführt. Der Getter und Setter der Eigenschaft Healthbar bleibt automatisch. Ich bin mir allerdings immer noch nicht sicher ob ich diese Variante zufrieden stellt (auch wenn ich mich freue wie Bolle).

In meiner Vorstellung sollte der (private) Setter das Ergebnis der Methode automatisch abholen. Ohne das ich den Aufruf direkt in static void Main(string[] args) einfügen muss. Ich hoffe es ist einigermaßen verständlich was ich meine.

Die angesprochenen Waffen vone bene98 werden demnächst in Angriff genommen, ich stelle mir dabei eine kleine Auswahl an Waffen vor, vielleicht mittels Waffenschnittstelle. Welche dann mittels Angriffsmethode verwendet werden können.

Danke euch alle.

 

Geschrieben
vor 2 Minuten schrieb Gewinde:

public int GetHealth(int _toughness)
{
    Healthbar = _toughness * 5;

    return Healthbar;
}

Getter sollten nichts setzen, weil es Seiteneffekte erzeugt, die man nicht haben möchte.
 

vor 4 Minuten schrieb Gewinde:

Allerdings führt diese Variante immer zu einer StackOverflowException.

Schaue dir dein Code genauer an:

public int Healthbar { get { return Healthbar;} set { GetHealth(Toughness);} 

Was macht der Getter von Healtbar? Er ruft sich selbst auf und erzeugt eine unendliche Rekursion, was deine StackOverflowException auslöst.

Geschrieben

Jetzt wo ihr mich mit der Nase drauf drückt fällt mir das natürlich auch ins Auge. Ja die GetMethoden sollten natürlich SetMethoden sein. Bei dem return fehlt wahrscheinlich noch die variable.

int healthbar;

public int Healthbar {get{ return healthbar;} set{.....}

denke das meintest du damit. Ja da fällt mir wohl jedesmal die wenige Praxiszeit auf die Füße. Ich komme leider nur sehr selten dazu mein Hobby weiterzuentwickeln, weshalb natürlich Lücken entstehen.

Als Grundkurs benutze ich https://produkte.programmieren-starten.de

Vielleicht sollte ich nochmal von vorne anfangen um gelerntes zu festigen und halbgelerntes besser zu verstehen. Mit der OOP wird das ganze auch wesentlich komplexer als mit den einfachen Variablen.

Selbige zählt für das Arrey, so wie du es schreibst macht es mehr sinn.

Danke für eure Kretik bzw. Tipps, ich habe den Code nochmal mit  Setmethoden umgewandelt:

        static void Main(string[] args)
        {
            BasicCharacter character = new BasicCharacter();

            character.SetName();
            character.SetGenus();
            character.SetSex();
            character.SetHealth(character.Toughness);
            character.SetPsionic(character.Psionic, character.Intelligent);
            //Console.WriteLine(character.ToString());

            BasicCharacter[] characters = new BasicCharacter[1];
            characters[0] = character;

            
            for(int i = 0; i < characters.Length; i++)
            {
               Console.WriteLine(characters[i].ToString());
            }

            Console.ReadKey();

        }

 

Und den Code in der Klasse selbst:

    class BasicCharacter : IPopulation
    {

        public enum Genus { Human, Psionic, Experimental }
        public enum Sex { neuter, Male, Female }

        //Attribues...

        public string Name { get; set; }
        public int Healthbar { get; set; }
        public int Psipool { get; set; }
        public int Toughness { get; set; }
        public int Strength { get; set; }
        public int Agility { get; set; }
        public int Intelligent { get; set; }
        public int Sense { get; set; }
        public int Psionic { get; set; }
        public Genus CharGenus { get; set; }
        public Sex CharSex { get; set; }

        //Methodes...

        public void SetGenus()
        {
            int genusChoice = 0;

            do
            {
                Console.WriteLine("Bitte suche den Genustyp deines Charakters aus...\n");
                Console.WriteLine("Soll dein Charakter ein Mensch sein, dann drücke die (1)");
                Console.WriteLine("Soll dein Charakter ein Psioniker sein, dann drücke die (2)");
                Console.WriteLine("Wenn dein Charakter im Labor erschaffen wurde, dann drücke die (3)");

                genusChoice = Convert.ToInt32(Console.ReadLine());

                switch (genusChoice)
                {
                    case 1:
                        CharGenus = Genus.Human;
                        Toughness = 200; Strength = 200; Agility = 200; Intelligent = 100; Sense = 200; Psionic = 200;
                        break;
                    case 2:
                        CharGenus = Genus.Psionic;
                        Toughness = 150; Strength = 150; Agility = 150; Intelligent = 200; Sense = 200; Psionic = 400;
                        break;
                    case 3:
                        CharGenus = Genus.Experimental;
                        Toughness = 500; Strength = 500; Agility = 200; Intelligent = 50; Sense = 150; Psionic = 50;
                        break;
                }

                if(genusChoice < 1 || genusChoice > 3)
                {
                    Console.WriteLine("Ups, da ist wohl gerade ein Fehler aufgetreten. Versuchen sie es bitte noch einmal...");
                }

            }while(genusChoice < 1 || genusChoice > 3);
        }

        public void SetSex()
        {
            if(CharGenus == Genus.Experimental)
            {
                CharSex = Sex.neuter;
                return;
            }

            int sexChoice = 0;

            do
            {
                Console.WriteLine("Soll dein Charakter männlich oder weiblich sein?\n");
                Console.WriteLine("Für einen männlichen Charakter drücke bitte die (1)");
                Console.WriteLine("Für einen weiblichen Charakter drücke bitte die(2)");

                sexChoice = Convert.ToInt32(Console.ReadLine());

                if (sexChoice == 1)
                {
                    CharSex = Sex.Male;
                    break;
                }
                else if (sexChoice == 2)
                {
                    CharSex = Sex.Female;
                    break;
                }
                else if (sexChoice < 1 || sexChoice > 2)
                {
                    Console.WriteLine("Da hat wohl etwas nicht funktioniert, bitte versuchen sie es noch einmal...");
                }
            } while (sexChoice < 1 || sexChoice > 2);
        }

        public void SetName()
        {
            Console.Write("Gebe bitte einen Namen für deinen Charakter ein: ");
            Name = Console.ReadLine();
        }

        public int SetHealth(int _toughness)
        {
            if(CharGenus == Genus.Human)
            {
                Healthbar = _toughness * 10;
            }
            else if(CharGenus == Genus.Experimental)
            {
                Healthbar = _toughness * 50;
            }else if(CharGenus == Genus.Psionic)
            {
                Healthbar = _toughness * 10;
            }

            return Healthbar;
        }

        public int SetPsionic(int _psionic, int _intelligent)
        {
            if (CharGenus == Genus.Human)
            {
                Psipool = (_psionic + _intelligent) * 5;
            }
            else if (CharGenus == Genus.Experimental)
            {
                Psipool = (_psionic + _intelligent) * 2;
            }
            else if (CharGenus == Genus.Psionic)
            {
                Psipool = (_psionic + _intelligent) * 8;
            }

            return Psipool;
        }

        public override string ToString()
        {
            string message = "Dein Charakter ist ein " + CharGenus + " und sein Geschlecht ist " + CharSex + " und sein Name ist " + Name + ".\n" +
                "Deine Attribute sind:\nHealthbar: " + Healthbar + "\nPsipool: " + Psipool + "\nToughness: " + Toughness + "\nStrength: " + Strength + "\nAgility: " + Agility + "\nIntelligent: " + Intelligent + "\nSense: " + Sense + "\nPsionic: " + Psionic;
            return message.ToString();
        }
    }

 

Als nächstes werde ich mir eure antworten aber erstmal zu herzen nehmen und nochmal ein paar Schritte zurück springen.

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...