SUPER WEIRD BUG: Breakable Drops Multiple Items if Hit by Multiple Bullets
I am currently developing a 2D rogue-like game and in it I have some breakable objects that drop items when they are broken (either shot or dashed into). The dropping works perfectly fine in all but one scenario. I recently implemented a "shotgun" type weapon which shoots multiple pellets as opposed to one bullet/projectile. When using all the other weapons and when dashing through the crates, they drop only one item (as is coded to do), but for some reason if I am using the shotgun and multiple pellets hit the collider very close together, the crate will drop an item for each bullet that hits. The "BreakableObjects" code is attached to the crate itself and is what handles the dropping. I have it set to instantiate a single random item from a list upon being destroyed (code shown below). Because the box is handling to drop an item when it comes into contact with a bullet, I guess it isn't able to process that it has already been destroyed and is dropping the items until it gets destroyed? Which I don't understand because the first thing "Smash" does is to destroy the object (crate in this case). Not really sure. If someone could help me out, that would be great. I am fairly new to coding and C# and don't really know more advanced functions (or even the beginner ones haha).
This checks the collision then runs the "Smash" function:
private void OnTriggerEnter2D(Collider2D other) { if(other.tag == "PlayerBullets") { Smash(); } }
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.tag == "Player")
{
if (PlayerController.instance.dashCounter > 0)
{
Smash();
}
}
if (other.gameObject.tag == "PlayerBullets")
{
Smash();
}
}
This is the "Smash function:
public void Smash() { Destroy(gameObject); AudioManager.instance.PlaySFX(breakSound);
//show broken pieces
int piecesToDrop = Random.Range(1, maxPieces);
for (int i = 0; i < piecesToDrop; i++)
{
int randomPiece = Random.Range(0, brokenPieces.Length);
Instantiate(brokenPieces[randomPiece], transform.position, transform.rotation);
}
//drop items
if (shouldDropItem)
{
float dropChance = Random.Range(0f, 100f);
float dropXOffset = Random.Range(-0.2f, 0.2f);
float dropYOffset = Random.Range(-0.2f, 0.2f);
float dropRotOffset = Random.Range(-45f, 45f);
if (dropChance <= itemDropPercent)
{
int randomItem = Random.Range(0, itemsToDrop.Length);
if (randomItem == 0 || randomItem == 1 || randomItem == 21 || randomItem == 22 || randomItem == 23 || randomItem == 24) //certain items I don't want rotation offset on
{
Instantiate(itemsToDrop[randomItem], transform.position, transform.rotation);
}
else
{
Instantiate(itemsToDrop[randomItem], new Vector3(transform.position.x + dropXOffset, transform.position.y + dropYOffset, transform.position.z), Quaternion.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z + dropRotOffset));
}
}
}
}
Having the same issue. Have you figured it out yet, @PilgrimFlowers ?
Answer by streeetwalker · Sep 19, 2020 at 06:51 AM
Destroy doesn't destroy the object and it's scripts until the next frame. Anything that hits your breakable in the same frame is going to run your code.
If you want to ensure that the breakable can only generate one drop, probably the most efficient way is to put a class boolean variable into into the class that contains your onCollisionEnter code (that is, at the top of the class, outside of any function ) and then check and set it inside onCollisonEnter, or where ever else you do smash.
//For example
private bool isSmashed = false;
private void OnCollisionEnter2D(Collision2D other) {
if( ! isSmashed ) {
if (other.gameObject.tag == "Player") {
if (PlayerController.instance.dashCounter > 0) {
Smash();
isSmashed = true;
}
}else if (other.gameObject.tag == "PlayerBullets") {
Smash();
isSmashed = true;
}
}
}
Answer by whysoserious206 · Sep 19, 2020 at 03:57 AM
Having the same issue. Have you figured it out yet, @PilgrimFlowers ?
Answer by PilgrimFlowers · Dec 22, 2020 at 11:21 PM
Hey everyone,
Thanks for the replies and the help! I didn't see this until now (kinda stopped developing for a little while), but that's actually exactly what I ended up doing anyway. Haha. So yes! That works. Thanks!
Your answer
Follow this Question
Related Questions
2D Diffuse Lighting Not Working as Advertised 1 Answer
One script stopped working after update 0 Answers
Problem with sibling hierarchy in inventory sytem 0 Answers
Unity graphic bug ? 0 Answers
Zelda-like inventory system 0 Answers