Spielcharakter-Entwicklung
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 86 von 87.
In dieser Herausforderung erstellen Sie ein Spielcharakter-Entwicklung-System, das die Leistungsfähigkeit von OOP bei der Modellierung komplexer, interaktiver Einheiten demonstriert.
Entwerfen Sie eine Charakter-Hierarchie, in der eine Basis-Character-Klasse gemeinsame Attribute wie Gesundheit, Name und Level definiert. Spezialisierte Klassen wie Warrior, Mage und Archer erweitern diese Basis um einzigartige Fähigkeiten und Kampfstile.
Interfaces funktionieren hier ganz natürlich: Attackable könnte Kampfmethoden definieren, während Healable Heilungsfähigkeiten übernimmt. Ein Mage könnte beides implementieren, während sich ein Warrior nur auf das Angreifen konzentriert.
Ziehen Sie die Verwendung des Strategy-Patterns für verschiedene Angriffsverhalten in Betracht, was es Charakteren ermöglicht, Kampfstile dynamisch zu wechseln. Das State-Pattern könnte Charakterzustände wie normale, vergiftete oder betäubte Zustände verwalten, die das Verhalten beeinflussen.
Denken Sie über Komposition für Ausrüstungssysteme nach, bei denen Charaktere Waffen und Rüstungen „besitzen“, anstatt von ihnen zu erben. Verwenden Sie Enums für Charakterklassen oder Schadensarten und wenden Sie Kapselung an, um Statuswerte vor ungültigen Änderungen zu schützen.
Aufgabe
EinfachLassen Sie uns ein Spielcharakter-Entwicklungssystem bauen, das die Stärke von OOP bei der Modellierung komplexer, interaktiver Spielentitäten demonstriert! Sie werden eine Charakterhierarchie mit verschiedenen Kampfstilen, Spezialfähigkeiten und einem Statussystem erstellen, das das Verhalten der Charaktere beeinflusst.
Sie werden Ihren Code über sieben Dateien organisieren:
DamageType.java: Erstellen Sie ein Enum, das verschiedene Schadensarten im Spiel darstellt. Fügen Sie die WertePHYSICAL,MAGICALundRANGEDhinzu. Fügen Sie ein privates Felddescription(String), einen Konstruktor, der dieses setzt, und einen Getter hinzu. Physischer Schaden sollte die Beschreibung "brute force" haben, magischer sollte "arcane energy" haben und Fernkampf sollte "precision strike" haben.Attackable.java: Erstellen Sie ein Interface, das die Kampffähigkeiten definiert. Deklarieren Sie die Methodenattack(Character target), die einen String zurückgibt, der den Angriff beschreibt, undgetDamageType(), die einen DamageType zurückgibt.Healable.java: Erstellen Sie ein Interface für Heilungsfähigkeiten. Deklarieren Sie eine Methodeheal(int amount), die einen String zurückgibt, der die Heilungsaktion beschreibt.Character.java: Erstellen Sie eine abstrakte Basisklasse für alle Spielcharaktere. Fügen Sie private Felder fürname(String),health(int),maxHealth(int) undlevel(int) hinzu. Der Konstruktor nimmt name, maxHealth und level entgegen und setzt health initial gleich maxHealth. Fügen Sie Getter für alle Felder hinzu. Fügen Sie eine geschützte MethodesetHealth(int health)hinzu, die sicherstellt, dass health zwischen 0 und maxHealth bleibt. Erstellen Sie eine MethodetakeDamage(int damage), die die Gesundheit reduziert und"[name] takes [damage] damage! Health: [health]/[maxHealth]"zurückgibt. Fügen Sie eine MethodeisAlive()hinzu, die true zurückgibt, wenn health größer als 0 ist. Deklarieren Sie eine abstrakte MethodegetCharacterClass(), die einen String zurückgibt.Warrior.java: Erstellen Sie eine Klasse, die Character erweitert und Attackable implementiert. Fügen Sie ein privates Feldstrength(int) hinzu. Der Konstruktor nimmt name, maxHealth, level und strength entgegen. Implementieren SiegetCharacterClass(), um"Warrior"zurückzugeben. Implementieren SiegetDamageType(), umPHYSICALzurückzugeben. Implementieren Sieattack(Character target), um Schaden in Höhe von strength plus level zu verursachen, rufen Sie die takeDamage-Methode des Ziels auf und geben Sie"[name] strikes with [damageType description] for [damage] damage!"gefolgt von einem Zeilenumbruch und dem takeDamage-Ergebnis zurück.Mage.java: Erstellen Sie eine Klasse, die Character erweitert und sowohl Attackable als auch Healable implementiert. Fügen Sie private Felderintelligence(int) undmana(int) hinzu. Der Konstruktor nimmt name, maxHealth, level, intelligence und mana entgegen. Implementieren SiegetCharacterClass(), um"Mage"zurückzugeben. Implementieren SiegetDamageType(), umMAGICALzurückzugeben. Implementieren Sieattack(Character target), um Schaden in Höhe von intelligence mal 2 zu verursachen, wobei das gleiche Format wie beim Warrior verwendet wird. Implementieren Sieheal(int amount), um die Gesundheit wiederherzustellen (unter Verwendung von setHealth) und"[name] channels healing magic! Health: [health]/[maxHealth]"zurückzugeben.Main.java: Erwecken Sie Ihr Spielsystem zum Leben! Sie erhalten einen kommagetrennten String mit Befehlen:CREATE_WARRIOR:name:maxHealth:level:strengthCREATE_MAGE:name:maxHealth:level:intelligence:manaATTACK:attackerName:targetNameHEAL:mageName:amountSTATUS:characterName
Verwalten Sie eine Sammlung von Charakteren. Verarbeiten Sie jeden Befehl und geben Sie Folgendes aus:
- CREATE_WARRIOR/CREATE_MAGE:
[name] the [characterClass] joins the battle! - ATTACK: Geben Sie das Angriffsergebnis aus (den vom attack-Methode zurückgegebenen String)
- HEAL: Geben Sie das Heilungsergebnis aus, oder
[name] cannot heal, wenn der Charakter kein Mage ist - STATUS:
[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]
Geben Sie nach allen Befehlen
"--- Battle Summary ---"aus, gefolgt vom Status jedes Charakters.
Sie erhalten eine Eingabe: den kommagetrennten Befehls-String.
Zum Beispiel, bei der Eingabe CREATE_WARRIOR:Thorin:100:5:15,CREATE_MAGE:Gandalf:80:7:12:50,ATTACK:Thorin:Gandalf,HEAL:Gandalf:25,STATUS:Gandalf, wäre Ihre Ausgabe:
Thorin the Warrior joins the battle!
Gandalf the Mage joins the battle!
Thorin strikes with brute force for 20 damage!
Gandalf takes 20 damage! Health: 60/80
Gandalf channels healing magic! Health: 80/80
Gandalf (Mage) - Level 7 - Health: 80/80 - Alive
--- Battle Summary ---
Thorin (Warrior) - Level 5 - Health: 100/100 - Alive
Gandalf (Mage) - Level 7 - Health: 80/80 - AliveDiese Herausforderung kombiniert Vererbung (Character-Hierarchie), die Implementierung mehrerer Interfaces (Mage implementiert sowohl Attackable als auch Healable), Enums mit Methoden (DamageType), Polymorphismus (die einheitliche Behandlung verschiedener Charaktertypen) und Kapselung (geschützte Gesundheitsverwaltung) in einem fesselnden Spielsystem!
Spickzettel
Objektorientierte Programmierung (OOP) ermöglicht die Modellierung komplexer Systeme durch Klassen, Vererbung, Schnittstellen und Entwurfsmuster.
Klassenhierarchie
Erstellen Sie eine Basisklasse mit gemeinsamen Attributen und erweitern Sie diese durch spezialisierte Klassen:
public abstract class Character {
private String name;
private int health;
private int maxHealth;
private int level;
public Character(String name, int maxHealth, int level) {
this.name = name;
this.maxHealth = maxHealth;
this.health = maxHealth;
this.level = level;
}
protected void setHealth(int health) {
this.health = Math.max(0, Math.min(health, maxHealth));
}
public abstract String getCharacterClass();
}Schnittstellen (Interfaces)
Definieren Sie Verträge für spezifische Verhaltensweisen, die Klassen implementieren können:
public interface Attackable {
String attack(Character target);
DamageType getDamageType();
}
public interface Healable {
String heal(int amount);
}Enums mit Feldern
Enums können Felder, Konstruktoren und Methoden haben:
public enum DamageType {
PHYSICAL("brute force"),
MAGICAL("arcane energy"),
RANGED("precision strike");
private String description;
private DamageType(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}Implementierung mehrerer Schnittstellen
Eine Klasse kann mehrere Schnittstellen implementieren:
public class Mage extends Character implements Attackable, Healable {
private int intelligence;
private int mana;
@Override
public String attack(Character target) {
// Implementation
}
@Override
public String heal(int amount) {
// Implementation
}
}Kapselung (Encapsulation)
Verwenden Sie private Felder mit geschützten Settern, um den Zugriff zu steuern und Daten zu validieren:
protected void setHealth(int health) {
this.health = Math.max(0, Math.min(health, maxHealth));
}Polymorphismus
Behandeln Sie verschiedene Charaktertypen einheitlich über ihre gemeinsame Basisklasse oder Schnittstellen, was flexible Sammlungen und Methodenaufrufe ermöglicht.
Probier es selbst
import java.util.Scanner;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Verwende eine Collection, um die Charaktere zu verwalten (LinkedHashMap bewahrt die Einfügereihenfolge)
// LinkedHashMap<String, Character> characters = new LinkedHashMap<>();
// TODO: Teile die Eingabe durch Kommas, um einzelne Befehle zu erhalten
// String[] commands = input.split(",");
// TODO: Verarbeite jeden Befehl:
// - CREATE_WARRIOR:name:maxHealth:level:strength
// Ausgabe: "[name] the Warrior joins the battle!"
//
// - CREATE_MAGE:name:maxHealth:level:intelligence:mana
// Ausgabe: "[name] the Mage joins the battle!"
//
// - ATTACK:attackerName:targetName
// Gib das Angriffsergebnis der attack-Methode aus
//
// - HEAL:mageName:amount
// Gib das Heilungsergebnis aus, oder "[name] cannot heal", falls es kein Mage ist
//
// - STATUS:characterName
// Ausgabe: "[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]"
// TODO: Gib nach allen Befehlen "--- Battle Summary ---" aus
// Gib anschließend den Status jedes Charakters aus
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem