0
\$\begingroup\$

I am trying to have a single class that handles multiple powerups types and using enum for the types of power-ups and switching the powers based on enum however when there are multiple power-ups in the scene then the collision only registers only for the last powerup in the scene and gives all the powers associated with the not collision registered when collides with last powerup in scene,
Here is the powerup class and enum:

using UnityEngine;

[System.Serializable]

public class PowerUp
{
    public PowersList ListofPowers;
    public string NameofPowerup;
    public GameObject PowerUpItem;
    [Tooltip("Time")]
    public float powerOfftime;
    public bool isTrigger = true;
    [Tooltip("Modifier")]
    public float powerInfluencer;
}
public enum PowersList
{
    Move, Jump, Shoot,None
}

Here is the Script for managing powerup class :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PowerManager : MonoBehaviour
{
    public List<PowerUp> power;
    private Collider2D playerCollider;
    private Collider2D objCollider;
    PlayerController player;
    private float Time;
    private float powerupInfluencer;
    int index;
    private void Awake()
    {
    }
    private void Start()
    {
        InintalizeComponents();
    }
    private void Update()
    {
        TriggerPower();
    }
    private void InintalizeComponents()
    {
        player = GetComponent<PlayerController>();
        playerCollider = player.GetComponent<CapsuleCollider2D>();
        foreach (PowerUp u in power)
        {
            u.NameofPowerup = u.ListofPowers.ToString();
            powerupInfluencer = u.powerInfluencer;
            if (u.PowerUpItem.GetComponent<BoxCollider2D>() == null) u.PowerUpItem.AddComponent<BoxCollider2D>();
            objCollider = u.PowerUpItem.GetComponent<BoxCollider2D>();
            u.isTrigger = objCollider.isTrigger;
            Time = u.powerOfftime;
        }
    }
    private void TriggerPower()
    {
        if (!Touching()) return;
        if (Touching())
        {
            StartCoroutine(GivePower());
        }
    }
    private bool Touching()
    {
        foreach (PowerUp p in power)
        {
            if (!objCollider) return false;
            if (playerCollider.IsTouching(objCollider)) return true;
        }
        return false;
    }
    private IEnumerator GivePower()
    {
        StartPower();
        yield return new WaitForSeconds(Time);
        EndPower();
    }
    private void StartPower()
    {
        foreach (PowerUp p in power)
        {
            SwitchPower(p.ListofPowers);
            Destroy(p.PowerUpItem);
            Debug.Log("PowerStarted");
        }
    }
    private void EndPower()
    {
        SwitchPower(PowersList.None);
        Debug.Log("PowerEnded");
    }
    private void SwitchPower(PowersList list)
    {
        foreach (PowerUp p in power)
        {
            switch (list)
            {
                case PowersList.Move:
                    player.moveSpeed = powerupInfluencer;
                    break;
                case PowersList.Jump:
                    player.jumpSpeed = powerupInfluencer;
                    break;
                case PowersList.None:
                    player.jumpSpeed = 8; player.moveSpeed = 6;
                    break;
                case PowersList.Shoot:
                    player.deservedAmmo += Mathf.RoundToInt(powerupInfluencer);
                    break;
                default:
                    player.moveSpeed = 6; player.jumpSpeed = 8;
                    break;
            }
        }
    }
}

Please help I am searching for an answer about the week, Thanks in advance. and please suggest is there a better way to do this.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

In your StartPower function you are just looping the list of powerups so when you call SwitchPower and Destroy it will affect all elements in the list. The reason you are seeing an effect only for last power up is that it is the last one in the list. You should change your StartPower function to take a type of powerup as parameter (like StartPower(PowersList typeOfPowerUp) ) and drop the foreach loop because you don't need it there. So when you call that function, you pass it the right type of powerup.

First, you need some way to know which powerup you are colliding with. There are multiple ways to do this: you could use tags or have some variable that identify the powerup. If you are attaching the powerup script to different game objects that you instantiate and you don't have a lot of powerups, the easiest way would be using tags and checking them on collision.

If you have one game object that changes its data based on some type variable Like your PowersList then you can check the set type on collision.

That are some approaches that I suggest: instead of using for loop for check all the powerups like you did, you could get the information of the powerup in the OnTriggerenter function.

Let's return to your specific problem of getting the last element. As I said, you are getting last element because you don't specify what powerup you want in your StartPower function. You are just looping them all and applying the same function on all of them. If you insist on using a foreach loop here, you should do something like this:

private void StartPower(PowersList typeOfPowerUp)
{
    foreach (PowerUp p in power)
    {
        if(p.ListofPowers == typeOfPowerUp)
        {
          SwitchPower(p.ListofPowers);
          Destroy(p.PowerUpItem);
          Debug.Log("PowerStarted");
        }
    }

That should apply the functions on only the chosen powerup.

\$\endgroup\$
5
  • \$\begingroup\$ can you eloborate cause i dont really get it \$\endgroup\$ Commented Sep 29, 2021 at 12:47
  • \$\begingroup\$ Taking another look at your code I can see you are using foreach loop in wrong place in a lot of places so I will edit my question whit an better explanation how to approach this. \$\endgroup\$
    – Ivan
    Commented Sep 29, 2021 at 13:02
  • \$\begingroup\$ thanks man but where am i wrongly using foreach loops \$\endgroup\$ Commented Sep 29, 2021 at 13:04
  • \$\begingroup\$ I try to explain it in an edit. I would suggest you take a look at some tutorials about powerUps to get an idea of different approaches. \$\endgroup\$
    – Ivan
    Commented Sep 29, 2021 at 14:08
  • \$\begingroup\$ Thanks man it worked \$\endgroup\$ Commented Sep 29, 2021 at 14:13
1
\$\begingroup\$

If I was implementing something like this I would probably use inheritance. I would have a base class Power that contains all the methods you need and abstract/virtual methods for applying the power. Each powerup could then be its own class that overrides the virtual apply power method and the rest of the powerup is managed by your base class.

\$\endgroup\$
3
  • \$\begingroup\$ But, I am trying to do it in the least hard work way possible by using list, can you see the list of powerups \$\endgroup\$ Commented Sep 29, 2021 at 11:06
  • \$\begingroup\$ With the inheritance approach you wouldn't have a list of powerups but you also wouldn't really need one. \$\endgroup\$
    – Vhagar
    Commented Sep 29, 2021 at 13:21
  • \$\begingroup\$ i want to use the list \$\endgroup\$ Commented Sep 29, 2021 at 13:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .