Erstmal Danke für die zahlreichen Antworten!
Na um Verhalten austauschbar zu halten gibt es das Strategy Pattern.
Guck dir den Link mal an. Das sollte dein Problem an sich lösen.
Das Strategy Pattern ist tatsächlich genau wonach ich gesucht habe. Ich habe es mir grade durchgelesen und festgestellt, dass ich das Verhalten von meinen Enemys sehr ähnlich austauschbar gemacht habe. Der einzige Unterschied: ich habe abstrakte Klassen, statt Interfaces verwendet. Wahrscheinlich werde ich das demnächst noch abändern.
Wichtig ist vor allem: Composition over Inheritance
Das von Schorsch genannte Pattern ist dabei eine mögliche Lösung, bei Unity würde man am ehesten mit unterschiedlichen Komponenten vorgehen. (Dabei können die Komponenten eine gemeinsame, abstrakte "Basiskomponente" teilen, welche beim Strategy-Pattern der "Strategy" entsprechen würde. In dem Zusammenhang ist das Attribut RequireComponent sehr nützlich.)
Entweder man sorgt über SendMessage für den richtigen Methodenaufruf, oder man sorgt mit dem RequireComponent-Attribut dafür, dass auf jeden Fall eine geeignete Komponente vorhanden ist, ruft diese einmalig mit GetComponent ab (und speichert die Komponente in einem Member) und kann dann direkt auf die entsprechende Methode zugreifen. (Letzteres wäre zu bevorzugen.)
Danke Sacaldur. Genau, mit RequireComponent, GetComponent und entsprechenden Member lässt sich das Pattern gut in Unity umsetzen.
Dass der Threadersteller wahrscheinlich nicht ganz Sattelfest in C# steckt, merkt bspw. an der Verwendung des Schlüsselworts new für die Update Methode. Das sorgt dafür, dass Objekte der Klasse nur teilweise Polymorph verwendet werden können. (Speichert man ein Objekt dieser Klasse in einer Variable vom Typ der Oberklasse, wird bei einem Aufruf die Methode der Oberklasse aufgerufen, da kein Überschreiben stattgefunden hat. Deshalb würde man in einem solchen Fall override verwenden.)
Ebenfalls gut erkannt hast du, dass ich mich mit c# nicht so wirklich gut auskenne... Ich benutze es halt nur um in Unity zu programmieren. Das new vor der Update-Methode entstand übrigens nur weil Unity rumgemeckert hat, dass ich dort ein new hinsetzen solle
Vererbung bei MonoBehaviours mit Awake, Start, Update etc. interessiert mich jetzt aber doch nochmal:
Eine Oberklasse für alle Einheiten in meinem Spiel sieht sehr minimiert z.B. so aus:
|
C#-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
public class NetworkUnit : NetworkBehaviour
{
// Publics
public int respawnTime;
// Network Syncvars
[SyncVar]
public int life;
// Privates
bool _isAlive = true;
int _maxLife;
void Start()
{
_maxLife = life;
}
[Server]
public void Hit(int damage)
{
life -= damage;
RpcHit();
if(life <= 0 && _isAlive)
{
_isAlive = false;
RpcDestroy();
StartCoroutine(Respawn());
}
}
[Server]
IEnumerator Respawn()
{
yield return new WaitForSeconds(respawnTime);
_isAlive = true;
life = _maxLife;
}
[ClientRpc]
void RpcDestroy()
{
// Grafische Darstellung der Zerstörung nur auf dem Clienten
}
[ClientRpc]
void RpcHit()
{
// Grafische Darstellung eines Treffers nur auf dem Clienten
}
|
Alle Einheiten in meinem Spiel haben also eine gewisse Anzahl an Leben und wenn dieses auf bzw. unter 0 fällt wird die Einheit nach einer bestimmten Zeit respawned. Dazu muss in der Start() Methode das maximale Leben abgespeichert werden.
Jetzt möchte ich die Einheit etwas weiter konkretisieren und erstelle ein Enemy. Der Gegner benötigt jetzt weitere Komponenten in seinem Script, die also in der Start Methode via GetComponent geholt werden müssen.
|
C#-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
|
public class NetworkEnemy : NetworkUnit
{
// Components
ComponentType component1;
...
void Start()
{
// GetComponent ...
}
}
|
So... Sowohl NetworkEnemy, also auch NetworkUnit benutzen die Start-Methode um Zeug zu initialisieren. Wie stelle ich jetzt also sicher, dass beide Start() aufgerufen werden?
Das Problem lässt sich auch auf Update, Awake etc. übertragen. Sagen wir das NetworkUnit bewegt sich jeden Frame und im NetworkEnemy möchte ich zusätzlich jeden Frame die Farbe wechseln (whatever).
Ich denke das Problem sollte klar sein.
Scheinbar ist "new" nicht richtig... eure vorherigen Posts bezüglich Update kann ich leider nicht nachvollziehen.