How Do I Instantiate Multiple Coins Once The Enemy Dies?
I am making a 2D Platformer and I am trying to make it so when the enemy dies he will drop 3-5 coins. Can someone help me @numberkruncher?
Answer by numberkruncher · Jun 17, 2017 at 08:18 PM
You could have a CoinRewarder
component that looking something like this:
// CoinRewarder.cs
// Attach this to any game object that can reward coins for whatever reason
// (be it an enemy kill reward, collectable coin, gold, etc).
public sealed class CoinRewarder : MonoBehaviour
{
[SerializeField]
private int minimumCoinReward = 3;
[SerializeField]
private int maximumCoinReward = 5;
public int MinimumCoinReward {
get { return this.minimumCoinReward; }
set { this.minimumCoinReward = value; }
}
public int MaximumCoinReward {
get { return this.maximumCoinReward; }
set { this.maximumCoinReward = value; }
}
public void Reward()
{
// Randomly pick a coin reward within the given range.
int coins = Random.Range(this.MinimumCoinReward, this.MaximumCoinReward);
// Reward coins using the game manager.
GameManager.Instance.RewardCoins(coins);
}
}
Alternatively if you want to spawn instances of a coin prefab:
// PrefabSpawner.cs
// Attach this to any game object that can spawn prefabs for whatever reason
// (be it coins, gold, explosion particles, etc.).
public sealed class PrefabSpawner : MonoBehaviour
{
[SerializeField]
private int minimumCount = 3;
[SerializeField]
private int maximumCount = 5;
[SerializeField]
private GameObject prefab = null;
public int MinimumCount {
get { return this.minimumCount; }
set { this.minimumCount= value; }
}
public int MaximumCount {
get { return this.maximumCount ; }
set { this.maximumCount = value; }
}
public GameObject Prefab{
get { return this.prefab; }
set { this.prefab= value; }
}
public void Spawn()
{
// Randomly pick the count of prefabs to spawn.
int count = Random.Range(this.MinimumCount, this.MaximumCount );
// Spawn them!
for (int i = 0; i < count; ++i) {
Instantiate(this.prefab, this.transform.position, Quaternion.identity);
}
}
}
The above obviously needs to be activated somehow; here is how you could allow for this to be wired up:
// IDamagable.cs
// The interface for something that can take damage.
public interface IDamagable
{
void TakeDamage(float damage, Object instigator);
}
// HealthComponent.cs
// Attach this to any character that has health and can die
// (be it player or enemy or a destructible chest)
public sealed class HealthComponent : MonoBehaviour, IDamagable
{
[SerializeField]
private float initialHealth = 100f;
[SerializeField]
private float initialMaximumHealth = 100f;
[SerializeField]
private UnityEvent onDied;
private float health;
private float maximumHealth;
public float InitialHealth {
get { return this.initialHealth; }
set { this.initialHealth = Mathf.Max(0f, value); }
}
public float InitialMaximumHealth {
get { return this.initialMaximumHealth; }
set { this.initialMaximumHealth = Mathf.Max(0f, value); }
}
public float Health {
get { return this.health; }
set { this.health = Mathf.Clamp(value, 0f, this.MaximumHealth); }
}
public float MaximumHealth {
get { return this.maximumHealth; }
set { this.maximumHealth = Mathf.Max(0f, value); }
}
public UnityEvent DiedEvent {
get { return this.onDied; }
}
private void OnEnable()
{
this.Health = this.InitialHealth;
this.MaximumHealth = this.InitialMaximumHealth;
}
private void OnDiedEvent()
{
var handler = this.onDied;
if (handler != null) {
handler.Invoke();
}
}
public void TakeDamage(float damage, Object instigator)
{
this.Health -= damage;
// Has the player just died?
if (Mathf.Approximately(this.Health, 0f)) {
this.OnDiedEvent();
}
}
}
So, how can these two components play nice together? Easy, there are a whole number of ways, but to keep things simple, here are two ways:
You can wire them up using the inspector.
You can wire them up using another script (for example, an EnemyController component).
// EnemyController.cs public class EnemyController : MonoBehaviour { protected HealthComponent healthComponent; protected virtual void OnEnable() { this.healthComponent = this.GetComponent<HealthComponent>(); this.healthComponent.DiedEvent.AddListener(this.OnDied); } protected virtual void OnDied() { var coinRewarder = this.GetComponent<CoinRewarder>(); if (coinRewarder != null) { coinRewarder.RewardCoins(); } } }
And as for the enemy taking damage:
// Projectile.cs
public class Projectile : MonoBehaviour
{
[SerializeField]
private float damage = 10f;
public float Damage {
get { return this.damage; }
set { this.damage = value; }
}
private void OnCollisionEnter(Collision collision)
{
var damagable = collision.gameObject.GetComponent<IDamagable>();
if (damagable != null) {
damagable.TakeDamage(this.Damage, this);
}
Destroy(this.gameObject);
}
}
I hope that you find this helpful!
Your answer
Follow this Question
Related Questions
Generating random points and instantiating prefabs with a set distance 0 Answers
Having trouble instantiating prefabs in my 2D game 1 Answer
Instantiate And move the GameObject to the click position from another position. 1 Answer
Multiple different bullet damages for multiple enemies 1 Answer
Less code for same thing 1 Answer