Hytale Modding
Основи Java

07 - Вступ до об'єктно-орієнтованого програмування

Вивчіть основи класів та об'єктів у Java.

Об'єктно-орієнтоване програмування (ООП) є основою Java та модифікацій Hytale. Замість того, щоб просто мати змінні та методи, ми організовуємо їх у класи та об'єкти.

Що таке клас?

Клас - це план для створення об'єктів. Уявіть його як рецепт або шаблон.

public class Player {
    // Властивості (дані)
    String name;
    int health;
    int level;
    
    // Поведінка (методи)
    public void takeDamage(int damage) {
        health -= damage;
        System.out.println(name + " отримав(-ла) " + damage + " шкоди!");
    }
}

Що таке об'єкт?

Об'єкт - це екземпляр, створений на основі класу. Якщо клас - це креслення, то об'єкт - це реальна річ, побудована за цим кресленням.

public class Main {
    public static void main(String[] args) {
        // Створити об'єкти з класу Player
        Player player1 = new Player();
        player1.name = "Анна";
        player1.health = 100;
        player1.level = 5;
        
        Player player2 = new Player();
        player2.name = "Богдан";
        player2.health = 80;
        player2.level = 3;
        
        // Використання об'єктів
        player1.takeDamage(20);  // Анна отримав(-ла) 20 шкоди!
        player2.takeDamage(15);  // Богдан отримав(-ла) 15 шкоди!
    }
}
Клас проти об'єкта

Клас = креслення (ідея гравця) Об'єкт = реальна річ (Анна, Богдан, конкретні гравці)

Один клас може створити багато об'єктів, так само як один рецепт може створити багато тортів!

Створення простого класу

Створімо клас Sword для Hytale:

public class Sword {
    // Властивості
    String name;
    int damage;
    int durability;
    
    // Метод використання меча
    public void attack(String target) {
        System.out.println("Атакує " + target + " на " + damage + " шкоди!");
        durability -= 1;
        
        if (durability <= 0) {
            System.out.println(name + " зламався!");
        }
    }
    
    // Метод для відображення інформації
    public void displayInfo() {
        System.out.println("Зброя: " + name);
        System.out.println("Шкода: " + damage);
        System.out.println("Міцність: " + durability);
    }
}

Використання класу:

public class Main {
    public static void main(String[] args) {
        Sword sword = new Sword();
        sword.name = "Залізний меч";
        sword.damage = 15;
        sword.durability = 3;
        
        sword.displayInfo();
        sword.attack("Зомбі");
        sword.attack("Скелет");
        sword.attack("Павук");  // Це зламає меч
    }
}

Конструктори

Замість того, щоб встановлювати властивості по одній, використовуйте конструктор для ініціалізації об'єктів:

public class Sword {
    String name;
    int damage;
    int durability;
    
    // Конструктор
    public Sword(String weaponName, int weaponDamage, int weaponDurability) {
        name = weaponName;
        damage = weaponDamage;
        durability = weaponDurability;
    }
    
    public void attack(String target) {
        System.out.println("Атакує " + target + " на " + damage + " шкоди!");
        durability--;
    }
}

Тепер створювати мечі стало простіше:

public class Main {
    public static void main(String[] args) {
        // Набагато простіше!
        Sword ironSword = new Sword("Залізний меч", 15, 100);
        Sword diamondSword = new Sword("Діамантовий меч", 25, 200);
        
        ironSword.attack("Зомбі");
        diamondSword.attack("Бос");
    }
}
Правила конструктора
  • Така сама назва, як і клас
  • Без типу повернення (навіть void)
  • Викликається автоматично при використанні new
  • Може мати кілька конструкторів (перевантаження)
public class Item {
    String name;
    int value;
    
    // Конструктор з усіма параметрами
    public Item(String name, int value) {
        this.name = name;
        this.value = value;
    }
    
    // Конструктор тільки з ім'ям
    public Item(String name) {
        this.name = name;
        this.value = 0;  // Значення за замовчуванням
    }
}

Ключове слово this

this посилається на поточний об'єкт. Використовуйте його для уточнення, коли імена параметрів збігаються з іменами властивостей:

public class Player {
    String name;
    int health;
    
    public Player(String name, int health) {
        this.name = name;      // this.name = властивість
        this.health = health;  // name = параметр
    }
}

Без this Java заплутується:

public Player(String name, int health) {
    name = name;      // ❌ Чиє ім'я? Неоднозначно!
    health = health;  // ❌ Чиє здоров'я? Неоднозначно!
}

Практичні приклади

Клас предмету

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 + ". Залишилося: " + quantity);
        } else {
            System.out.println("Більше " + name + " не лишилось!");
        }
    }
    
    public double getTotalWeight() {
        return weight * quantity;
    }
}
public class Main {
    public static void main(String[] args) {
        Item potion = new Item("Зілля здоров'я", "Витратний", 5, 0.5);
        
        potion.use();  // Використано Зілля здоров'я. Залишилося: 4
        System.out.println("Загальна вага: " + potion.getTotalWeight()); // 2.0
    }
}

Клас монстра

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 + " отримав(-ла) " + damage + " шкоди!");
        
        if (health <= 0) {
            System.out.println(name + " був переможений!");
        } else {
            System.out.println(name + " має ще " + health + " здоров'я.");
        }
    }
    
    public int attackPlayer() {
        if (isHostile && health > 0) {
            System.out.println(name + " атакує на " + attack + " шкоди!");
            return attack;
        }
        return 0;
    }
    
    public boolean isAlive() {
        return health > 0;
    }
}
public class Main {
    public static void main(String[] args) {
        Monster zombie = new Monster("Зомбі", 50, 10, true);
        Monster chicken = new Monster("Курка", 10, 0, false);
        
        zombie.takeDamage(20);        // Зомбі отримав(-ла) 20 шкоди!
        int damage = zombie.attackPlayer();  // Зомбі атакує на 10 шкоди!
        
        if (zombie.isAlive()) {
            System.out.println("Монстр досі живий!");
        }
    }
}

Клас блоку

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("Ламає " + type + " блок в (" + x + ", " + y + ", " + z + ")");
        System.out.println("Твердість: " + hardness);
    }
    
    public String getPosition() {
        return "(" + x + ", " + y + ", " + z + ")";
    }
    
    public boolean canWalkThrough() {
        return !isSolid;
    }
}

Модифікатори доступу (попередній перегляд)

Ви вже бачили public - це означає "доступний для всіх". Пізніше ми дізнаємося більше про контроль доступу, а поки що ось попередній перегляд:

public class Example {
    public String publicVar;      // Доступний для всіх
    private String privateVar;    // Доступний тільки для цього класу
    /* (без модифікатора) */ String defaultVar; // Доступ до пакета
}

Наразі використовуйте public для всього. Коли використовувати private, ми дізнаємося в наступній статті.

Навіщо використовувати класи?

Класи допомагають:

  • Організувати пов'язані дані та методи разом
  • Легко повторно використовувати код (створювати багато об'єктів з одного класу)
  • Моделювати реальні речі (гравців, предмети, монстрів)
  • Підтримувати код (зміни в одному місці впливають на всі об'єкти)

Без класів для управління 100 гравцями знадобилося б 100 окремих змінних для кожної властивості. З класами це лише 100 об'єктів гравця!

Практичні вправи

  1. Створіть клас Potion:

    • Властивості: name, healAmount, uses
    • Конструктор для встановлення всіх властивостей
    • Метод drink(), який лікує і зменшує використання (uses)
    • Метод isEmpty(), який повертає true, якщо використання (uses) менше або дорівнює 0
  2. Створіть клас Chest:

    • Властивості: isLocked, itemCount, capacity
    • Конструктор
    • Метод addItem(), який перевіряє capacity
    • Метод unlock(), який встановлює isLocked на false
    • Метод isFull(), який перевіряє, чи itemCount >= capacity
  3. Створіть клас Villager:

    • Властивості: name, profession, tradeCount
    • Конструктор
    • Метод greet(), який виводить привітання
    • Метод trade(), який збільшує tradeCount
    • Метод getInfo(), який відображає всі властивості
  4. Створіть кілька об'єктів: Використовуючи будь-який створений вами клас, створіть 3 різних об'єкти та протестуйте всі їхні методи.