new changes

master
Mark Beck 2025-11-06 14:56:58 +01:00
parent 289b635077
commit e9602140e9
7 changed files with 199 additions and 21 deletions

View File

@ -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<App> appClassToken = app.class;
```

View File

@ -0,0 +1,7 @@
public record BattleWin(
Entity winningSquad,
Entity loosingSquad,
boolean draw,
) {
}

View File

@ -7,22 +7,34 @@ import com.example.ecs.Entity;
public class Squad implements Component {
private String name;
private List<Entity> units;
private List<Entity> activeUnits;
private List<Entity> deadUnits;
public Squad(String name, List<Entity> 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<Entity> units() {
return units;
public List<Entity> activeUnits() {
return activeUnits;
}
public List<Entity> deadUnits() {
return deadUnits;
}
public boolean isActive() {
return !activeUnits.empty()
}
}

View File

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

View File

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

View File

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

View File

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