Ich bin grade dabei ein Textbasiertes Spiel (Rollenspiel sollte man warscheinlich sagen oder "Adventure") zu erstellen und ich bin dabei auf ein paar Umsetzungsprobleme gestoßen und auch sonst will ich einfach einen guten konzeptionellen Weg gehen.
Ich bin auch noch nicht so lange im OOP Bereich aber ich wollte unbedingt mal ein paar kleiner Projekte für mich selbst erledigen.
Zudem habe ich da auch noch so ein kleines Problem mit einer Schleife und ich finde da den Fehler irgendwie nicht.
Erst einmal zu den konzeptionellen Fragen:
1. Ich bin grade an einer "Monster" oder Kreatur Klasse dran und ich habe das ganze jetzt so geregelt, das ein Monster in einem Raum existieren darf aber nicht mehr. Wenn man mehrere Monster in einem Raum haben wollte, müsste man diese ja einfach nur in einer Hashmap oder einer andere Collection (im Raum) speichern, oder?
2.
2.1 Ich habe jetzt eine Klasse Lebewesen erstellt und eine Klasse Spieler und eine Klasse Monster erben grade davon. Die Klasse Lebewesen ist abstrakt.
Das sieht bei mir derzeit so aus:
und dann ein Monster:
Ist das so ein guter Ansatz? Da der Spieler ja auch noch einige zusätzliche Werte hat, wie evtl. Hunger oder Durst habe ich die Methode istTot nur als abstract gekennzeichnet und ohne eine Implementierung.
2.2 Wie man sieht habe ich ja auch noch eine Methode kannSpielerVerfolgen und dazu hätte ich auch noch eine Frage. In meiner "Spiel" Klasse, also da wo das Spiel initialisiert wird etc. rufe ich dann bei der Eingabe von angriff eine Methode kampf auf. Da gibt es dann aber auch immer ein Problem. Ich setze ja jetzt bspw. so eigentlich immer voraus, das der Spieler zuerst angreift und dem ist ja auch so aber müsste man nicht auch noch vor monster.attack() dann prüfen, ob das monster nicht evtl. schon vom Spieler angegriffen wurde? Ansonsten würde das tote Monster den Spieler ja auch wieder angreifen können?
In der Methode habe ich auch noch zwei zusätzliche Probleme und da ist auch das Schleifenproblem aber wie gesagt, erst einmal das konzeptionelle.
2.3 Da ich ja wie schon in 2.2 gesagt immer mehr oder weniger voraussetze, das der Spieler zuerst angreift bin ich auf ein Problem gestoßen. Ich wollte das jetzt kurz vor dem Ausgang und auch in ein paar anderen Räumen so machen, das die Monster eine Chance von 40% oder so haben, den Spieler zu "sehen" und ihn dann anzugreifen. Dazu müsste aber ja jetzt natürlich das Monster zuerst angreifen.
Ich habe das jetzt so gelöst, das ich in der Methode die auch in der Klasse Spiel ist, prüfe, ob es sich dabei um einen speziellen Raum handelt, da wo der Spieler bspw. auf jeden Fall gesehen werden soll. Das befindet sich jetzt in der Methode, die aufgerufen wird, wenn der Spieler weitergeht:
Aber ist das wohl ein guter Weg oder gibt es da noch eine bessere Möglichkeit? Wie könnte ich das aber dann z.B auch noch allgemein halten, also das es in jedem Raum vielleicht auch unterschiedliche Chancen gibt, das der Spieler gseehen wird?
3.
3.1 Ich würde jetzt auch gerne spezielle Gegenstände erstellen, also bspw. sowas wie ein Schwert oder einen allgemeinen Gegenstand wie eine Wasserflasche oder dergleichen erstellen. Erst einmal habe ich auch dafür wieder eine Klase Gegenstand erstellt.
und dann, bspw. für das Wasser oder allgemein "trinkbare" Gegenstände eine Klasse "Trinkbar" erstellt.
Da bräuchte man dann ja auch eigentlich nur noch ein Attribut, das beschreibt wie viele Durst oder dergleichen das Objekt still und dann noch eine Methode, die aufgerufen wird, wie z.B trinken() und da wird dann einfach der Durst des Spielers gesetzt aber aber wie sorge ich dafür, das wenn der Gegenstand Wasserflasche benutzt wird auch die Methode trinken aufgerufen wird? Müsste das dann auch in die Spiel Klasse?
3.2 Wenn ich jetzt auch beispielsweise auch noch ein Schwert oder eine Waffe mit magischen Fähigkeiten erstellen wollte, dann bräuchte man doch auch wieder eine neue Klasse aber würde man dafür auch wieder eine Klasse Waffe erst einmal erstellen oder sowas wie eine Klasse Magisch, die sich dann von Gegenstand ableitet und dann das Schwert von "Magisch"?
4. Analog dazu:
Wie würde man das bei Monstern machen, also wenn die auch noch eine Fähigkeit haben, dann würde ein Objekt von Monster ja eigentlich nicht mehr reichen oder? Dann müsste man ja schon ein Klasse von Monster ableiten, z.B ein Hexer?
Wie geht man aber dann auch nachher sicher, das der Hexer dann auch seine Fähigkeit evtl. mal anwendet? Könnte man das auch wieder mit so einer Prozentualen Lösung machen und evtl. einem "Cooldown"?
Zu 3. & 4
Wie man es dann erreichen könnte das der Schaden etc. dann für kurze Zeit bei einer Schadensfähigkeit erhöht wird, wäre mir schon klar aber wie könnte eine Implementierung für einen Gifteffekt oder so aussehen? Der müsste dann ja beim Spieler implementiert sein, nehme ich mal an? Wenn man da mit Schaden/Zeit was machen müsste, wie würde man das dann machen? Mit einem Timer?
Bräuchte man dann eigentlich auch evtl. sogar noch eine Klasse Fähigkeit oder würde das eher zu den Monstern/Spielern bzw. den Gegenständen gehören?
So, das wäre auch das konzeptionelle. Ich habe da auch noch immer so ein paar Zuordnungsprobleme, wie man vielleicht auch sieht, also bspw. wo man dann auch nachher welche Methode verstaut.
Nun zu dem Schleifenproblem: (Ist bei 3 die Kampf Methode)
Wenn ich das Programm dann mal so laufen lasse, dann kriege ich diese Ausgabe:
Ich habe jetzt auch mal einige Teile entfernt, damit das ganze hier nicht zu überladen wird aber wie man sieht, läuft die Schleife einmal zu viel aber warum? Ich muss, obwohl der Spieler "Tobias" ja oben schon tot ist, trotzdem noch einmal eine Eingabe machen aber wieso? Der Spieler ist ja, wie man oben sieht tot? (0 Lebenspunkte).
Wieso wird die Schleife dann trotzdem noch einmal ausgeführt oder bin ich grade einfach nur zu müde? Irgendwie finde ich den Fehler nicht ...
Puuuh .. das wärs dann auch. Danke schon einmal für jede Hilfe und jeden Ratschlag.
Ich bin auch noch nicht so lange im OOP Bereich aber ich wollte unbedingt mal ein paar kleiner Projekte für mich selbst erledigen.
Zudem habe ich da auch noch so ein kleines Problem mit einer Schleife und ich finde da den Fehler irgendwie nicht.
Erst einmal zu den konzeptionellen Fragen:
1. Ich bin grade an einer "Monster" oder Kreatur Klasse dran und ich habe das ganze jetzt so geregelt, das ein Monster in einem Raum existieren darf aber nicht mehr. Wenn man mehrere Monster in einem Raum haben wollte, müsste man diese ja einfach nur in einer Hashmap oder einer andere Collection (im Raum) speichern, oder?
2.
2.1 Ich habe jetzt eine Klasse Lebewesen erstellt und eine Klasse Spieler und eine Klasse Monster erben grade davon. Die Klasse Lebewesen ist abstrakt.
Das sieht bei mir derzeit so aus:
Java:
public abstract class Lebewesen
{
private String name;
private int schaden;
private int lebenspunkte;
private Raum aktuellerRaum;
/**
* Konstruktor der Klasse Lebewesen
*/
public Lebewesen(String name, int lebenspunkte, int schaden, Raum startRaum)
{
this.name = name;
this.schaden = schaden;
this.lebenspunkte = lebenspunkte;
this.aktuellerRaum = startRaum;
}
/**
* @return Gibt die Lebenspunkte des Lebewesens zurück.
*/
public int getLebenspunkte()
{
return lebenspunkte;
}
/**
* @return Gibt den Schaden des Lebewesens zurück.
*/
public int getSchaden()
{
return schaden;
}
/**
* @return Gibt den Raum zurück, in dem sich das Lebewesen grade befindet.
*/
public Raum getAktuellerRaum()
{
return aktuellerRaum;
}
/**
* Setter für den Raum des Lebewesens
*/
public void setAktuellerRaum(Raum raum)
{
aktuellerRaum = raum;
}
/**
* Setter für die Lebenspunkte des Lebewesens
*/
public void setLebenspunkte(int lebenspunkte)
{
this.lebenspunkte = lebenspunkte;
}
/**
* Setter für den Schaden des Lebewesens
*/
public void getSchaden(int schaden)
{
this.schaden = schaden;
}
/**
* @return Gibt den "Status" des Lebewesens wieder, also ob es tot oder lebendig ist.
* Gibt 'true' zurück, wenn das Lebewesen tot ist, andernfalls 'false'.
*/
public abstract boolean istTot();
public void attack(Lebewesen lebewesen)
{
int damage = Math.max(0, this.getSchaden());
int health = lebewesen.getLebenspunkte() - damage;
System.out.println(this.getName() + "'s angriff hat " + damage + " Schaden angerichtet!\n");
System.out.println(lebewesen.getName() + "'s Lebenspunkte: " + health);
lebewesen.setLebenspunkte(health);
}
}
und dann ein Monster:
Java:
import java.util.Iterator;
public class Monster extends Lebewesen
{
public Monster(String name, int lebenspunkte, int schaden, Raum raum)
{
super(name, lebenspunkte, schaden, raum);
raum.setMonster(this);
}
public String gibBeschreibung()
{
String returnString = getAktuellerRaum().gibLangeBeschreibung();
returnString += "Lebenspunkte " + getLebenspunkte();
return returnString;
}
public boolean istTot()
{
if(getLebenspunkte() < 1)
return true;
return false;
}
public boolean kannSpielerVerfolgen()
{
if(Math.random() < 0.2) // 20% chance
return true;
return false;
}
}
Ist das so ein guter Ansatz? Da der Spieler ja auch noch einige zusätzliche Werte hat, wie evtl. Hunger oder Durst habe ich die Methode istTot nur als abstract gekennzeichnet und ohne eine Implementierung.
2.2 Wie man sieht habe ich ja auch noch eine Methode kannSpielerVerfolgen und dazu hätte ich auch noch eine Frage. In meiner "Spiel" Klasse, also da wo das Spiel initialisiert wird etc. rufe ich dann bei der Eingabe von angriff eine Methode kampf auf. Da gibt es dann aber auch immer ein Problem. Ich setze ja jetzt bspw. so eigentlich immer voraus, das der Spieler zuerst angreift und dem ist ja auch so aber müsste man nicht auch noch vor monster.attack() dann prüfen, ob das monster nicht evtl. schon vom Spieler angegriffen wurde? Ansonsten würde das tote Monster den Spieler ja auch wieder angreifen können?
Java:
private void kampf(Befehl befehl)
{
boolean fliehen = false;
Monster monster = spieler.getAktuellerRaum().getMonster();
do
{
spieler.attack(monster);
monster.attack(spieler);
System.out.println("Weiterkämpfen? Dann geben Sie bitte 'weiter' ein.");
parser.getEingabeBefehl();
String befehlswort = befehl.gibEingabeBefehl();
if (befehlswort.equals("weiter"))
{
}
else if(befehlswort.equals("fliehen"))
{
spieler.getAktuellerRaum().setZufaelligerFluchtraum(spieler);
if(monster.kannSpielerVerfolgen())
{
monster.attack(spieler);
System.out.println("Sie konnten leider nicht entkommen. Das Monster hat Sie zudem angegriffen!");
System.out.println("Was möchten Sie machen? Weiterkämpfen oder weiter versuchen zu fliehen?");
}
else
{
fliehen = true;
return;
}
}
System.out.println("Loop Spieler LP: " + spieler.getLebenspunkte());
System.out.println("Loop Monster LP: " + monster.getLebenspunkte());
System.out.println("Loop Spieler Tot: " + spieler.istTot());
System.out.println("Loop Monster Tot: " + monster.istTot());
}
while ((!spieler.istTot() && !monster.istTot()) && !fliehen);
System.out.println("Spieler LP: " + spieler.getLebenspunkte());
System.out.println("Monster LP: " + monster.getLebenspunkte());
if (!spieler.istTot())
System.out.println("Sie haben den Kampf gewonnen!");
else if (!monster.istTot())
System.out.println("Sie haben den Kampf verloren!");
}
In der Methode habe ich auch noch zwei zusätzliche Probleme und da ist auch das Schleifenproblem aber wie gesagt, erst einmal das konzeptionelle.
2.3 Da ich ja wie schon in 2.2 gesagt immer mehr oder weniger voraussetze, das der Spieler zuerst angreift bin ich auf ein Problem gestoßen. Ich wollte das jetzt kurz vor dem Ausgang und auch in ein paar anderen Räumen so machen, das die Monster eine Chance von 40% oder so haben, den Spieler zu "sehen" und ihn dann anzugreifen. Dazu müsste aber ja jetzt natürlich das Monster zuerst angreifen.
Ich habe das jetzt so gelöst, das ich in der Methode die auch in der Klasse Spiel ist, prüfe, ob es sich dabei um einen speziellen Raum handelt, da wo der Spieler bspw. auf jeden Fall gesehen werden soll. Das befindet sich jetzt in der Methode, die aufgerufen wird, wenn der Spieler weitergeht:
Java:
private void wechsleRaum(Befehl befehl)
{
Raum aktuellerRaum = spieler.getAktuellerRaum();
....
if (naechsterRaum == null)
{
System.out.println("\nIn dieser Richtung befindet sich kein Raum!");
}
else if(spieler.weitergehen(richtung))
{
aktuellerRaum = naechsterRaum;
System.out.println(aktuellerRaum.getBeschreibung());
if(aktuellerRaum == vorAusgang)
{
monster.attack(spieler);
System.out.println("Sie wurden von einem Monster angegriffen, was möchten Sie tun?");
}
}
}
Aber ist das wohl ein guter Weg oder gibt es da noch eine bessere Möglichkeit? Wie könnte ich das aber dann z.B auch noch allgemein halten, also das es in jedem Raum vielleicht auch unterschiedliche Chancen gibt, das der Spieler gseehen wird?
3.
3.1 Ich würde jetzt auch gerne spezielle Gegenstände erstellen, also bspw. sowas wie ein Schwert oder einen allgemeinen Gegenstand wie eine Wasserflasche oder dergleichen erstellen. Erst einmal habe ich auch dafür wieder eine Klase Gegenstand erstellt.
Java:
public class Gegenstand
{
private String name;
private String beschreibung;
public Gegenstand(String name, String beschreibung)
{
this.name = name;
this.beschreibung = beschreibung;
}
public String getName() {
return name;
}
public String getBeschreibung() {
return beschreibung;
}
}
und dann, bspw. für das Wasser oder allgemein "trinkbare" Gegenstände eine Klasse "Trinkbar" erstellt.
Java:
public class Trinkbar extends Gegenstand
{
public Trinkbar(String name, String beschreibung)
{
super(name, beschreibung);
}
/*
public void trinken()
{
// Durst des Spielers holen und anschleißend mit dem stillendem Durst addieren und dann set aufrufen?
// und anschließend den Gegenstand entfernen?
}
*/
}
Da bräuchte man dann ja auch eigentlich nur noch ein Attribut, das beschreibt wie viele Durst oder dergleichen das Objekt still und dann noch eine Methode, die aufgerufen wird, wie z.B trinken() und da wird dann einfach der Durst des Spielers gesetzt aber aber wie sorge ich dafür, das wenn der Gegenstand Wasserflasche benutzt wird auch die Methode trinken aufgerufen wird? Müsste das dann auch in die Spiel Klasse?
3.2 Wenn ich jetzt auch beispielsweise auch noch ein Schwert oder eine Waffe mit magischen Fähigkeiten erstellen wollte, dann bräuchte man doch auch wieder eine neue Klasse aber würde man dafür auch wieder eine Klasse Waffe erst einmal erstellen oder sowas wie eine Klasse Magisch, die sich dann von Gegenstand ableitet und dann das Schwert von "Magisch"?
4. Analog dazu:
Wie würde man das bei Monstern machen, also wenn die auch noch eine Fähigkeit haben, dann würde ein Objekt von Monster ja eigentlich nicht mehr reichen oder? Dann müsste man ja schon ein Klasse von Monster ableiten, z.B ein Hexer?
Wie geht man aber dann auch nachher sicher, das der Hexer dann auch seine Fähigkeit evtl. mal anwendet? Könnte man das auch wieder mit so einer Prozentualen Lösung machen und evtl. einem "Cooldown"?
Zu 3. & 4
Wie man es dann erreichen könnte das der Schaden etc. dann für kurze Zeit bei einer Schadensfähigkeit erhöht wird, wäre mir schon klar aber wie könnte eine Implementierung für einen Gifteffekt oder so aussehen? Der müsste dann ja beim Spieler implementiert sein, nehme ich mal an? Wenn man da mit Schaden/Zeit was machen müsste, wie würde man das dann machen? Mit einem Timer?
Bräuchte man dann eigentlich auch evtl. sogar noch eine Klasse Fähigkeit oder würde das eher zu den Monstern/Spielern bzw. den Gegenständen gehören?
So, das wäre auch das konzeptionelle. Ich habe da auch noch immer so ein paar Zuordnungsprobleme, wie man vielleicht auch sieht, also bspw. wo man dann auch nachher welche Methode verstaut.
Nun zu dem Schleifenproblem: (Ist bei 3 die Kampf Methode)
Wenn ich das Programm dann mal so laufen lasse, dann kriege ich diese Ausgabe:
Code:
>
Loop Spieler LP: 40
Loop Monster LP: 60
Loop Spieler Tot: false
Loop Monster Tot: false
Tobias's angriff hat 10 schaden gemacht!
Höhlenwolf's Lebenspunkte: 50
Höhlenwolf's angriff hat 20 schaden gemacht!
Tobias's Lebenspunkte: 20
Weiterkämpfen? Dann geben Sie bitte 'weiter' ein.
>
Loop Spieler LP: 20
Loop Monster LP: 50
Loop Spieler Tot: false
Loop Monster Tot: false
Tobias's angriff hat 10 schaden gemacht!
Höhlenwolf's Lebenspunkte: 40
Höhlenwolf's angriff hat 20 schaden gemacht!
Tobias's Lebenspunkte: 0
Weiterkämpfen? Dann geben Sie bitte 'weiter' ein.
>
Loop Spieler LP: 0
Loop Monster LP: 40
Loop Spieler Tot: true
Loop Monster Tot: false
Spieler LP: 0
Monster LP: 40
Sie haben den Kampf verloren!
Ich habe jetzt auch mal einige Teile entfernt, damit das ganze hier nicht zu überladen wird aber wie man sieht, läuft die Schleife einmal zu viel aber warum? Ich muss, obwohl der Spieler "Tobias" ja oben schon tot ist, trotzdem noch einmal eine Eingabe machen aber wieso? Der Spieler ist ja, wie man oben sieht tot? (0 Lebenspunkte).
Wieso wird die Schleife dann trotzdem noch einmal ausgeführt oder bin ich grade einfach nur zu müde? Irgendwie finde ich den Fehler nicht ...
Puuuh .. das wärs dann auch. Danke schon einmal für jede Hilfe und jeden Ratschlag.
Zuletzt bearbeitet: