|
Post by baroquedub on May 5, 2017 22:40:02 GMT
I have an Enemy prefab spawned by PoolBoss which has a Killable script on it. I'd like to call a method when it dies (i.e when hitpoints get to zero, get a reference to the Killable gameObject then do GetComponent<myAiScript>().DoDeath()) - the idea is for this method to change the mecanim animation to a death clip, stop NavMesh movement and do other game related things. Using a modified version of this script [http://darktonic.freeforums.net/thread/481/kilable-custom-events] I can call a Custom Event on death which would do the trick *except* that the option of having a Death Event is only available if a Death Prefab is defined. I could spawn a death prefab that had the death anim on it, but I'd rather not have to. Am I missing something? Is there a better way of doing what I'm after? I'm no expert but could you not have an option in Death Prefab Settings & Events that simply was a SendMessage option to send a method call to the prefab that has the Killable script on it? ps. Could you do some tutorials (either video or text) on setting up and using Custom Events and Listeners, and getting different part of CGK talking to different game objects and components in a game. e.g. real-world examples of when you'd use a custom event and listeners and the kind of functionality they bring when developing a game. Thanks, as always.
|
|
|
Post by DarkTonic Dev on May 6, 2017 2:05:04 GMT
You can do this either by making a subclass of Killable and using that instead of Killable. Or easier, make a subclass of KillableListener and add code to the appropriate event (something with Destroy in the name). Nothing sends messages except for PoolBoss.
We have it on the roadmap to make generic Listeners that can do stuff like fire custom events, go to next wave etc.
I believe you need to assign "death delay" to the Killable as well so it doesn't despawn the instant it "dies". If it did you wouldn't see the animation.
|
|
|
Post by baroquedub on May 7, 2017 21:46:44 GMT
Thanks, I'd forgotten about overriding the KillableListener class, which I remember now you've provided a sample for.
As you suggested I had to use the death delay to allow enough time for the death animation to show. That's ok. But I couldn't find any of the listeners that fire just as the hit points reach zero and the death 'countdown' is triggered.
So this is what I have:
public class KillableListenerAssaultTroop : KillableListener {
// if you need more than one Listener for of each type (KillableListener etc), create subclasses like this, inheriting from KillableListener
private EnemyAttackSimpleAI aiScript;
private Killable killableScript;
void Awake(){
aiScript = this.gameObject.GetComponent<EnemyAttackSimpleAI>();
killableScript = this.gameObject.GetComponent<Killable>();
}
public override void Despawning(TriggeredSpawner.EventType eType) {
base.Despawning(eType);
// your code here.
}
public override void TakingDamage(int pointsDamage, Killable enemyHitBy) {
base.TakingDamage(pointsDamage, enemyHitBy);
int hitpointsLeft = killableScript.currentHitPoints;
Debug.Log(this.sourceKillableName+" taking "+pointsDamage+" points damage. "+hitpointsLeft+" left");
if(hitpointsLeft<=0){
Debug.Log("waiting to despawn");
aiScript.DoDeath();
}
}
public override void DamagePrefabSpawned(Transform damagePrefab) {
base.DamagePrefabSpawned(damagePrefab);
// your code here.
}
public override void DamagePrefabFailedToSpawn(Transform damagePrefab) {
base.DamagePrefabFailedToSpawn(damagePrefab);
// your code here.
}
public override void DeathPrefabSpawned(Transform deathPrefab) {
base.DeathPrefabSpawned(deathPrefab);
// your code here.
Debug.Log("Death prefab spawned for " + this.sourceKillableName);
}
public override void DeathPrefabFailedToSpawn(Transform deathPrefab) {
base.DeathPrefabFailedToSpawn(deathPrefab);
// your code here.
}
public override void ModifyingDeathWorldVariables(List<WorldVariableModifier> variableModifiers) {
base.ModifyingDeathWorldVariables(variableModifiers);
// your code here.
Debug.Log("Modifying world variations for " + this.sourceKillableName + " destruction");
}
} Can I ask, is there a better way to find out if the death delay has started? I can see the DeathDelayStarted() method in the API but can't work out a way of using it in this context.
And is there a better way of getting a reference to the Killable script from this subclass?
Also, newbie c# question... do I need to include all of the overriden methods in my subclass? Or can I just reduce it down to the ones I'm actually overriding?
|
|
|
Post by DarkTonic Dev on May 8, 2017 1:15:56 GMT
No you don't need to include any of the methods you aren't overriding, since it's a base class.
You should be using the method "WaitingToDestroyKillable" since you have Death Delay > 0. That will get called exactly when the Killable first takes lethal damage and the death delay starts. Play the animation there. Don't use TakingDamage as that's a very complex method with code for invincibility, negative damage and other stuff too.
Also, the dead Killable is passed into that method (and a lot of the Listener methods), so just use it. No need to add Awake code to get the component.
Looks like DeathDelayStarted is also in the Listener but it doesn't pass in the Killable, otherwise pretty much identical and not sure why I have both right now. But use the other one.
|
|
|
Post by baroquedub on May 9, 2017 21:05:44 GMT
Really helpful and informative, as always. Thank you!
So for anyone interested,... the working code is a rather more sensible:
using System.Collections.Generic; using DarkTonic.CoreGameKit; using UnityEngine;
public class KillableListenerAssaultTroop : KillableListener {
public override void WaitingToDestroyKillable (Killable deadKillable) { base.WaitingToDestroyKillable (deadKillable); deadKillable.gameObject.GetComponent<EnemyAttackSimpleAI>().DoDeath();
} }
|
|
|
Post by DarkTonic Dev on May 9, 2017 21:07:14 GMT
Looks good!
|
|
|
Post by baroquedub on May 9, 2017 23:32:38 GMT
Sorry to bother you again... Which method or settings should I use if I don't want the gameObject with the Killable on it to be destroyed (or despawned, as it's not in the Pool) but I still want to call a method on it? I've set the HP Death Mode in Despawn & Death Triggers to None - so that the component doesn't try to despawn a non-pooled object, but I can't see anything in the inspector that allows me to trigger something else on zero hit points being reached. So I'm looking again at making a subclass of KillableListener but can't see an obvious method to use. I can do this: public class KillableListenerCannon : KillableListener {
private AutoAimingCannonFull aiScript;
private Killable killableScript;
void Awake(){
aiScript = this.gameObject.GetComponent<AutoAimingCannonFull>();
killableScript = this.gameObject.GetComponent<Killable>();
}
public override void TakingDamage(int pointsDamage, Killable enemyHitBy) {
base.TakingDamage(pointsDamage, enemyHitBy);
int hitpointsLeft = killableScript.currentHitPoints;
if(hitpointsLeft<=0){
aiScript.DoDeath();
}
}
} Which works and is very similar to what I had before, but you seemed to imply that this was a bad idea because TakingDamage is a very complex method. Also, slightly oddly, here the Killable being passed is a reference to what's hitting the gameObject (it's my player's bullet, not the enemy being killed) Is there a more efficient way of doing this?
|
|
|
Post by DarkTonic Dev on May 9, 2017 23:53:51 GMT
That does work. You may want to hook into an existing event to override just to copy the Killable instance instead of doing GetComponent though. No need for Awake event.
That method is meant for examining the thing that it hitting you mainly.
|
|
|
Post by baroquedub on May 10, 2017 9:08:43 GMT
Could you explain, maybe with a code snippet, how to "hook into an existing event to override just to copy the Killable instance"? Sorry, I don't really understand As I mentioned in my initial post, it would be brilliant if you did some tutorials (either video or text) on this kind of thing - setting up and using Custom Events and Listeners, i.e. getting different parts of CGK talking to each other and triggering non CGK methods.
|
|
|
Post by DarkTonic Dev on May 10, 2017 19:44:44 GMT
Yeah here's what I'm saying. Delete your Awake method in the Listener and use this instead:
public override void Spawned(Killable newKillable) { killableScript = newKillable; }
This way you can be sure that you've stored the correct thing no matter if your Listener is located on the same Game Object or not.
The Listeners can of course fire any non-CGK code you want, it's not limited in any way.
|
|
|
Post by baroquedub on May 10, 2017 21:09:59 GMT
Ah, clever! Makes sense now. In this instance it doesn't work because my gameObject isn't spawned. That was part of the problem, not being able to hook into a death/despawning event. Thanks again for your patience and continued support. Wish I could give you another 5 stars on the asset store, although I do try to make up for it by recommending your assets whenever I can
|
|
|
Post by DarkTonic Dev on May 10, 2017 22:29:49 GMT
Thanks. I'm going to add another Listener method for Start method so you could use that when something starts ina scene.
|
|