Added some documentation

main
Yan Wittmann 2024-12-13 21:35:22 +01:00
parent b688b5c8f5
commit 7ac9bf90e1
2 changed files with 218 additions and 0 deletions

218
state/CA1.md 100644
View File

@ -0,0 +1,218 @@
# GAI/CA1 - Yan Wittmann
## 1.1 Part 1: State Machines
<!-- TOC -->
* [Einleitung](#einleitung)
* [Szenen und States-Implementierung](#szenen-und-states-implementierung)
* [Konfiguration der Transitionen](#konfiguration-der-transitionen)
* [Bedingungen (`conditions`)](#bedingungen-conditions)
* [Transfer (`transfer`)](#transfer-transfer)
* [Dynamische Zielzustände](#dynamische-zielzustände)
<!-- TOC -->
### Einleitung
Dieses Projekt stellt eine State Machine dar, die in der Lage ist, zwischen unterschiedlichen Zuständen aufgrund von
komplexen Bedingungen zu wechseln.
Hier wird diese für einen Character Controller eingesetzt, sie ist aber generisch genug, um auch für andere Anwendungen
verwendet zu werden.
Die Konfiguration der States und Transitions erfolgt über eine JSON-Datei
[character_state_machine.json](assets/character_state_machine.json), die zur Laufzeit eingelesen wird.
Konkret wird hier ein Reinigungsroboter simuliert, der Müllsäcke einsammelt und zu einem Müllcontainer bringt.
Regelmäßig muss er auch seine Batterie aufladen und dafür zu einer Ladestation fahren.
Eine Video-Demo ist hier verfügbar: [state-machine-demo.mp4](res/state-machine-demo.mp4)
Alle bewertungsrelevanten Punkte sind erfüllt:
- Das Projekt implementiert eine State Machine, die einen nicht-Spieler-Charakter steuert.
- Der aktuelle Zustand ist mit "b" einblendbar.
- Weitere Informationen über den aktuellen Zustand und die Transitionen sind zur Laufzeit mit "b" einblendbar.
Weitere Contrubutors können im Code einfach hinzugefügt werden.
- Ein Node-Graph zeigt die Transitionen und deren Bedingungen, sowie den aktuellen Zustand an. Mit "a" einblendbar.
- Die Visualisierung der Zusatzinformationen kann über "a" und "b" aktiviert und deaktiviert werden.
### Szenen und States-Implementierung
Die Haupt-Szene ist [StateMachineWorld.tscn](scenes/state/StateMachineWorld.tscn).
Diese verwaltet unter anderem diese Insatanzen:
- [SMCharacter.gd](scenes/state/SMCharacter.gd): Der Character, auf den die State Machine angewendet wird.
- [StateMachine.gd](scenes/state/StateMachine.gd): Als child node des Characters hat die state machine die States als
ihre child nodes.
- Weitere Instanzen wie ein [TrashBin.tscn](scenes/state/TrashBin.tscn) oder [Battery.tscn](scenes/state/Battery.tscn).
States implementieren die [State.gd](scenes/state/State.gd)-Klassenschnittstelle, die die folgenden Methoden definiert:
```gdscript
func state_enter() -> void
func state_process(delta: float) -> void
func state_exit(new_state: State) -> void
```
Da die Transitionen ausschließlich über die JSON-Datei konfiguriert werden, sind die States selbst nur für die
Implementierung der Logik zuständig.
Ein Beispiel von [state_PickupTrash.gd](scenes/state/state_PickupTrash.gd), der sich auf den Müllsack zubewegt:
```gdscript
extends State
var pickup_trash_target: Vector2 = Vector2.ZERO
func state_enter():
var waste = state_machine.state_transfer_variables["waste"]
pickup_trash_target = waste.position
print(waste, " ", pickup_trash_target)
func state_process(delta: float) -> void:
character.move_towards(pickup_trash_target, delta)
character.move_and_slide()
```
Es wird hier bereits viel auf den Charakter ausgelagert, um die States möglichst einfach zu halten.
Das viel interresantere ist jedoch die Konfiguration der Transitionen, was im folgenden Kapitel beschrieben wird.
### Konfiguration der Transitionen
In der JSON-Datei [character_state_machine.json](assets/character_state_machine.json) werden die States und Transitions
konfiguriert.
Hierbeit ist das Format möglichst offen gehalten, um auch komplexere Bedingungen zu ermöglichen.
Auf den obersten Ebenen werden allgemein die folgenden Keys verlangt:
```json
{
"start": {
"state": "<state_name>"
},
"template_transitions": {
"<transition_name>": {}
},
"states": {
"<state_name>": {
"transitions": []
}
}
}
```
- `start`: Bestimmt initiale Eigenschaften der State Machine. Eine Property `state` gibt den Startzustand an.
- `template_transitions`: Definieren Transitionen, die in `states` referenziert werden können, falls sie mehrfach
verwendet werden.
- `states`: Definieren die States und über `transitions` deren Transitionen.
Transitionen sind das Kernstück der Konfiguration und haben folgende Struktur:
```json
{
"target": "<state_name>" | { "type": "<selector_type>" },
"signal": "<signal_name>",
"conditions": [],
"transfer": {}
}
```
- `target`: Der Name des Zielzustands, zu dem die State Machine wechseln soll. Kann auch ein Objekt sein, das dynamisch
einen Zielzustand bestimmt.
- `signal`: (Optional) Ein Signalname, der von der State Machine seit dem letzten Tick empfangen werden muss, damit die Transition
berücksichtigt wird.
- `conditions`: Ein Array von Bedingungen, die alle erfüllt sein müssen, damit die Transition durchgeführt wird.
- `transfer`: Ein Objekt, das definiert, welche Daten beim Übergang in den neuen Zustand übergeben werden sollen.
```json
{
"template": "<template_transition_name>",
}
```
- Oder einfach eine Referenz auf eine `template_transition`.
#### Bedingungen (`conditions`)
Bedingungen sind ein Array von Objekten, die alle erfüllt sein müssen, damit eine Transition ausgeführt wird. Jede
Bedingung hat folgende Struktur:
```json
{
"type": "<condition_type>",
"left": {},
"right": {}
}
```
- `type`: Der Typ der Bedingung ("=", "!=", ">", "<", ">=", "<=").
- `left`: Der linke Operand der Bedingung.
- `right`: Der rechte Operand der Bedingung.
Die Operanden können entweder eine `value` Property (direkter Wert), einen `accessor` (Pfad zu einer Variable) oder eine
`function` (Aufruf einer Funktion) verwenden.
- `value`: Ein direkter Wert (z.B. `{"value": 100}`).
- `accessor`: Ein Array von Strings, das einen Pfad zu einer Variable in der Szene oder der State Machine angibt (z.B.
`{"accessor": ["character", "battery_charge"]}`).
- `function`: Ein Objekt, das eine Funktion mit Argumenten aufruft (z.B. `{"function": "distance", "args": [...]}`).
Diese können beliebig verschachtelt werden.
```json
{
"type": "<=",
"left": {
"value": 100
},
"right": {
"accessor": [
"character",
"battery_charge"
]
}
}
```
#### Transfer (`transfer`)
Das `transfer`-Objekt ermöglicht es, Daten zwischen Zuständen zu übertragen. Es ist ein Objekt, bei dem der Key der Name
der Variable ist, und der Wert ein Accessor, der die Datenquelle angibt.
```json
"transfer": {
"waste": {
"accessor": [
"signals",
"waste_detected",
"args",
"waste"
]
}
}
```
In diesem Beispiel wird die Variable `waste` des Zielzustands mit dem Wert des Arguments `waste` des Signals `waste_detected` befüllt.
#### Dynamische Zielzustände
Der `target` einer Transition kann auch ein Objekt sein, das dynamisch einen Zielzustand bestimmt.
Das folgende Beispiel zeigt, wie man in der Historie der Zustände zu einem vorherigen Zustand zurückkehrt,
aber gewisse Zustände dabei ignoriert:
```json
{
"target": {
"type": "history_first",
"ignore": [
"RechargeBattery",
"GoToBattery"
],
"restore_transfer_variables": true
}
}
```
- `type`: Der Typ des dynamischen Ziels (hier: `history_first`).
- `ignore`: Eine Liste von Zuständen, die bei der Suche nach dem vorherigen Zustand ignoriert werden sollen.
- `restore_transfer_variables`: Ein Boolean, der angibt, ob die Transfervariablen dieses vorherigen Zustands ebenfalls
wiederhergestellt werden sollen.

Binary file not shown.