Recreating Space Invaders for my University project, need help with enemies shooting randomly.

So i am recreating space invaders as part of my University project. I have the player firing but now i want to reuse the same script for the enemies. I have it all figured out pretty much except for replacing firing button with a random timer. Ideally i would want to be able to manipulate the chance any individual enemy will fire until i feel i hit the right amount, not too hard and not too easy to dodge. Here’s the code i have for the player firing.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerShooting : MonoBehaviour
{
    public Transform PlayerGun;
    public GameObject PlayerBullet;


    // Update is called once per frame
    void Update()
    {
        if(Input.GetButtonDown("Fire1"))
        {
            Shoot();
        }
    }

    void Shoot()
    {
        Instantiate(PlayerBullet, PlayerGun.position, PlayerGun.rotation);
    }
}

Additionally i have a bit of a problem, if anyone can figure it out. My bullet entity is supposed to self destruct upon hitting the first enemy but instead it keeps going trough all 3 rows. Here’s the bullet code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour
{
    public float speed = 20f;
    public Rigidbody2D rb;
    public int damage = 1;


    // Start is called before the first frame update
    void Start()
    {
        rb.velocity = transform.up * speed;
    }

    void OnTriggerEnter2D(Collider2D hitInfo)
    {
        EnemyDestroy enemyDestroy = hitInfo.GetComponent<EnemyDestroy>();
        if (enemyDestroy != null)
        {
            enemyDestroy.TakeDamage(damage);
        }


        Destroy(gameObject);
    }
}

And here’s the code for the enemies when they self destruct upon being hit:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyDestroy : MonoBehaviour
{
    public int health = 1;

    public GameObject deathEffect;

    public void TakeDamage (int damage)
    {
        health -= damage;
        if (health <= 0)
        {
            Die();
        }
    }

    void Die()
    {
        Instantiate(deathEffect, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }
}

I really can’t figure out why enemies get destroyed but bullets don’t.

Thanks in advance.

Hello!

My first suggestion would be to check if damage is being applied using a debug log or by debugging the instance in visual studio, this could help figure out the problem.

Another thing I see that I often confused myself early on in my experience is the use of the OnTriggerEnter2D method. If the project uses 3D colliders or you don’t have “isTrigger” selected for one of the objects, this method won’t be called.

There is a collision action matrix in the documentation: Unity - Manual: Colliders (unity3d.com) that goes over which method is called when. The documentation also explores the collision types and in which situation to use them.

Depending on your projects setup you will likely need to use OnCollisionEnter(Collider other); to detect collision from one physics object to another in 3D space.

Maybe some more context from the project could help figure out the core issue, otherwise I hope the above explanation can help you!

Smart! This will teach you all the fundamentals of inter-object interactions (collisions, spawns, etc.) as well as simple rule-based enemy motions.

Parameters for this that might change during the course of the game:

  • maximum allowable number of bombs falling from the enemies at any given moment (don’t drop any more beyond this)

  • speed of their falling

  • percent chance of a bomb being dropped very close to where the player is

I also like to stagger enemy fire slightly by a global counter, so that two bombs won’t drop closer than say 0.25s apart. This is just a regular old cooldown timer.

Cooldown timers, gun bullet intervals, shot spacing, rate of fire:

https://discussions.unity.com/t/821482/2

GunHeat (gunheat) spawning shooting rate of fire:

https://discussions.unity.com/t/824570/2

Staring at code isn’t super-useful. You must find a way to understand what the code is doing, essentially get the information you need in order to reason about what the problem is.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

1 Like

Thanks i will try that. Will ask followup questions if i have any more issues.

EDIT: Ok, so my project is 2d and i do have circle colliders on my bullet and all my NPCs. NPCs get destroyed upon collision so the colision is definitely getting detected, it’s just that the bullet itself keeps ploughing trough the whole row, instead of being deleted. If you require any more context i will be happy to provide it. There are 3 rows of 7 fighters, which are all just 2d square sprites right now with circle colliders. Each fighter moves between 2 points which makes for uniform movement. Both fighters and the player have scripts for movement but i can’t imagine those affecting the bullet in any way. The bullet itself is a prefab. If you need any more context just ask.

1 Like

Thanks, this is a bit too complex for this stage. This is supposed to just be a rough prototype. I just want to replace trigger firing with a script that fires randomly every few seconds. Like every fighter has a 20% chance to fire every 2 seconds, that would be ideal.

Okay, a couple of thoughts.

Is the component on the root game object of the bullet? Can you check if the Destroy(gameObject) line is being called?

Maybe with those questions answered I can help more, but there doesn’t seem to be anything inherently wrong with your code. So as per the questions above, maybe the prefab structure is off, or you could try DestroyImmediately() but that can be really dangerous because it can delete assets, so use it with caution.

Well i added debug log to the code, here’s new code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour
{
    public float speed = 20f;
    public Rigidbody2D rb;
    public int damage = 1;


    // Start is called before the first frame update
    void Start()
    {
        rb.velocity = transform.up * speed;
    }

    void OnTriggerEnter2D(Collider2D hitInfo)
    {
        EnemyDestroy enemyDestroy = hitInfo.GetComponent<EnemyDestroy>();
        if (enemyDestroy != null)
        {
            enemyDestroy.TakeDamage(damage);
        }


        Destroy(gameObject);
        Debug.Log("hit");
    }
}

It seems it’s getting called, here’s a screenshot

https://ibb.co/pwtQ9MJ

Sorry i could not embed that, here are a few other screenshots, i screenshotted the bullet prefab:

https://ibb.co/2sh9Gbx

And the standard enemy:

https://ibb.co/hCYsNPs

Hope that helps.

Okay, it was a good thing to make sure, can you check the prefab hierarchy by opening up the bullet prefab and taking a screenshot, I think you should check which game object the bullet component is attached to.

Second screenshot.

Interesting, I don’t see what could cause that. If they are colliding then that should run. Could you check if the OnDestroy callback is called? If it is, you may have multiple bullets being instantiated or a bullet instantiating in the destroyed bullets position.

Maybe check that your reference to the deathEffect in the enemy script isn’t referencing the bullet by accident, that would definitely cause the issue.

1 Like

What should the death effect be referencing instead?

Not another bullet, I’m not sure what you have in the inspector, can’t tell from the screenshot.

I tried to leave that empty. but then nothing happens.

Sorry, then nothing happens? What is expected to happen, what behaviour are you looking for?

NVM, that was the issue, i added something into enemy death effect and now it works fine, still would like to reuse the script with the AI, with that random timer, if you know how i could do that,

Yeah definitely. There is a really good example in the docs: Unity - Scripting API: Time.deltaTime (unity3d.com)

I couldn’t put it any better myself than the example they give. Basically having a total time for how long you want between each time it fires and a timer variable which is increased by time.deltaTime every Update.

1 Like

Cool… without even reading any of the intervening stuff above, this can easily be accomplished with a timer and a check:

private float fireYet;

In Update for firing:

fireYet += Time.deltaTime;

if (fireYet >= 2.0f)
{
  fireYet = 0.0f;  // reset timer

  // chance of firing?
  if (Random.value < 0.20f)
  {
    // TODO: do firing here
  }
}

Keep it simple!

1 Like

Thanks.