Skip to main content

RPG Game System with Interfaces and Inheritance

Complete game system demonstrating interfaces, abstract classes, inheritance, and polymorphism

SpacialElement (Base Class)

Base class for all elements that exist in the game world.

  • name: Name of the element (protected)
  • x: X coordinate on the map (protected)
  • y: Y coordinate on the map (protected)
  • SpacialElement(String name, int x, int y): Constructor to place element at coordinates
  • Implements Movable interface
  • All game elements inherit from this class

Movable (Interface)

Interface for elements that can move in four directions.

  • goUp(int speed): Move up by speed units
  • goDown(int speed): Move down by speed units
  • goRight(int speed): Move right by speed units
  • goLeft(int speed): Move left by speed units

Attacker (Interface)

Interface for entities that can attack.

  • attack(target): Attack a target entity

DistantAttacker (Interface)

Interface for entities that can attack from a distance.

  • distantAttack(target, int): Attack a target from distance with range parameter

Flying (Interface)

Interface for entities that can fly.

  • takeOff(): Take off from ground, returns success status
  • land(): Land on ground, returns success status

Adopt (Interface)

Interface for entities that can adopt other beings (like packs).

  • adopt(candidate MovableBeing): Adopt a movable being into the group, returns success
  • revoke(candidate Object): Remove a being from the group, returns success

Being

Living entity with health and resistance.

  • maxHealth: Maximum health points (private)
  • health: Current health points (protected)
  • resistance: Damage resistance (protected)
  • Extends SpacialElement
  • receiveDamage(int amount): Reduces health by damage minus resistance
  • getLuckLevel(): Returns a luck value affecting outcomes
  • Base class for all living entities

MovableBeing (Abstract Class)

Abstract base class for all creatures that can move and fight.

  • maxSpeed: Maximum movement speed (protected)
  • force: Attack strength (protected)
  • inAir: Whether the being is currently airborne (protected)
  • Extends Being
  • Implements Attacker and Movable interfaces
  • canMove(String direction): Checks if movement in direction is possible
  • communicate(): Makes sounds or communicates with others
  • Cannot be instantiated directly

Humanoid (Abstract Class)

Abstract base class for human-like creatures.

  • Extends MovableBeing
  • No additional attributes or methods in base form
  • Template for warrior, archer, wizard types
  • Cannot be instantiated directly

Animal (Abstract Class)

Abstract base class for animal creatures.

  • Extends MovableBeing
  • getMaxSpeed(): Returns maximum speed (animals tend to be fast)
  • Template for dragons, eagles, wolves, etc.
  • Cannot be instantiated directly

Pack

Group of creatures that moves and acts together.

  • maxSize: Maximum number of members (private)
  • name: Name of the pack (public)
  • Extends SpacialElement
  • Implements Adopt, Movable, and Attacker interfaces
  • Pack(MovableBeing chief): Creates pack with a leader
  • isInPack(Object being): Checks if a being is member of this pack
  • Contains 1 or more MovableBeing members
  • Has exactly 1 chief (leader)
  • Pack moves as a unit and can attack as a group

Warrior

Melee fighter class.

  • Extends Humanoid
  • No special attributes beyond inherited ones
  • Strong in close combat

Archer

Ranged attacker with bow and arrows.

  • range: Maximum attack range (public)
  • dexterity: Skill level with ranged weapons (public)
  • Extends Humanoid
  • Implements DistantAttacker interface
  • Can attack from distance

Dragon

Powerful flying creature with breath weapon.

  • power: Attack power multiplier (private)
  • range: Distance of breath attack (public)
  • Extends Animal
  • Implements Flying and DistantAttacker interfaces
  • Can fly and attack from distance with breath weapon

Eagle

Flying bird of prey.

  • vision: Range of sight (public)
  • Extends Animal
  • Implements Flying interface
  • High speed and vision, can fly

Wolf

Ground-based pack animal.

  • Extends Animal
  • No special attributes
  • Typically part of a Pack

Tree

Static vegetation obstacle.

  • Extends Being (has health, can be damaged/destroyed)
  • No movement or attack capabilities
  • Blocks movement

Rock

Static terrain obstacle.

  • Extends SpacialElement (not Being - cannot be damaged)
  • No health or combat properties
  • Permanent obstacle

Map

Game world that contains all spatial elements.

  • WIDTH: Map width in tiles (static public constant)
  • HEIGHT: Map height in tiles (static public constant)
  • add(SpacialElement element): Adds element to the map
  • Maintains collection of all elements in the game world

Exporter

Utility for saving and loading game state.

  • serialize(Object map, String path): Saves map to file
  • deserialize(String path): Loads map from file, returns Map object
  • filter(Object m): Private method to filter elements before export

Practice Exercise: Implement the RPG Game System

Objective: Implement the complete game system matching the UML diagram precisely.

Requirements:

  1. Create all 5 interfaces: Movable, Attacker, DistantAttacker, Flying, Adopt
  2. Create base class SpacialElement implementing Movable
  3. Create Being extending SpacialElement with health system
  4. Create abstract MovableBeing extending Being and implementing Attacker and Movable
  5. Create abstract Humanoid and Animal classes
  6. Implement all concrete classes: Warrior, Archer, Dragon, Eagle, Wolf, Tree, Rock, Pack
  7. Implement Map and Exporter utility classes
  8. Demonstrate polymorphism with pack mechanics
💡 Click to see suggested implementation
// Movable interface
public interface Movable {
void goUp(int speed);
void goDown(int speed);
void goRight(int speed);
void goLeft(int speed);
}

// Attacker interface
public interface Attacker {
void attack(Object target);
}

// DistantAttacker interface
public interface DistantAttacker {
void distantAttack(Object target, int range);
}

// Flying interface
public interface Flying {
boolean takeOff();
boolean land();
}

// Adopt interface
public interface Adopt {
boolean adopt(MovableBeing candidate);
boolean revoke(Object candidate);
}

// SpacialElement base class
public class SpacialElement implements Movable {
protected String name;
protected int x;
protected int y;

public SpacialElement(String name, int x, int y) {
this.name = name;
this.x = x;
this.y = y;
}

@Override
public void goUp(int speed) {
y -= speed;
}

@Override
public void goDown(int speed) {
y += speed;
}

@Override
public void goRight(int speed) {
x += speed;
}

@Override
public void goLeft(int speed) {
x -= speed;
}

public String getName() { return name; }
public int getX() { return x; }
public int getY() { return y; }
}

// Being class
public class Being extends SpacialElement {
private int maxHealth;
protected int health;
protected double resistance;

public Being(String name, int x, int y, int maxHealth, double resistance) {
super(name, x, y);
this.maxHealth = maxHealth;
this.health = maxHealth;
this.resistance = resistance;
}

public void receiveDamage(int amount) {
int actualDamage = (int) (amount - resistance);
if (actualDamage > 0) {
health -= actualDamage;
if (health < 0) health = 0;
}
System.out.println(name + " received " + actualDamage + " damage. HP: " + health);
}

public int getLuckLevel() {
return (int) (Math.random() * 10); // Random luck 0-9
}

public int getHealth() { return health; }
public boolean isAlive() { return health > 0; }
}

// MovableBeing abstract class
public abstract class MovableBeing extends Being implements Attacker {
protected int maxSpeed;
protected int force;
protected boolean inAir;

public MovableBeing(String name, int x, int y, int health, double resistance, int force) {
super(name, x, y, health, resistance);
this.force = force;
this.maxSpeed = 5;
this.inAir = false;
}

public boolean canMove(String direction) {
return isAlive(); // Can only move if alive
}

public void communicate() {
System.out.println(name + " communicates!");
}

// Abstract attack method - each type implements differently
@Override
public abstract void attack(Object target);

public int getForce() { return force; }
}

// Humanoid abstract class
public abstract class Humanoid extends MovableBeing {
public Humanoid(String name, int x, int y) {
super(name, x, y, 100, 5.0, 15); // Standard humanoid stats
}
}

// Animal abstract class
public abstract class Animal extends MovableBeing {
public Animal(String name, int x, int y, int health, double resistance, int force) {
super(name, x, y, health, resistance, force);
this.maxSpeed = 8; // Animals tend to be faster
}

public int getMaxSpeed() {
return maxSpeed;
}
}

// Warrior class
public class Warrior extends Humanoid {
public Warrior(String name, int x, int y) {
super(name, x, y);
this.force = 20; // Warriors are strong
}

@Override
public void attack(Object target) {
if (target instanceof Being && isAlive()) {
System.out.println(name + " attacks with sword!");
((Being) target).receiveDamage(force);
}
}
}

// Archer class
public class Archer extends Humanoid implements DistantAttacker {
public int range;
public int dexterity;

public Archer(String name, int x, int y) {
super(name, x, y);
this.range = 10;
this.dexterity = 15;
this.force = 12;
}

@Override
public void attack(Object target) {
if (target instanceof Being && isAlive()) {
System.out.println(name + " shoots arrow!");
((Being) target).receiveDamage(force);
}
}

@Override
public void distantAttack(Object target, int distance) {
if (target instanceof Being && isAlive() && distance <= range) {
int damage = force + dexterity / 2;
System.out.println(name + " shoots from distance " + distance + "!");
((Being) target).receiveDamage(damage);
}
}
}

// Dragon class
public class Dragon extends Animal implements Flying, DistantAttacker {
private int power;
public int range;

public Dragon(String name, int x, int y) {
super(name, x, y, 200, 15.0, 30);
this.power = 40;
this.range = 15;
}

@Override
public boolean takeOff() {
if (!inAir) {
inAir = true;
System.out.println(name + " takes off!");
return true;
}
return false;
}

@Override
public boolean land() {
if (inAir) {
inAir = false;
System.out.println(name + " lands!");
return true;
}
return false;
}

@Override
public void attack(Object target) {
if (target instanceof Being && isAlive()) {
System.out.println(name + " breathes fire!");
((Being) target).receiveDamage(power);
}
}

@Override
public void distantAttack(Object target, int distance) {
if (target instanceof Being && isAlive() && distance <= range) {
System.out.println(name + " breathes fire from distance!");
((Being) target).receiveDamage(power + 10);
}
}
}

// Eagle class
public class Eagle extends Animal implements Flying {
public int vision;

public Eagle(String name, int x, int y) {
super(name, x, y, 50, 2.0, 8);
this.vision = 20;
}

@Override
public boolean takeOff() {
if (!inAir) {
inAir = true;
System.out.println(name + " soars into the sky!");
return true;
}
return false;
}

@Override
public boolean land() {
if (inAir) {
inAir = false;
System.out.println(name + " lands gracefully!");
return true;
}
return false;
}

@Override
public void attack(Object target) {
if (target instanceof Being && isAlive()) {
System.out.println(name + " dives and strikes!");
((Being) target).receiveDamage(force);
}
}
}

// Wolf class
public class Wolf extends Animal {
public Wolf(String name, int x, int y) {
super(name, x, y, 80, 3.0, 12);
}

@Override
public void attack(Object target) {
if (target instanceof Being && isAlive()) {
System.out.println(name + " bites!");
((Being) target).receiveDamage(force);
}
}

@Override
public void communicate() {
System.out.println(name + " howls!");
}
}

// Tree class
public class Tree extends Being {
public Tree(String name, int x, int y) {
super(name, x, y, 100, 0.0);
}

@Override
public void goUp(int speed) {
System.out.println("Trees cannot move!");
}

@Override
public void goDown(int speed) {
System.out.println("Trees cannot move!");
}

@Override
public void goRight(int speed) {
System.out.println("Trees cannot move!");
}

@Override
public void goLeft(int speed) {
System.out.println("Trees cannot move!");
}
}

// Rock class
public class Rock extends SpacialElement {
public Rock(String name, int x, int y) {
super(name, x, y);
}

@Override
public void goUp(int speed) {
System.out.println("Rocks cannot move!");
}

@Override
public void goDown(int speed) {
System.out.println("Rocks cannot move!");
}

@Override
public void goRight(int speed) {
System.out.println("Rocks cannot move!");
}

@Override
public void goLeft(int speed) {
System.out.println("Rocks cannot move!");
}
}

// Pack class
import java.util.ArrayList;
import java.util.List;

public class Pack extends SpacialElement implements Adopt, Attacker {
private int maxSize;
public String name;
private MovableBeing chief;
private List<MovableBeing> members;

public Pack(MovableBeing chief) {
super("Pack of " + chief.getName(), chief.getX(), chief.getY());
this.chief = chief;
this.maxSize = 10;
this.members = new ArrayList<>();
this.members.add(chief);
this.name = "Pack";
}

@Override
public boolean adopt(MovableBeing candidate) {
if (members.size() < maxSize && !members.contains(candidate)) {
members.add(candidate);
System.out.println(candidate.getName() + " joined the pack!");
return true;
}
return false;
}

@Override
public boolean revoke(Object candidate) {
if (candidate instanceof MovableBeing && candidate != chief) {
boolean removed = members.remove(candidate);
if (removed) {
System.out.println(((MovableBeing) candidate).getName() + " left the pack!");
}
return removed;
}
return false;
}

public boolean isInPack(Object being) {
return members.contains(being);
}

@Override
public void attack(Object target) {
System.out.println("Pack attacks together!");
for (MovableBeing member : members) {
member.attack(target);
}
}

@Override
public void goUp(int speed) {
super.goUp(speed);
for (MovableBeing member : members) {
member.goUp(speed);
}
}

@Override
public void goDown(int speed) {
super.goDown(speed);
for (MovableBeing member : members) {
member.goDown(speed);
}
}

@Override
public void goRight(int speed) {
super.goRight(speed);
for (MovableBeing member : members) {
member.goRight(speed);
}
}

@Override
public void goLeft(int speed) {
super.goLeft(speed);
for (MovableBeing member : members) {
member.goLeft(speed);
}
}

public MovableBeing getChief() { return chief; }
public List<MovableBeing> getMembers() { return new ArrayList<>(members); }
}

// Map class
import java.util.ArrayList;
import java.util.List;

public class Map {
public static final String WIDTH = "100";
public static final String HEIGHT = "100";
private List<SpacialElement> elements;

public Map() {
this.elements = new ArrayList<>();
}

public void add(SpacialElement element) {
elements.add(element);
System.out.println("Added " + element.getName() + " to map at (" +
element.getX() + ", " + element.getY() + ")");
}

public List<SpacialElement> getElements() {
return new ArrayList<>(elements);
}
}

// Exporter class
import java.io.*;

public class Exporter {
public void serialize(Object map, String path) {
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(path))) {
out.writeObject(filter(map));
System.out.println("Map exported to " + path);
} catch (IOException e) {
System.err.println("Export failed: " + e.getMessage());
}
}

public Object deserialize(String path) {
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(path))) {
Object map = in.readObject();
System.out.println("Map imported from " + path);
return map;
} catch (IOException | ClassNotFoundException e) {
System.err.println("Import failed: " + e.getMessage());
return null;
}
}

private Object filter(Object m) {
// Filter out temporary or invalid elements before export
return m;
}
}

// Game demo
public class RPGGameDemo {
public static void main(String[] args) {
System.out.println("=== RPG Game System Demo ===\n");

// Create map
Map gameMap = new Map();

// Add terrain
gameMap.add(new Tree("Oak", 10, 10));
gameMap.add(new Rock("Boulder", 15, 15));

// Create characters
Warrior warrior = new Warrior("Aragorn", 5, 5);
Archer archer = new Archer("Legolas", 7, 5);
Dragon dragon = new Dragon("Smaug", 50, 50);
Eagle eagle = new Eagle("Gwaihir", 60, 5);

gameMap.add(warrior);
gameMap.add(archer);
gameMap.add(dragon);
gameMap.add(eagle);

// Create wolf pack
Wolf alpha = new Wolf("Alpha", 20, 20);
Wolf beta = new Wolf("Beta", 21, 20);
Wolf gamma = new Wolf("Gamma", 20, 21);

Pack wolfPack = new Pack(alpha);
wolfPack.adopt(beta);
wolfPack.adopt(gamma);
gameMap.add(wolfPack);

System.out.println("\n=== Combat Demo ===");

// Warrior attacks dragon
warrior.attack(dragon);

// Archer uses distant attack
archer.distantAttack(dragon, 8);

// Dragon flies and attacks
dragon.takeOff();
dragon.distantAttack(warrior, 10);
dragon.land();

// Pack attacks together
System.out.println("\nWolf pack attacks:");
wolfPack.attack(warrior);

// Eagle flies
eagle.takeOff();
eagle.attack(gamma);

System.out.println("\n=== Movement Demo ===");
System.out.println("Pack position: (" + wolfPack.getX() + ", " + wolfPack.getY() + ")");
wolfPack.goRight(3);
System.out.println("Pack moved to: (" + wolfPack.getX() + ", " + wolfPack.getY() + ")");

System.out.println("\n=== Pack Info ===");
System.out.println("Pack members: " + wolfPack.getMembers().size());
System.out.println("Pack chief: " + wolfPack.getChief().getName());
}
}

Key Implementation Points:

  • SpacialElement is the base class for ALL game elements
  • Being extends SpacialElement and adds health/resistance
  • MovableBeing is abstract and implements both Attacker and inherits Movable
  • Humanoid and Animal are abstract templates
  • Pack extends SpacialElement (not Being) and implements 3 interfaces
  • Tree extends Being (can be damaged) but Rock extends SpacialElement (indestructible)
  • Static constants in Map are public Strings
  • Multiple interface implementation shown (Dragon, Archer, Pack)
  • Pack contains and moves members together
  • Protected members allow subclass access