I created 3 powerups for my player and instead of having 3 separate powerups scattered around the map I would like to put them into one gameobject and have it randomly choose one of the three powerups depending on if that powerup is cooldown and if it is not already in use. Here is my PowerUps class:
using UnityEngine;
using System.Collections;
using PlayerInfo;
using EnemyInfo;
using Management;
using UnityEngine.UI;
using Shell;
public class PowerUps : MonoBehaviour
{
public Text PowerUpMessageText;
public float SpeedBonus, SpeedDuration, SpeedCooldown;
public float HealthPercentIncrease, HealthCooldown;
public float DamageMultiplier, DamageDuration, DamageCooldown;
PlayerMovement pMove;
EnemyMovement eMove;
PlayerHealth pHealth;
EnemyHealth eHealth;
PlayerAttack pAttack;
EnemyAttack eAttack;
ShellExplosion peDamage;
float NewCurrentHealth;
static PowerUps instance;
[HideInInspector] public bool isActivable_speed = true;
[HideInInspector] public bool isActivable_health = true;
[HideInInspector] public bool isActivable_damage = true;
void Awake ()
{
instance = this;
}
IEnumerator PowerUpMessage (string message, float Delay)
{
PowerUpMessageText.text = message;
PowerUpMessageText.enabled = true;
yield return new WaitForSeconds (Delay);
PowerUpMessageText.enabled = false;
}
public IEnumerator PlayerSpeedPowerUp()
{
StartCoroutine(PowerUpMessage("SPEED POWERUP ACTIVATED! " + "+" + SpeedBonus + "SPEED FOR " + SpeedDuration + " SECONDS", 4));
isActivable_speed = false;
pMove.Speed += SpeedBonus;
yield return new WaitForSeconds (SpeedDuration);
pMove.Speed -= SpeedBonus;
StartCoroutine (PowerUpMessage("SPEED POWERUP FINISHED! " + SpeedCooldown + " SECOND COOLDOWN", 4));
yield return new WaitForSeconds (SpeedCooldown);
isActivable_speed = true;
}
public IEnumerator PlayerHealthPowerUp()
{
NewCurrentHealth = pHealth.CurrentHealth * HealthPercentIncrease;
StartCoroutine (PowerUpMessage("HEALTH POWERUP USED! " + HealthPercentIncrease + "% MORE HEALTH", 4));
isActivable_health = false;
pHealth.CurrentHealth += NewCurrentHealth;
yield return new WaitForSeconds (HealthCooldown);
isActivable_health = true;
}
public IEnumerator PlayerDamagePowerUp()
{
float NewDamage = peDamage.MaxDamage * DamageMultiplier;
StartCoroutine (PowerUpMessage ("DAMAGE POWERUP ACTIVATED! " + DamageMultiplier + "x HIGHER DAMAGE", 4));
isActivable_damage = false;
peDamage.MaxDamage += NewDamage;
yield return new WaitForSeconds (DamageDuration);
peDamage.MaxDamage -= NewDamage;
StartCoroutine (PowerUpMessage ("DAMAGE POWERUP FINISH! " + DamageCooldown + " SECOND COOLDOWN", 4));
yield return new WaitForSeconds (DamageCooldown);
isActivable_damage = true;
}
}
How could I say when the player goes over the powerup gameobject to choose one of these three powerups. This is difficult to explain but say the player already has the speed powerup and he goes over the gameobject again, then it’ll choose between the health powerup or the damage powerup and it will check if both of those are cooled down and ready to be used, and if so choose one of those, and if not then simply don’t give a powerup. I hope this makes sense. Thank you
I found several errors and bad things after I posted so I edited code. I’m sloppy today)
That’s not best way as it allocates list, but it works. If you need extra-performant code (for 10000+ calls per frame) I could write it, but why?
EDIT: and another error fixed (random should start from 0).
I think using the list you provided should work pretty well. Given the fact that I am only going to call this section of code when the player goes into the powerup collider. Thank you
So after using this and changing the parts to do what I would like it to do, it’s giving me two separate errors. First if I keep the ‘int’ as an ‘int’ the switch (PowerUpsPossible [PowerUpRand]) gives me this error Error CS1502: The best overloaded method match for 'System.Collections.Generic.List<float>.this[int]' has some invalid arguments (CS1502) (Assembly-CSharp) & this Error CS1503: Argument 1: cannot convert from 'float' to 'int' (CS1503) (Assembly-CSharp)
Not sure how to fix this but here is my code for that part of my class:
void OnTriggerEnter (Collider collider)
{
List<int> PowerUpsPossible = new List<int> ();
if (collider.CompareTag("PowerUp") && PowerUp.isActivable_speed == true)
{
PowerUpsPossible.Add (1);
}
if (collider.CompareTag("PowerUp") && PowerUp.isActivable_health == true)
{
PowerUpsPossible.Add (2);
}
if (collider.CompareTag("PowerUp") && PowerUp.isActivable_damage == true)
{
PowerUpsPossible.Add (3);
}
if (PowerUpsPossible.Count == 0)
{
return;
}
int PowerUpRand = Random.Range (0, PowerUpsPossible.Count);
switch (PowerUpsPossible [PowerUpRand])
{
case 1:
StartCoroutine (PowerUp.PlayerSpeedPowerUp);
break;
case 2:
StartCoroutine (PowerUp.PlayerHealthPowerUp);
break;
case 3:
StartCoroutine (PowerUp.PlayerDamagePowerUp);
break;
}
}
According to those errors it… It somehow treats List as List which is… absurd. Such cast should not be possible at all. And there’s no such cast anywhere in code you posted. Also it somehow treats PowerUpRand as float even though it’s explicitly stated that it’s int…
Only problem I see is that you’re doing StartCoroutine(PowerUp.PlayerSpeedPowerUp); while it should be StartCoroutine(PowerUp.PlayerSpeedPowerUp()); (a call of method is missing - the () brackets).
For me it compiles fine however… My minimal code that compiles looks like this:
Some useless code
//File name Dbg.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
class PowerUpClass //Just declarations here
{
public bool isActivable_speed;
public bool isActivable_health;
public bool isActivable_damage;
public IEnumerator PlayerSpeedPowerUp() { yield return null; }
public IEnumerator PlayerHealthPowerUp() { yield return null; }
public IEnumerator PlayerDamagePowerUp() { yield return null; }
}
public class Dbg : MonoBehaviour {
PowerUpClass PowerUp;//An object of PowerUpClass that will be used
void OnTriggerEnter(Collider collider)//My VS2015 and Unity say it compiles fine!
{
List<int> PowerUpsPossible = new List<int>();
if (collider.CompareTag("PowerUp") && PowerUp.isActivable_speed == true)
{
PowerUpsPossible.Add(1);
}
if (collider.CompareTag("PowerUp") && PowerUp.isActivable_health == true)
{
PowerUpsPossible.Add(2);
}
if (collider.CompareTag("PowerUp") && PowerUp.isActivable_damage == true)
{
PowerUpsPossible.Add(3);
}
if (PowerUpsPossible.Count == 0)
{
return;
}
int PowerUpRand = Random.Range(0, PowerUpsPossible.Count);
switch (PowerUpsPossible[PowerUpRand])
{
case 1:
StartCoroutine(PowerUp.PlayerSpeedPowerUp());
break;
case 2:
StartCoroutine(PowerUp.PlayerHealthPowerUp());
break;
case 3:
StartCoroutine(PowerUp.PlayerDamagePowerUp());
break;
}
}
}
I don’t know what’s wrong there but those errors are… Absurd because code and errors don’t correspond at all. Are you sure you saved code?
Best way to know what happens… Place Debug.Log(…) everywhere.
From what I see only problem that might happen in this code is that PowerUpsPossible.Count==0 might always trigger from external conditions not described in this code meaning it will always think all powerups are on cooldown and do nothing.