Hallo,
hier zuerst eine kurze Einführung, um mein Problem zu erläutern. Mache momentan einen Java Kurs und mir sollten jetzt ein Text-basiertes Spiel erweitern. Mein Spiel kann eigentlich schon deutlich mehr als gefordert aber das ist nicht das Problem. Eher das Design ist IMHO irgendwie nicht so toll.
Es geht mir also mehr um das Desing also das Spiel. Deshalb habe ich dieses Unterforum gewählt.
Das Problem:
Es gibt eine Klasse GameCharacter(kann böse oder gut sein) und eine Klasse Player, die beide von der gleichen abstrakten Klasse GameFigure erben. Eine GameFigure kann bewaffnet sein und die Waffe benutzen, es gibt also auch eine Klasse Weapon.
GameFigure haben einen Gesundheitslevel.
Jetzt will ich einen Kampf zw. Player und GameCharacter simulieren.
Welche Klasse ist jetzt verantwortlich für das abfeuern der Waffe? (GameFigure? oder die Waffe selbst?)
Jede Waffe verfolgt wieviele Schüsse noch im Magazin sind. Ist sie leergeschossen, muss man zuerst nachladen. Wo kontrolliere ich den Ladestatus? Immer bevor man die Waffe benutzt? (etwa so: player.getWeapon().isLoaded())
Oder in der "benutzen" Methode selbst?(Wie gebe ich dann zurück, dass die Waffe nicht abgefeuert wurde bzw. aus welchem Grund nicht? Es kann auch sein, dass der Spieler keine Waffe hat, dann muss er flüchten (brauche mehr als 2 Zustände)).
Jetzt beim schreiben kommt mir folgende Gedanke: enum "useWeaponResult" fired, empty, unarmed.
Aber dies löst das Hauptproblem nicht. Momentan gebe ich in x-verschiedenen Klassen direkt Text aus (anstatt in einer "AusgabeKlasse"), weil es so am einfachsten ist.
Es ist schwer zu erklären, deshalb hier mal die momentane statische Kampfklasse, um das Problem zu zeigen bzw das, ähm, ned so tolle Design. Allgemein macht mir das wesentlich mehr Mühe. Ein Problem zu lösen, geht meist, irgendwie, nur ob es ein guter weg ist, ist die andere Frage.
Daneben gibts noch die Command und Game Klasse, die ebenfalls direkt Text ausgeben. Momentan ist dies kein Problem, aber sobald man zb, ein GUI machen möchte, sieht es düster aus. Wie man sieht ist momentan die Waffe selbst für abfeuern zuständig, aber mehr als die Munition um 1 zu veringern tut die Methode selbst nicht.
Die Frage ist auch, wo diese "Kampf-Logik" hin gehört. In eine eigene Klasse?
Oder in die GameFigure klasse mit methode:
fireWeapon(GameFigure target);
Fragen über fragen...
hier zuerst eine kurze Einführung, um mein Problem zu erläutern. Mache momentan einen Java Kurs und mir sollten jetzt ein Text-basiertes Spiel erweitern. Mein Spiel kann eigentlich schon deutlich mehr als gefordert aber das ist nicht das Problem. Eher das Design ist IMHO irgendwie nicht so toll.
Es geht mir also mehr um das Desing also das Spiel. Deshalb habe ich dieses Unterforum gewählt.
Das Problem:
Es gibt eine Klasse GameCharacter(kann böse oder gut sein) und eine Klasse Player, die beide von der gleichen abstrakten Klasse GameFigure erben. Eine GameFigure kann bewaffnet sein und die Waffe benutzen, es gibt also auch eine Klasse Weapon.
GameFigure haben einen Gesundheitslevel.
Jetzt will ich einen Kampf zw. Player und GameCharacter simulieren.
Welche Klasse ist jetzt verantwortlich für das abfeuern der Waffe? (GameFigure? oder die Waffe selbst?)
Jede Waffe verfolgt wieviele Schüsse noch im Magazin sind. Ist sie leergeschossen, muss man zuerst nachladen. Wo kontrolliere ich den Ladestatus? Immer bevor man die Waffe benutzt? (etwa so: player.getWeapon().isLoaded())
Oder in der "benutzen" Methode selbst?(Wie gebe ich dann zurück, dass die Waffe nicht abgefeuert wurde bzw. aus welchem Grund nicht? Es kann auch sein, dass der Spieler keine Waffe hat, dann muss er flüchten (brauche mehr als 2 Zustände)).
Jetzt beim schreiben kommt mir folgende Gedanke: enum "useWeaponResult" fired, empty, unarmed.
Aber dies löst das Hauptproblem nicht. Momentan gebe ich in x-verschiedenen Klassen direkt Text aus (anstatt in einer "AusgabeKlasse"), weil es so am einfachsten ist.
Es ist schwer zu erklären, deshalb hier mal die momentane statische Kampfklasse, um das Problem zu zeigen bzw das, ähm, ned so tolle Design. Allgemein macht mir das wesentlich mehr Mühe. Ein Problem zu lösen, geht meist, irgendwie, nur ob es ein guter weg ist, ist die andere Frage.
Java:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
/**
* This class describes events that can occur in the game. Convert to abstract or Interface
* for a more general use.
*
* @author XXXXXXXX
* @version 0.1
*/
public class GameEvents
{
private static boolean finishFight;
private static int nrOfItems;
/**
* Constructor for objects of class GameEvents
*/
public GameEvents()
{
}
public static boolean onRoomEntry(Room newRoom, Player player)
{
HashSet<GameCharacter> gameCharacters =
new HashSet<GameCharacter>();
gameCharacters = newRoom.getCharactersInRoom();
GameCharacter currentCharacter;
for(Iterator iter =
gameCharacters.iterator(); iter.hasNext(); ){
currentCharacter = (GameCharacter)iter.next();
if (currentCharacter.getType() == CharacterType.EVIL){
//implement other behaviours like agrressivnes, evil but unarmed,...
return startFireFight(currentCharacter, player);
}
else if (currentCharacter.getType() == CharacterType.FRIENDLY){
// implement friendly character
}
}
return false;
}
public static boolean startFireFight(
GameCharacter evilPerson, Player player)
{
Random rand = new Random();
nrOfItems = evilPerson.getNumberOfItems();
boolean finishFight = false;
while(! finishFight) {
if (evilTurnInFight(evilPerson, player))
//player died. finishGame = true;
return true;
if (!playerTurnInFight(evilPerson, player)){
// evilPerson dead, Game continues
return false;
}
if(fleeFromRoom(evilPerson)){
finishFight = true;
return false;
}
}
return false;
}
/**
* Player turn in fight
*
* @return if the fight should continue or not
*/
private static boolean playerTurnInFight(GameCharacter evilPerson, Player player)
{
Random rand = new Random();
Weapon playerWeapon = player.getCurrentWeapon();
Parser parser = new Parser();
Room currentRoom = ((Room)player.getCurrentOwner());
Command command = parser.getCommand();
if(!(command instanceof WeaponCommand)) {
System.out.println("You are in a fire fight!");
System.out.println("You can't do that now!");
} else {
while(playerWeapon == null){
System.out.println("You have to flee or select a weapon!");
//punish player for beeing unarmed
evilTurnInFight(evilPerson, player);
command = parser.getCommand();
if(!((command instanceof GoCommand) || (command instanceof SelectCommand))) {
//punish player entering wrong command
System.out.println("You can't do that now!");
System.out.println("Select a weapon or flee!");
evilTurnInFight(evilPerson, player);
}
else if (command instanceof GoCommand){
//flee! Change Room and leave fight
command.execute(player);
return false;
}
else if (command instanceof SelectCommand){
//select a weapon. if invalid enemy will get
//more free shots.
finishFight = command.execute(player);
playerWeapon = player.getCurrentWeapon();
}
}
// fire only if ammo available.
if (command.getSecondWord().equalsIgnoreCase("fire")){
if (playerWeapon.getAmmoInMagazine() > 0){
finishFight = command.execute(player);
if (evilPerson.changeHealth(
-5*playerWeapon.getFirePower())){
System.out.println(
"You shot your enemy " + evilPerson.getName() + "!");
System.out.println("But he is still alive!");
}
else{
System.out.println("You killed " + evilPerson.getName() + "!");
currentRoom.removeItem(evilPerson);
if(nrOfItems > 0)
System.out.println(evilPerson.getName() + " dropped something!");
finishFight = true;
return false;
}
}
else
//we get here when weapon is unloaded, 0 shots in magazine
//the command has not yet been executed.
finishFight = command.execute(player);
}
else if (command.getSecondWord().equalsIgnoreCase("reload")){
finishFight = command.execute(player);
//punish player while reloading
int time = playerWeapon.getReloadTime()/2;
// if player still has ammo, reload
if(player.getAmmunitionLeft(playerWeapon.getAmmunitionType()) > 0){
for (int i = time; i > 0; i--){
evilTurnInFight(evilPerson, player);
System.out.println("Reloading...");
}
}
else {
System.out.println("No Ammunition left. You must run!");
command = parser.getCommand();
if(!(command instanceof GoCommand)) {
//punish player entering wrong command
System.out.println("You can't do that now!");
System.out.println("You must run away to stay alive!");
evilTurnInFight(evilPerson, player);
}
else{
// run away = leave the room
finishFight = command.execute(player);
return false;
}
}
}
}
return true;
}
/**
* Turn of the evil Player in a fire fight
*
* @return wether the Player died during this turn or not
*/
private static boolean evilTurnInFight(GameCharacter evilPerson, Player player)
{
Random rand = new Random();
Weapon evilWeapon = evilPerson.getCurrentWeapon();
if (evilWeapon.fireWeapon()){
if (rand.nextDouble() < evilPerson.getShootingAccuracy()){
if (player.changeHealth(-evilWeapon.getFirePower()*rand.nextInt(11))){
System.out.println("You have been shot by " + evilPerson.getName() + "!");
System.out.println("Fire back!");
System.out.println(
"Health left: " + player.getHealth());
}
else {
System.out.println("You are shot!");
System.out.println("You lost the fight!");
System.out.println("You are dead!");
finishFight = true;
return finishFight;
}
}
else{
System.out.println(evilPerson.getName() + " shot at you!");
System.out.println("He missed. Fire back!");
}
}
else {
evilWeapon.loadWeapon(evilWeapon.getMagazineSize());
System.out.println(evilPerson.getName() + " has to reload!");
System.out.println("Take this chance and finish him!");
}
return false;
}
/**
* Actions when friendly person is in the new Room
*
*/
private boolean friendlyPersonAction(GameCharacter friend, Player player){
System.out.println(friend.getName() + " is in the Room.");
if (fleeFromRoom(friend)){
return true;
}
else
System.out.println(friend.getName() + " says: 'Hi'");
return false;
}
private static boolean fleeFromRoom(GameCharacter characterToMove)
{
Random rand = new Random();
if(rand.nextFloat() > characterToMove.getChanceOfFleeing()){
//Character does not flee.
return false;
}
Room currentRoom = (Room)characterToMove.getCurrentOwner();
currentRoom.removeItem(characterToMove);
String direction = currentRoom.getRandomExitDirection();
Room nextRoom = currentRoom.getExit(direction);
characterToMove.setCurrentOwner(nextRoom);
nextRoom.addItem(characterToMove);
System.out.println(characterToMove.getName() + " fled from the Room");
System.out.println("Go '" + direction + "' to follow " + characterToMove.getName() + ".");
return true;
}
}
Daneben gibts noch die Command und Game Klasse, die ebenfalls direkt Text ausgeben. Momentan ist dies kein Problem, aber sobald man zb, ein GUI machen möchte, sieht es düster aus. Wie man sieht ist momentan die Waffe selbst für abfeuern zuständig, aber mehr als die Munition um 1 zu veringern tut die Methode selbst nicht.
Die Frage ist auch, wo diese "Kampf-Logik" hin gehört. In eine eigene Klasse?
Oder in die GameFigure klasse mit methode:
fireWeapon(GameFigure target);
Fragen über fragen...