0
\$\begingroup\$

This is for a simple sidescrolling game. I want to have it so that when an enemy is killed, it has a chance of dropping a health collectible for the player. I wrote a separate simple bool method RollForCollectible() that does a call to Random.Range(0, 1) that returns true if the value is above 0.75 (so about 25% of the time).

When I instantiate the prefab WITHOUT using RollForCollectible(), it works as expected and spawns the health collectible at the desired location. When I change nothing else except adding in that call to RollForCollectible, it will spawn empty game objects (Titled "New Game Object" with no properties or components) instead of health collectibles.

This is the code that "works":

   private void DropLootAndReward()
   {
       ScoreController.ChangeScore(scoreDelta);

           GameObject collectible = EnemyStateController.Instantiate(enemyStateController.collectibleDrop, enemyStateController.transform.position, Quaternion.identity);
           collectible.transform.SetParent(GameObject.Find("Collectibles").transform);
           collectible.GetComponent<HealthCollectibleController>().SetScore(-scoreDelta * 2);
       
       DeathExplosion();

       if (enemyStateController.finalBoss)
       {
           splashAnimator.SetTrigger("Victory");
           player.ChangeState(player.victoryState);
           player.canGetScore = false;
       }
   }

   private bool RollForCollectible()
   {
       if (Random.Range(0, 1) >= 0.75f)
       {
           return true;
       }

       retu

rn false; }

I set the parent to null so that the prefab isn't destroyed along with the enemy. But this code spawns a collectible every single time an enemy dies.

This is the code that only instantiates empty game objects:

   private void DropLootAndReward()
   {
       ScoreController.ChangeScore(scoreDelta);

       if (RollForCollectible() == true)
       {
           GameObject collectible = EnemyStateController.Instantiate(enemyStateController.collectibleDrop, enemyStateController.transform.position, Quaternion.identity);
           collectible.transform.SetParent(GameObject.Find("Collectibles").transform);
           collectible.GetComponent<HealthCollectibleController>().SetScore(-scoreDelta * 2);
       }
       
       DeathExplosion();

       if (enemyStateController.finalBoss)
       {
           splashAnimator.SetTrigger("Victory");
           player.ChangeState(player.victoryState);
           player.canGetScore = false;
       }
   }

   private bool RollForCollectible()
   {
       if (Random.Range(0, 1) >= 0.75f)
       {
           return true;
       }

       return false;
   }

There are no other changes between those two screenshots anywhere in the project or editor.

At first I thought Random.Range() could be an IEnumerator or otherwise acting on a separate thread and thus not returning until after the enemy was already Destroyed, so I tried doing the call to Random.Range() when the enemy first activates instead of when it dies, but the behavior was exactly the same.

I've also tried creating the "GameObject collectible" variable outside of the if() block, but that also had no effect on this behavior.

\$\endgroup\$
8
  • \$\begingroup\$ I think you're calling the int overload of Random.Range(), so you'll always get 0 and your method will always return false. Not sure if that resolves the full problem. \$\endgroup\$ Commented May 17 at 11:29
  • \$\begingroup\$ Thank you for the answer, but the actual random functionality seems to be working properly. It does return true about 25% of the time. The gameobject that gets spawned when it returns true is simply empty. Nevertheless, I'm gonna look into this avenue because I hadn't considered possible overloads. \$\endgroup\$
    – Dan Shaw
    Commented May 17 at 11:34
  • \$\begingroup\$ Okay, interestingly enough this did... half fix my problem. I changed Random.Range(0, 1) to Random.Range(0f, 1f) and the enemy is properly spawning the collectibles 25% of the time. They are, however, still spawning Empty Game Objects about 25% of the time too (not the same 25% chance either. Sometimes an empty game object spawns, and sometimes a health collectible spawns) Either way, this gives me a much better direction to look in and is probably something I can track down on my own now \$\endgroup\$
    – Dan Shaw
    Commented May 17 at 11:53
  • \$\begingroup\$ I'm not sure if I can accept your answer from a comment but if you post it as an Answer I'd be happy to mark it as such. \$\endgroup\$
    – Dan Shaw
    Commented May 17 at 12:01
  • \$\begingroup\$ @DanShaw I'll post it as an answer, but give it a little time - someone might be able to resolve your entire problem. \$\endgroup\$ Commented May 17 at 12:17

1 Answer 1

2
\$\begingroup\$

One of the issues with the code is the call to Random.Range(0, 1) - this is always going to return zero, as you're calling the integer overload of the method:

public static int Range(int minInclusive, int maxExclusive);

The documentation says that this method only returns integers, and as the maxExclusive bound is exclusive, the only integer that can possibly fall in that range is zero. To resolve that, provide at least of the parameters as a float, so that the proper overload is called:

if (Random.Range(0f, 1f) >= 0.75f)
{
  //...
}
\$\endgroup\$

You must log in to answer this question.

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