Hytale Modding
Java Grundlagen

07 - Einführung in die objektorientierte Programmierung

Lerne die Grundlagen von Klassen und Objekten in Java.

Objektorientiertes Programmieren (OOP) ist die Grundlage von Java und Hytale Modding. Anstatt Variablen und Methoden einfach nur herumfliegen zu lassen, organisieren wir sie in Klassen und Objekten.

Was ist eine Klasse?

Eine Klasse ist ein Bauplan zum Erstellen von Objekten. Stell es dir wie ein Rezept oder eine Vorlage vor.

public class Player {
    // Eigenschaften (Daten)
    String name;
    int health;
    int level;
    
    // Verhalten (Methoden)
    public void takeDamage(int damage) {
        health -= damage;
        System.out.println(name + " hat " + damage + " Schaden genommen!");
    }
}

Was ist ein Objekt?

Ein Objekt ist eine Instanz, die von einer Klasse erstellt wird. Wenn eine Klasse ein Bauplan ist, dann ist ein Objekt die eigentliche Sache, die aus diesem Bauplan gebaut wurde.

public class Main {
    public static void main(String[] args) {
        // Objekte der Player Klasse erstellen
        Player player1 = new Player();
        player1.name = "Alice";
        player1.health = 100;
        player1.level = 5;
        
        Player player2 = new Player();
        player2.name = "Bob";
        player2.health = 80;
        player2.level = 3;
        
        // Verwende die Objekte
        player1.takeDamage(20);  // Alice hat 20 Schaden genommen!
        player2.takeDamage(15);  // Bob hat 15 Schaden genommen!
    }
}
Klasse vs Objekt

Klasse = Bauplan (die Idee eines Spielers) Objekt = Tatsächliche Sache (Alice, Bob, bestimmte Spieler)

Eine Klasse kann viele Objekte erstellen, genau wie man mit einem Rezept mehrere Kuchen backen kann!

Eine einfache Klasse erstellen

Lass uns eine Sword-Klasse für Hytale erstellen:

public class Sword {
    // Eigenschaften
    String name;
    int damage;
    int durability;
    
    // Methode um das Schwert zu benutzen
    public void attack(String target) {
        System.out.println(target + " angegriffen für " + damage + " Schaden!");
        durability -= 1;
        
        if (durability <= 0) {
            System.out.println(name + " ist kaputt gegangen!");
        }
    }
    
    // Methode um Informationen anzuzeigen
    public void displayInfo() {
        System.out.println("Waffe: " + name);
        System.out.println("Schaden: " + damage);
        System.out.println("Haltbarkeit: " + durability);
    }
}

Die Klasse verwenden:

public class Main {
    public static void main(String[] args) {
        Sword sword = new Sword();
        sword.name = "Eisenschwert";
        sword.damage = 15;
        sword.durability = 3;
        
        sword.displayInfo();
        sword.attack("Zombie");
        sword.attack("Skelett");
        sword.attack("Spinne");  // Macht das Schwert kaputt
    }
}

Konstruktoren

Statt Eigenschaften einzeln zu setzen, verwende einen Konstruktor, um Objekte zu initialisieren:

public class Sword {
    String name;
    int damage;
    int durability;
    
    // Konstruktor
    public Sword(String weaponName, int weaponDamage, int weaponDurability) {
        name = weaponName;
        damage = weaponDamage;
        durability = weaponDurability;
    }
    
    public void attack(String target) {
        System.out.println(target + " angegriffen für " + damage + " Schaden!");
        durability--;
    }
}

Jetzt ist es einfacher, Schwerter zu erstellen:

public class Main {
    public static void main(String[] args) {
        // Viel ordentlicher!
        Sword ironSword = new Sword("Eisenschwert", 15, 100);
        Sword diamondSword = new Sword("Diamantschwert", 25, 200);
        
        ironSword.attack("Zombie");
        diamondSword.attack("Boss");
    }
}
Konstruktor-Regeln
  • Selber Name wie die Klasse
  • Kein Rückgabetyp (nicht einmal void)
  • Wird automatisch aufgerufen, wenn du new verwendest
  • Kann mehrere Konstruktoren haben (Overloading)
public class Item {
    String name;
    int value;
    
    // Konstruktor mit allen Parametern
    public Item(String name, int value) {
        this.name = name;
        this.value = value;
    }
    
    // Konstruktor nur mit Name
    public Item(String name) {
        this.name = name;
        this.value = 0;  // Standardwert
    }
}

Das Schlüsselwort this

this bezieht sich auf das aktuelle Objekt. Verwende es zum klarzustellen, wenn Parametername und Eigenschaftsname übereinstimmen:

public class Player {
    String name;
    int health;
    
    public Player(String name, int health) {
        this.name = name;      // this.name = Eigenschaft
        this.health = health;  // name = Parameter
    }
}

Ohne this kommt Java durcheinander:

public Player(String name, int health) {
    name = name;      //Welches name? Mehrdeutig!
    health = health;  //Welches health? Mehrdeutig!
}

Praktische Beispiele

Item Klasse

public class Item {
    String name;
    String type;
    int quantity;
    double weight;
    
    public Item(String name, String type, int quantity, double weight) {
        this.name = name;
        this.type = type;
        this.quantity = quantity;
        this.weight = weight;
    }
    
    public void use() {
        if (quantity > 0) {
            quantity--;
            System.out.println(name + "verwendet. Noch übrig: " + quantity);
        } else {
            System.out.println("Kein " + name + " mehr übrig!");
        }
    }
    
    public double getTotalWeight() {
        return weight * quantity;
    }
}
public class Main {
    public static void main(String[] args) {
        Item potion = new Item("Heiltrank", "Konsumierbares", 5, 0.5);
        
        potion.use();  // Heiltrank verwendet. Noch übrig: 4
        System.out.println("Gesamtgewicht: " + potion.getTotalWeight()); // 2.0
    }
}

Monster Klasse

public class Monster {
    String name;
    int health;
    int attack;
    boolean isHostile;
    
    public Monster(String name, int health, int attack, boolean isHostile) {
        this.name = name;
        this.health = health;
        this.attack = attack;
        this.isHostile = isHostile;
    }
    
    public void takeDamage(int damage) {
        health -= damage;
        System.out.println(name + " hat " + damage + " Schaden genommen!");
        
        if (health <= 0) {
            System.out.println(name + " wurde besiegt!");
        } else {
            System.out.println(name + " hat " + health + " Leben übrig.");
        }
    }
    
    public int attackPlayer() {
        if (isHostile && health > 0) {
            System.out.println(name + " greift für " + attack + " Schaden an!");
            return attack;
        }
        return 0;
    }
    
    public boolean isAlive() {
        return health > 0;
    }
}
public class Main {
    public static void main(String[] args) {
        Monster zombie = new Monster("Zombie", 50, 10, true);
        Monster chicken = new Monster("Huhn", 10, 0, false);
        
        zombie.takeDamage(20);               // Zombie hat 20 Schaden genommen!
        int damage = zombie.attackPlayer();  // Zombie greift für 20 Schaden an!
        
        if (zombie.isAlive()) {
            System.out.println("Monster lebt noch!");
        }
    }
}

Block Klasse

public class Block {
    String type;
    int x, y, z;
    boolean isSolid;
    int hardness;
    
    public Block(String type, int x, int y, int z, boolean isSolid, int hardness) {
        this.type = type;
        this.x = x;
        this.y = y;
        this.z = z;
        this.isSolid = isSolid;
        this.hardness = hardness;
    }
    
    public void breakBlock() {
        System.out.println("Macht " + type + " bei (" + x + ", " + y + ", " + z + ") kaputt");
        System.out.println("Härte: " + hardness);
    }
    
    public String getPosition() {
        return "(" + x + ", " + y + ", " + z + ")";
    }
    
    public boolean canWalkThrough() {
        return !isSolid;
    }
}

Zugriffsmodifikatoren (Vorschau)

Du kennst schon public - es bedeutet "jeder kann darauf zugreifen". Du wirst später mehr über Zugriffsmodifikatoren (Zugriffskontrolle) erfahren, aber hier ist eine Vorschau:

public class Beispiel {
    public String publicVar;      // Jeder kann drauf zugreifen
    private String privateVar;    // Nur diese Klasse kann zugreifen
    /* (kein Modifikator) */ String defaultVar; // Package-Zugriff
}

Verwende im Moment public für alles. Du wirst in der nächsten Lektion lernen, wie man private verwendet.

Warum Klassen verwenden?

Klassen helfen dir:

  • Methoden und zusammengehörende Daten zu organisieren
  • Code einfach wiederverwenden (Erstellen vieler Objekte von einer Klasse)
  • Dinge aus der echten Welt abbilden (Spieler, Items, Monster)
  • Code warten (Änderungen an einem Ort beeinflussen alle Objekte)

Ohne Klassen würde das Management von 100 Spielern für jede Eigenschaft 100 separate Variablen erfordern. Mit Klassen sind es nur 100 Spielerobjekte!

Übungsaufgaben

  1. Erstelle eine Potion Klasse:

    • Eigenschaften: name, healAmount, uses
    • Konstruktor um alle Eigenschaften zu setzen
    • Methode drink() die heilt und uses reduziert
    • Methode isEmpty() die true zurückgibt, wenn uses weniger als oder gleich 0 ist
  2. Erstelle eine Chest Klasse:

    • Eigenschaften: isLocked, itemCount, capacity
    • Konstruktor
    • Methode addItem(), die capacity überprüft
    • Methode unlock(), die isLocked auf false setzt
    • Methode isFull(), die überprüft ob itemCount >= capacity
  3. Erstelle eine Villager Klasse:

    • Eigenschaften: name, profession, tradeCount
    • Konstruktor
    • Methode greet(), die einen Gruß ausgibt
    • Methode trade(), die tradeCount erhöht
    • Methode getInfo(), die alle Eigenschaften anzeigt
  4. Erstelle mehrere Objekte: Erstelle mithilfe einer beliebigen Klasse, die du erstellt hast, 3 verschiedene Objekte und teste alle ihre Methoden.