Menu
Coddy logo textTech

Game Character Development

Part of the Object Oriented Programming section of Coddy's Java journey — lesson 86 of 87.

This challenge has you building a Game Character Development system that showcases OOP's power in modeling complex, interactive entities.

Design a character hierarchy where a base Character class defines common attributes like health, name, and level. Specialized classes such as Warrior, Mage, and Archer extend this base with unique abilities and combat styles.

Interfaces work naturally here: Attackable could define combat methods, while Healable handles restoration abilities. A Mage might implement both, whereas a Warrior focuses only on attacking.

Consider using the Strategy pattern for different attack behaviors, allowing characters to switch combat styles dynamically. The State pattern could manage character conditions like normal, poisoned, or stunned states that affect behavior.

Think about composition for equipment systems where characters "have" weapons and armor rather than inheriting from them. Use enums for character classes or damage types, and apply encapsulation to protect stats from invalid modifications.

challenge icon

Challenge

Easy

Let's build a Game Character Development system that showcases the power of OOP in modeling complex, interactive game entities! You'll create a character hierarchy with different combat styles, special abilities, and a state system that affects how characters behave.

You'll organize your code across seven files:

  • DamageType.java: Create an enum representing different types of damage in the game. Include values PHYSICAL, MAGICAL, and RANGED. Add a private field description (String), a constructor that sets it, and a getter. Physical damage should have description "brute force", magical should have "arcane energy", and ranged should have "precision strike".
  • Attackable.java: Create an interface defining combat capabilities. Declare methods attack(Character target) that returns a String describing the attack, and getDamageType() that returns a DamageType.
  • Healable.java: Create an interface for restoration abilities. Declare a method heal(int amount) that returns a String describing the healing action.
  • Character.java: Create an abstract base class for all game characters. Include private fields for name (String), health (int), maxHealth (int), and level (int). The constructor takes name, maxHealth, and level, setting health equal to maxHealth initially. Include getters for all fields. Add a protected method setHealth(int health) that ensures health stays between 0 and maxHealth. Create a method takeDamage(int damage) that reduces health and returns "[name] takes [damage] damage! Health: [health]/[maxHealth]". Add a method isAlive() returning true if health is greater than 0. Declare an abstract method getCharacterClass() returning a String.
  • Warrior.java: Create a class extending Character and implementing Attackable. Add a private field strength (int). The constructor takes name, maxHealth, level, and strength. Implement getCharacterClass() to return "Warrior". Implement getDamageType() to return PHYSICAL. Implement attack(Character target) to deal damage equal to strength plus level, call the target's takeDamage method, and return "[name] strikes with [damageType description] for [damage] damage!" followed by a newline and the takeDamage result.
  • Mage.java: Create a class extending Character and implementing both Attackable and Healable. Add private fields intelligence (int) and mana (int). The constructor takes name, maxHealth, level, intelligence, and mana. Implement getCharacterClass() to return "Mage". Implement getDamageType() to return MAGICAL. Implement attack(Character target) to deal damage equal to intelligence times 2, following the same format as Warrior. Implement heal(int amount) to restore health (using setHealth) and return "[name] channels healing magic! Health: [health]/[maxHealth]".
  • Main.java: Bring your game system to life! You'll receive a comma-separated string of commands:
    • CREATE_WARRIOR:name:maxHealth:level:strength
    • CREATE_MAGE:name:maxHealth:level:intelligence:mana
    • ATTACK:attackerName:targetName
    • HEAL:mageName:amount
    • STATUS:characterName

    Maintain a collection of characters. Process each command and print:

    • CREATE_WARRIOR/CREATE_MAGE: [name] the [characterClass] joins the battle!
    • ATTACK: Print the attack result (the String returned by attack method)
    • HEAL: Print the heal result, or [name] cannot heal if the character isn't a Mage
    • STATUS: [name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]

    After all commands, print --- Battle Summary --- followed by each character's status.

You will receive one input: the comma-separated command string.

For example, with input CREATE_WARRIOR:Thorin:100:5:15,CREATE_MAGE:Gandalf:80:7:12:50,ATTACK:Thorin:Gandalf,HEAL:Gandalf:25,STATUS:Gandalf, your output would be:

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 - Alive

This challenge combines inheritance (Character hierarchy), multiple interface implementation (Mage implements both Attackable and Healable), enums with methods (DamageType), polymorphism (treating different character types uniformly), and encapsulation (protected health management) into an engaging game system!

Cheat sheet

Object-oriented programming (OOP) allows modeling complex systems through classes, inheritance, interfaces, and design patterns.

Class Hierarchy

Create a base class with common attributes and extend it with specialized classes:

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();
}

Interfaces

Define contracts for specific behaviors that classes can implement:

public interface Attackable {
    String attack(Character target);
    DamageType getDamageType();
}

public interface Healable {
    String heal(int amount);
}

Enums with Fields

Enums can have fields, constructors, and methods:

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;
    }
}

Multiple Interface Implementation

A class can implement multiple interfaces:

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
    }
}

Encapsulation

Use private fields with protected setters to control access and validate data:

protected void setHealth(int health) {
    this.health = Math.max(0, Math.min(health, maxHealth));
}

Polymorphism

Treat different character types uniformly through their common base class or interfaces, allowing flexible collections and method calls.

Try it yourself

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: Use a collection to maintain characters (LinkedHashMap preserves insertion order)
        // LinkedHashMap<String, Character> characters = new LinkedHashMap<>();
        
        // TODO: Split input by comma to get individual commands
        // String[] commands = input.split(",");
        
        // TODO: Process each command:
        // - CREATE_WARRIOR:name:maxHealth:level:strength
        //   Print: "[name] the Warrior joins the battle!"
        // 
        // - CREATE_MAGE:name:maxHealth:level:intelligence:mana
        //   Print: "[name] the Mage joins the battle!"
        // 
        // - ATTACK:attackerName:targetName
        //   Print the attack result from the attack method
        // 
        // - HEAL:mageName:amount
        //   Print heal result, or "[name] cannot heal" if not a Mage
        // 
        // - STATUS:characterName
        //   Print: "[name] ([characterClass]) - Level [level] - Health: [health]/[maxHealth] - [Alive/Defeated]"
        
        // TODO: After all commands, print "--- Battle Summary ---"
        // Then print each character's status
    }
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming