Hytale Modding
Conceptos básicos de Java

07 - Introducción a la programación orientada a objetos

Aprende los fundamentos de las clases y objetos en Java.

La programación orientada a objetos (OOP por sus iniciales en inglés) es la base fundamental de Java y del modding para Hytale. En vez de solo usar variables y métodos flotando por todos lados, los organizamos en clases y objetos

¿Qué es una clase?

Una clase es una plantilla para crear objetos. Piensa como si fuera una receta o una guía

public class Player {
    // Propiedades (datos)
    String name;
    int health;
    int level;
    
    // Comportamiento (métodos)
    public void takeDamage (int damage) {
        health -= damage;
        System.out.println(name + " recibió" + damage + " de daño!");
    }
}

¿Qué es un objeto?

Un objeto es una instancia creada desde una clase Si una clase es una plantilla, un objeto es lo que se hace a partir de dicha plantilla. Si una clase es una plantilla, un objeto es lo que se hace a partir de dicha plantilla.

public class Main {
    public static void main(String[] args) {
        // Crea objetos en base a la clase Player
        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;
        
        // Usa los objetos
        player1.takeDamage(20);  // Alice recibió 20 de daño!
        player2.takeDamage(15);  // Bob recibió 15 de daño! 
    }
}
Clases vs Objetos

Clase = Plantilla (La idea de un jugador) Objeto = Lo que si usaremos (Alice, Bob, jugadores específicos)

¡Una clase puede crear muchos objetos, igual que una receta puede hacer muchas galletas!

Creando una clase simple

Creemos una clase para "Espada" en Hytale:

public class Espada {
    // Propiedades
    String name;
    int damage;
    int durability;
    
    // Método para usar la espada
    public void attack(String target) {
        System.out.println("¡Impacta a " + target + " por " + damage + " de daño!");
        durability -= 1;
        
        if (durability <= 0) {
            System.out.println(name + " se gastó");
        }
    }
    
    // Método para mostrar información
    public void displayInfo() {
        System.out.println("Arma: " + name);
        System.out.println("Daño: " + damage);
        System.out.println("Durabilidad: " + durability);
    }
}

Usando la clase:

public class Main {
    public static void main(String[] args) {
        Sword sword = new Sword();
        sword.name = "Espada de hierro";
        sword.damage = 15;
        sword.durability = 3;
        
        sword.displayInfo();
        sword.attack("Zombie");
        sword.attack("Esqueleto");
        sword.attack("Araña");  // Esto romperá la espada con su uso
    }
}

Constructores

En vez de establecer propiedades una por una, use un constructor para inicializar objetos:

public class Sword {
    String name;
    int damage;
    int durability;
    
    // Constructor
    public Sword(String weaponName, int weaponDamage, int weaponDurability) {
        name = weaponName;
        damage = weaponDamage;
        durability = weaponDurability;
    }
    
    public void attack(String target) {
        System.out.println("¡Impaca a " + target + " por " + damage + " de daño!");
        durability--;
    }
}

Ahora la creación de espadas es más fácil:

public class Main {
    public static void main(String[] args) {
        // Más limpio!
        Sword ironSword = new Sword("Espada de Hierro", 15, 100);
        Sword diamondSword = new Sword("Espada de Diamante", 25, 200);
        
        ironSword.attack("Zombi");
        diamondSword.attack("Jefe");
    }
}
Reglas del Constructor
  • Mismo nombre que la clase
  • Sin tipo de retorno (ni siquiera void)
  • Es llamado automáticamente cuando utilizas new
  • Puede haber varios constructores (overloading)
public class Item {
    String name;
    int value;
    
    // Constructor con todos los parámetros
    public Item(String name, int value) {
        this.name = name;
        this.value = value;
    }
    
    // Constructor solo con el nombre
    public Item(String name) {
        this.name = name;
        this.value = 0;  // Valor por defecto
    }
}

La palabra clave this

this se refiere al objeto actual. Úsalo para aclarar cuándo los nombres de los parámetros coinciden con los nombres de propiedades:

public class Player {
    String name;
    int health;
    
    public Player(String name, int health) {
        this.name = name;      // this.name = la propiedad
        this.health = health;  // name = el parámetro
    }
}

Sin this, Java se confunde.

public Player(String name, int health) {
    name = name;      // ❌ ¿Cuál nombre? Ambiguo!
    health = health;  // ❌ ¿Cuál vida? Ambiguo!
}

Ejemplos prácticos

Clase Item

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("Se utilizó " + name + ". Restantes: " + quantity);
        } else {
            System.out.println("Ya no queda más " + name + " !");
        }
    }
    
    public double getTotalWeight() {
        return weight * quantity;
    }
}
public class Main {
    public static void main(String[] args) {
        Item potion = new Item("Poción de Curación", "Consumible", 5, 0.5);
        
        potion.use();  // Se utilizó Poción de Curación. Restantes: 4
        System.out.println("Peso total: " + potion.getTotalWeight()); // 2.0
    }
}

Clase Monstruo

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 + " recibió " + damage + " de daño!");
        
        if (health <= 0) {
            System.out.println(name + " fue derrotado!");
        } else {
            System.out.println(name + " tiene " + health + " de vida restante.");
        }
    }
    
    public int attackPlayer() {
        if (isHostile && health > 0) {
            System.out.println(name + " ataca y causa " + attack + " de daño!");
            return attack;
        }
        return 0;
    }
    
    public boolean isAlive() {
        return health > 0;
    }
}
public class Main {
    public static void main(String[] args) {
        Monster zombie = new Monster("Zombi", 50, 10, true);
        Monster chicken = new Monster("Pollo", 10, 0, false);
        
        zombie.takeDamage(20);        // Zombi recibió 20 de daño!
        int damage = zombie.attackPlayer();  // Zombi ataca y causa 10 de daño!
        
        if (zombie.isAlive()) {
            System.out.println("El monstruo sigue vivo!");
        }
    }
}

Clase Bloque

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("Rompiendo " + type + " bloque en (" + x + ", " + y + ", " + z + ")");
        System.out.println("Dureza: " + hardness);
    }
    
    public String getPosition() {
        return "(" + x + ", " + y + ", " + z + ")";
    }
    
    public boolean canWalkThrough() {
        return !isSolid;
    }
}

Modificadores de Acceso (Ejemplo)

Has visto public - significa "cualquiera puede acceder a esto". Vamos a aprender más sobre control de acceso más tarde, pero aquí hay un ejemplo:

public class Example {
    public String publicVar;      // Anyone can access
    private String privateVar;    // Only this class can access
    // (no modifier) String defaultVar; // Package access
}

Por ahora, utilizaremos public para todo. Aprenderemos a utilizar private en el próximo artículo.

¿Por qué usar clases?

Las clases te ayudan a:

  • Organizar datos y métodos relacionados entre sí
  • Reutilizar código fácilmente (crear muchos objetos a partir de una sola clase)
  • Modelar cosas del mundo real (jugadores, items, monstruos)
  • Mantener el código (cambios en un solo lugar afectan a todos los objetos)

Sin clases, administrar 100 jugadores requeriría 100 variables separadas para cada propiedad. ¡Con clases, son solo 100 objetos Player!

Ejercicios de Práctica

  1. Crea una clase Potion:

    • Propiedades: name, healAmount, uses
    • Constructos para definir todas las propiedades
    • Método drink() que cura y disminuye usos.
    • Método isEmpty() que retorne true si los usos son menores o iguales a 0
  2. Crea una clase Chest:

    • Propiedades: isLocked, itemCount, capacity
    • Constructor
    • Método addItem() que compruebe la capacidad
    • Método unlock() que establezca isLocked a false
    • Método isFull() que compruebe si itemCount >= capacity
  3. Crea una clase Villager:

    • Propiedades: name, profession, tradeCount
    • Constructor
    • Método greet() que imprima un saludo
    • Método trade() que aumente tradeCount
    • Método getInfo() que muestre todas las propiedades
  4. Crea Múltiples Objetos: Usando cualquier clase que hayas hecho, crea 3 objetos diferentes y prueba todos sus métodos.