184 lines
5.2 KiB
Markdown
184 lines
5.2 KiB
Markdown
|
# My Behaviour Tree
|
||
|
|
||
|
## Lizenz
|
||
|
check the License.md file.
|
||
|
|
||
|
|
||
|
## Was macht ein Behaviourtree
|
||
|
|
||
|
Behaviour Trees sind eine High-Level Struktur zum steuern von künstlichen Intelligenzen oder Abläufen.
|
||
|
|
||
|
MyBT ist keine exakte abbildung von Behaviour Trees sondern Arbeitet mit ähnlichen Methoden welche ich für sinnvoll erachtet habe.
|
||
|
|
||
|
Neben dem Behaviour Tree muss man auch die aufgerufenen Funktionen definieren.
|
||
|
|
||
|
## Grundstruktur
|
||
|
|
||
|
Ein GameObject mit folgenden Komponenten:
|
||
|
|
||
|
- TaskController
|
||
|
- Ein Behaviour Tree Script auf "TaskScript" legen
|
||
|
- Weitere Monobehaviours die vom Behaviour Tree aufgerufen werden.
|
||
|
|
||
|
## Aufbau Behaviour Tree Script
|
||
|
|
||
|
Ein neues Unity Text Asset erstellen.
|
||
|
|
||
|
zBsp. Name.bt.txt
|
||
|
|
||
|
```
|
||
|
Tree("Root") {
|
||
|
Composite (Sequence) {
|
||
|
RunTree ("Player")
|
||
|
}
|
||
|
}
|
||
|
Tree ("Player") {
|
||
|
Composite (Sequence) {
|
||
|
SimpleController.SetRandomTarget (0, 0, 10)
|
||
|
Composite (Race) {
|
||
|
SimpleController.NearTarget (2)
|
||
|
SimpleController.RotateTowards (90)
|
||
|
SimpleController.MoveForward (4)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Kommentare sind moeglich, gegenwaertig sie aber nicht im editor dargestellt
|
||
|
Einzeilige Kommentare mittels //
|
||
|
Mehrzeilige Kommentare mittels /* und */
|
||
|
|
||
|
## Composite Typen:
|
||
|
// --- Sequence node ---
|
||
|
Starts all Children in sequence:
|
||
|
- any child running -> return running
|
||
|
- any child success -> continue in loop
|
||
|
- any child failed -> return failed
|
||
|
- finally -> exit success (there is no looping)
|
||
|
// ---
|
||
|
|
||
|
// --- Selector (fallback) node ---
|
||
|
Starts all Children in sequence:
|
||
|
- any child running -> continue in loop
|
||
|
- any child success -> return success
|
||
|
- any child failed -> continue in loop
|
||
|
- finally -> exit failed (there is no looping)
|
||
|
// ---
|
||
|
|
||
|
|
||
|
// --- Race Node, first finishes ---
|
||
|
Starts all Children in parallel:
|
||
|
- any child running -> continue in loop
|
||
|
- any child success -> return success, abort all remaining running
|
||
|
- any child failed -> continue in loop
|
||
|
- return after 1 iteration
|
||
|
- if all fail, fail.
|
||
|
// ---
|
||
|
|
||
|
// --- Marathon Node, wait for everyone ---
|
||
|
Starts all Children in parallel:
|
||
|
- any child running -> continue in loop
|
||
|
- any child success -> continue in loop
|
||
|
- any child failed -> continue in loop
|
||
|
- return after 1 iteration
|
||
|
- succeed when all are succeeded or failed
|
||
|
// ---
|
||
|
## Einen Task erstellen
|
||
|
|
||
|
## Decorator Typen:
|
||
|
Ein Decorator veraendert das resultat eines umschlossenen tasks oder composites
|
||
|
|
||
|
// --- Inverter ---
|
||
|
- return succeeded when failed
|
||
|
- return failed when succeeded
|
||
|
// ---
|
||
|
|
||
|
// --- ReturnSucceed ---
|
||
|
- returns succeeded when failed or succeeded
|
||
|
// ---
|
||
|
|
||
|
// --- Repeat ---
|
||
|
- returns running when failed or succeeded
|
||
|
// ---
|
||
|
|
||
|
// --- RepeatUntilFailed ---
|
||
|
- returns running when succeeded
|
||
|
// ---
|
||
|
##
|
||
|
|
||
|
Ein Unity Monobehaviour erstellen und auf das Objekt legen.
|
||
|
|
||
|
Alle Funktionen mit `[Task]` können durch MyBT aufgerufen werden.
|
||
|
|
||
|
Es gibt 2 Varianten wie ein Task aufgebaut werden kann:
|
||
|
|
||
|
### Ausführung der Tasks
|
||
|
|
||
|
* Ein Task wird einmal im Zustand "FirstRun" ausgeführt
|
||
|
* Danach im Zustand "Running"
|
||
|
* Beim Abbrechen wird der Task noch einmal mit dem Zustand "Aborting" Ausgeführt. Aborting wird nicht generell ausgeführt, sondern wenn ein Task, zBsp. aufgrund eines Races nicht mehr weiter ausgeführt wird.
|
||
|
|
||
|
### Task Code Variante 1
|
||
|
|
||
|
Prüfe mit `Task.Running(this)` ob der Task im Running oder Starting Zustand ist:
|
||
|
|
||
|
```c#
|
||
|
[Task]
|
||
|
public void MoveBy(float x, float y, float z) {
|
||
|
if (Task.isStartingOrRunning) {
|
||
|
transform.position += new Vector3(x, y, z) * Time.deltaTime;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
### Task Code Variante 2
|
||
|
|
||
|
Nutze einen `Switch(Task.GetState(this))` um zu Prüfen in welchem Zustand der Task Ist:
|
||
|
|
||
|
```c#
|
||
|
[Task]
|
||
|
public void MoveByTimed(float x, float y, float z, float timer) {
|
||
|
switch (Task.getState) {
|
||
|
case NodeState.FirstRun:
|
||
|
Task.data = Time.time;
|
||
|
break;
|
||
|
case NodeState.Running:
|
||
|
float startTime = (float)Task.data;
|
||
|
float elapsed = Time.time - startTime;
|
||
|
if (elapsed > timer) {
|
||
|
Task.Succeeded(this);
|
||
|
}
|
||
|
transform.position += new Vector3(x, y, z) * Time.deltaTime;
|
||
|
break;
|
||
|
case NodeState.Aborting:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
### Task Return Fail or Succeess
|
||
|
|
||
|
Mittels `Task.Succeeded(this);` und `Task.Failed(this);` kann der Task ein Signal zurückgeben.
|
||
|
|
||
|
### Daten zum Task speichern
|
||
|
|
||
|
Mit `Task.SetData(object)` können Daten gespeichert und mit `Task.GetData()` wieder geladen werden. Diese sind nur mit der Instanz der Methode verbunden, nicht mit der Klasse. Wird der Composite unterbrochen, werden auf die daten gelöscht.
|
||
|
|
||
|
Ein Task kann natürlich auch Daten in der Klasse speichern und unter den Tasks austauschen.
|
||
|
|
||
|
### Einschränkungen für Tasks
|
||
|
|
||
|
Es gibt Einschränkungen bezüglich der möglichen Parameter der Tasks. Es können keine Funktionen als Parameter übergeben werden, so ist es z.Bsp. nicht möglich einen Vector3 als Parameter anzugeben.
|
||
|
|
||
|
Folgende Parameter sind unterstützt.
|
||
|
|
||
|
- Bool
|
||
|
- Int
|
||
|
- Float
|
||
|
- Char
|
||
|
- String
|
||
|
- Enum
|