From e9602140e9c6d9fed0934bcd308b0ffb46c2a82d Mon Sep 17 00:00:00 2001 From: Mark Beck Date: Thu, 6 Nov 2025 14:56:58 +0100 Subject: [PATCH] new changes --- README.md | 63 ++++++++++++++----- .../com/example/components/BattleWin.java | 7 +++ .../java/com/example/components/Squad.java | 22 +++++-- .../example/systems/SquadUpdateSystem.java | 44 +++++++++++++ .../java/com/example/systems/WinSystem.java | 44 +++++++++++++ src/test/java/com/example/ecs/EntityTest.java | 21 +++++++ .../java/com/example/ecs/RegistryTest.java | 19 ++++++ 7 files changed, 199 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/example/components/BattleWin.java create mode 100644 src/main/java/com/example/systems/SquadUpdateSystem.java create mode 100644 src/main/java/com/example/systems/WinSystem.java create mode 100644 src/test/java/com/example/ecs/EntityTest.java create mode 100644 src/test/java/com/example/ecs/RegistryTest.java diff --git a/README.md b/README.md index 45259e9..1b45cbb 100644 --- a/README.md +++ b/README.md @@ -80,48 +80,72 @@ Werden jetzt wie im vorherigen Beispiel die Lebenspunkte aller Wesen gebraucht, Ein Entity-Component-System besteht aus vier Konzepten: -### Entities +### Entity Entities sind Spielobjekte, sie sind meist nicht mehr als eine fortlaufende ID. -### Components - +### Component Components sind die zum Spielobjekt gehörenden Daten. Wie viele Daten jede Art von Component enthält kann verschieden sein. Zum Beispiel kann ein `Lebenspunkte` Component nur die derzeitigen Lebenspunkte enthalten, während ein `Kampfkraft` Component Schaden, Geschwindigkeit und Rüstung enthält. ### Registry -Die Registry ist eine Datenbank, die alle Entities ihren Components zuweist und folgende Operationen Erlaubt: +Die Registry ist eine Datenbank, die alle Entities ihren Components zuweist und meist folgende Operationen erlaubt: +- addComponent(entity, component) -- Füge einen neuen Component in die verwaltung hinzu. +- removeComponent(entity, ComponentType) -- Lösche den Component diesen Types für die Entity. +- withComponents(ComponentTypes[]) -- erstelle eine Liste aller Entities, die alle angegebenen Component Typen besitzen. + +### Sytem + +Systems bilden die Anwendungslogik ab. Sie können die Registry nach Entities abfragen und neue Entities oder Components hinzufügen. +Ein System könnte zum Beispiel die Schadensberechnung für alle Einheiten durchführen und daraus Schadens-Entities erstellen und ein anderes System alle Schadens-Entities abfragen und Lebenspunkte abziehen. + + +## Aufgabe + +Ihre Aufgabe ist es ein Entity-Component-System zu entwickeln. +Das ECS muss mindestens aus folgenden Klassen bestehen: + +- class Entity -- Entities sollten unveränderbar und nach Wert vergleichbar sein. + - die folgenden beiden Konstruktoren müssen existieren: + - public Entity() + - protected Entity(int) + +- interface Component -- Ein interface zur Markierung von Components. +- class Registry -- Die Registry soll alle Entities und Components verwalten. Sie soll folgende Operationen unterstuützen: ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ registerComponentType(componentClass) │ -│ └─ Registriert eine neue Art von Component zur Verwaltung │ +│ └─ Registriert eine neue Art von Component zur Verwaltung. +| Es dürfen nur Klassen akzeptiert werden, die das Interface Component implementieren │ │ │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ addComponent(entity, component) │ -│ └─ Fügt der Entity einen neuen Component hinzu │ +│ └─ Fügt der Entity einen neuen Component hinzu. +| Diese Methode akzeptiert alle Components, die das Interface Component implementieren. +| Besitzt die Entity bereits einen Component dieser Klasse, wird dieser durch die neue Instanz ersetzt. │ │ │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ -│ removeComponent(entity, componentType) │ -│ └─ Löscht den angegebenen Component von der Entity │ +│ removeComponent(entity, componentClass) │ +│ └─ Löscht den Component der angegebenen Klasse von der Entity. │ │ │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ -│ hasComponent(entity, componentType) → boolean │ -│ └─ Prüft, ob die Entity einen Component diesen Types hat │ +│ hasComponent(entity, componentClass) → boolean │ +│ └─ Prüft, ob die Entity einen Component dieser Klasse hat. │ │ │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ -│ getComponent(entity, componentType) → component │ -│ └─ Gibt den angegebenen Component für die Entity zurück │ +│ getComponent(entity, componentClass) → component │ +│ └─ Gibt den Component der angegebenen Klasse für die Entity zurück. │ │ │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ -│ withComponents(componentType...) → entity[] │ -│ └─ Gibt alle Entities zurück, die alle angegebenen Components haben │ +│ withComponents(componentClass...) → entity[] │ +│ └─ Gibt alle Entities zurück, die alle angegebenen Components haben. │ │ │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ @@ -131,6 +155,13 @@ Die Registry ist eine Datenbank, die alle Entities ihren Components zuweist und └─────────────────────────────────────────────────────────────────────────┘ ``` -### Sytems +Tipp: -Systems bilden die Anwendungslogik ab. Sie können die Registry nach Entities abfragen und neue Entities oder Components hinzufügen +Sie können die Klasse eines Objektes mit der .class Eigenschaft ermitteln. Das damit erzeugte Class-Token kann wie jeder andere Wert in Datenstruckturen gespeichert werden. + +``` +class App {} + +App app = new App(); +Class appClassToken = app.class; +``` \ No newline at end of file diff --git a/src/main/java/com/example/components/BattleWin.java b/src/main/java/com/example/components/BattleWin.java new file mode 100644 index 0000000..fc49178 --- /dev/null +++ b/src/main/java/com/example/components/BattleWin.java @@ -0,0 +1,7 @@ +public record BattleWin( + Entity winningSquad, + Entity loosingSquad, + boolean draw, +) { + +} \ No newline at end of file diff --git a/src/main/java/com/example/components/Squad.java b/src/main/java/com/example/components/Squad.java index 99e0a67..64ba492 100644 --- a/src/main/java/com/example/components/Squad.java +++ b/src/main/java/com/example/components/Squad.java @@ -7,22 +7,34 @@ import com.example.ecs.Entity; public class Squad implements Component { private String name; - private List units; + private List activeUnits; + private List deadUnits; public Squad(String name, List units) { this.name = name; this.units = units; } - public void removeUnit(Entity entity) { - units.remove(entity); + public void killUnit(Entity entity) { + if (activeUnits.contains(entity)) { + activeUnits.remove(entity); + deadUnits.add(unit); + } } public String name() { return name; } - public List units() { - return units; + public List activeUnits() { + return activeUnits; + } + + public List deadUnits() { + return deadUnits; + } + + public boolean isActive() { + return !activeUnits.empty() } } diff --git a/src/main/java/com/example/systems/SquadUpdateSystem.java b/src/main/java/com/example/systems/SquadUpdateSystem.java new file mode 100644 index 0000000..335cbe9 --- /dev/null +++ b/src/main/java/com/example/systems/SquadUpdateSystem.java @@ -0,0 +1,44 @@ +package com.example.systems; + +import java.util.Random; + +import com.example.components.Attack; +import com.example.components.Battle; +import com.example.components.Hero; +import com.example.components.Squad; +import com.example.components.Stats; +import com.example.ecs.Entity; +import com.example.ecs.Registry; +import com.example.ecs.System; + +public class SquadUpdateSystem extends System { + + public UnitKillerSystem(Registry registry) { + super(registry); + } + + public void run() { + for (var battleEntity : registry.getWithComponents(Battle.class)) { + var battle = registry.getComponent(battleEntity, Battle.class); + + var squad1 = registry.getComponent(battle.squad1(), Squad.class); + var squad2 = registry.getComponent(battle.squad2(), Squad.class); + + Entity battleWinEntity = new Entity(); + if (squad1.isActive() && squad2.isActive()) { + BattleWin battleWin(battle.squad1(), battle.squad2(), true); + registry.add(battleWinEntity, battleWin); + } else if (squad1.isActive) { + BattleWin battleWin(battle.squad2(), battle.squad1(), false); + registry.add(battleWinEntity, battleWin); + } else if (squad2.isActive()) { + BattleWin battleWin(battle.squad1(), battle.squad2(), false); + registry.add(battleWinEntity, battleWin); + } + + if (squad1.isActive() || squad2.isActive()) { + registry.remove(battleEntity); + } + } + } +} diff --git a/src/main/java/com/example/systems/WinSystem.java b/src/main/java/com/example/systems/WinSystem.java new file mode 100644 index 0000000..8205b55 --- /dev/null +++ b/src/main/java/com/example/systems/WinSystem.java @@ -0,0 +1,44 @@ +package com.example.systems; + +import java.util.Random; + +import com.example.components.Attack; +import com.example.components.Battle; +import com.example.components.Hero; +import com.example.components.Squad; +import com.example.components.Stats; +import com.example.ecs.Entity; +import com.example.ecs.Registry; +import com.example.ecs.System; + +public class WinSystem extends System { + + public WinSystem(Registry registry) { + super(registry); + } + + public void run() { + for (var battleEntity : registry.getWithComponents(Battle.class)) { + var battle = registry.getComponent(battleEntity, Battle.class); + + var squad1 = registry.getComponent(battle.squad1(), Squad.class); + var squad2 = registry.getComponent(battle.squad2(), Squad.class); + + Entity battleWinEntity = new Entity(); + if (squad1.isActive() && squad2.isActive()) { + BattleWin battleWin(battle.squad1(), battle.squad2(), true); + registry.add(battleWinEntity, battleWin); + } else if (squad1.isActive) { + BattleWin battleWin(battle.squad2(), battle.squad1(), false); + registry.add(battleWinEntity, battleWin); + } else if (squad2.isActive()) { + BattleWin battleWin(battle.squad1(), battle.squad2(), false); + registry.add(battleWinEntity, battleWin); + } + + if (squad1.isActive() || squad2.isActive()) { + registry.remove(battleEntity); + } + } + } +} diff --git a/src/test/java/com/example/ecs/EntityTest.java b/src/test/java/com/example/ecs/EntityTest.java new file mode 100644 index 0000000..f3b1096 --- /dev/null +++ b/src/test/java/com/example/ecs/EntityTest.java @@ -0,0 +1,21 @@ +package com.example.ecs; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assert; + +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ +public class EntityTest { + + /** + * Rigorous Test :-) + */ + @Test + public void ShouldBeCreatable() { + Entity entity = new Entity(); + assert() + } +} \ No newline at end of file diff --git a/src/test/java/com/example/ecs/RegistryTest.java b/src/test/java/com/example/ecs/RegistryTest.java new file mode 100644 index 0000000..c874646 --- /dev/null +++ b/src/test/java/com/example/ecs/RegistryTest.java @@ -0,0 +1,19 @@ +package com.example.ecs; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** + * Unit test for simple App. + */ +public class RegistryTest { + + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() { + assertTrue(true); + } +} \ No newline at end of file