Enemy Shooting

I’m sorry but there is no sound in the video I need to upgrade the software. I’m currently trying to get the player health bar to decrease when the enemy shoots and hits the player I believe I need to link the player controller with the player health script. How can I link the player health with the player controller script? I would appreciate any feedback :wink:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

public class PlayerController : MonoBehaviour
{
    [Header("General")]
    [Tooltip("In ms^-1")] [SerializeField] float controlSpeed = 24f;
    [Tooltip("In m")] [SerializeField] float xRange = 6f;
    [Tooltip("In m")] [SerializeField] float yRange = 4f;
    [SerializeField] GameObject[] guns;

    [Header("Screen-position Based")]
    [SerializeField] float positionPitchFactor = -5f;
    [SerializeField] float positionYawFactor = 5f;

    [Header("Control-throw Based")]
    [SerializeField] float controlPitchFactor = -20f;
    [SerializeField] float controlRollFactor = -20f;

    float xThrow, yThrow;
    bool isControlEnabled = true;
    private bool landed = true;
    private GameController gameController;


    private void Start()
    {
        gameController = FindObjectOfType<GameController>();
    }

    // Update is called once per frame
    void Update()
    {
        if (isControlEnabled)
        {
            ProcessTranslation();
            ProcessRotation();
            ProcessFiring();
        }

    }
    void OnPlayerDeath()
    {
        isControlEnabled = false;
        gameController.GameOver();
    }
    private void ProcessRotation()
    {
        float pitchDueToPosition = transform.localPosition.y * positionPitchFactor;
        float pitchDueToControlThrow = yThrow * controlPitchFactor;
        float pitch = pitchDueToPosition + pitchDueToControlThrow;
        float yaw = transform.localPosition.x * positionYawFactor;
        float roll = xThrow * controlRollFactor;

        transform.localRotation = Quaternion.Euler(pitch, yaw, roll);
    }

    private void ProcessTranslation()
    {

        xThrow = CrossPlatformInputManager.GetAxis("Horizontal");
        yThrow = CrossPlatformInputManager.GetAxis("Vertical");

        float xOffset = xThrow * controlSpeed * Time.deltaTime;
        float yOffset = yThrow * controlSpeed * Time.deltaTime;


        float rawXPos = transform.localPosition.x + xOffset;
        float clampedXPos = Mathf.Clamp(rawXPos, -xRange, xRange);

        float rawYPos = transform.localPosition.y + yOffset;
        float clampedYPos = Mathf.Clamp(rawYPos, -yRange, yRange);

        transform.localPosition = new Vector3(clampedXPos, clampedYPos, transform.localPosition.z);
    }
    void ProcessFiring()
    {
        if (CrossPlatformInputManager.GetButton("Fire"))
        {
            SetGunsActive(true);
        }
        else
        {
            SetGunsActive(false);
        }
    }
    private void SetGunsActive(bool isActive)
    {
        foreach (GameObject gun in guns) // care may affect death FX
        {
            var emissionModule = gun.GetComponent<ParticleSystem>().emission;
            emissionModule.enabled = isActive;
        }
    }
    void OnPlayerLanding()
    {
        isControlEnabled = false;

        if (!landed)
        {
            gameController.GameOver();
        }
    }
    void OnPlayerTakeOff()
    {
        isControlEnabled = true;
        landed = false;

    }
}
using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class PlayerHealth : MonoBehaviour
{
    [SerializeField] GameObject deathFX;
    [SerializeField] Transform parent;
    public Image Bar;
    public Text Text;
    public float max_health = 100f;
    public float cur_health = 0f;


    //Use this for initialization
    void Start()
    {
        // Initialize the health that is given
        cur_health = max_health;

        InvokeRepeating("decreaseHealth", 0f, 2f);



    }
    void Update()
    {
        if (cur_health <= 0)
        {
            Destroy(gameObject);   //if the player has no health point left, destroy the player.
        }
    }
    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.GetComponent<Projectiles>())
        {
            max_health -= cur_health;
            //if the collision object has a homing script, minus player health by damageToPlayer
        }
    }
    void decreaseHealth()
    {
        //Subtract the health at the following rate
        //Check if the health is 0 before we do any damage
        if (cur_health < 0)
        {
            cur_health = 0;
        }



        //make a new variable and divide the current health my the maximum health
        //this is because the fill value goes from 0 to 1
        float calc_health = cur_health / max_health; // 70 / 100 = 0.7
        SetHealth(calc_health);

        //Change the color of the health bar
        if (cur_health != 0 && cur_health <= max_health / 1.6 && cur_health > max_health / 2.9) // on the scale of 1000, if health <= 625 and is greater than 345, do the following
        {
            Bar.color = new Color32(171, 162, 53, 255);
        }
        else if (cur_health != 0 && cur_health <= max_health / 2.9) // on the scale of 1000, if health <= 625, do the following
        {
            Bar.color = new Color32(158, 25, 25, 255);
        }
    }
    void SetHealth(float myHealth)
    {
        Debug.Log(GetInstanceID() + ": SetHealth() called."); // Does the method get called?
        Debug.Log(GetInstanceID() + ":SetHealth(), myHealth: " + myHealth); // What value was passed on to it?

        //defill the bar based on the current health
        Bar.fillAmount = myHealth;

        //change the text to display the amount of health
        Text.text = cur_health.ToString("f0") + "/100";
    }
}
1 Like

Hi Martin,

What is the video about? The NullReferenceException? Or is the problem something else? The first thing you should do is to fix the NullReferenceException.

Double click on the error message to see which line gets highlighted. If it’s gameController.GameOver();, check if the GameController instance was found in the Start method of the PlayerController.

Regarding the healthbar problem: The messages you logged into the console are very helpful. We can see that the instance ids are different. This means that there must be multiple PlayerHealth instances in your scene.

Hope this helps. :slight_smile:

1 Like

I sorry but I have no sound with the video software at this time until I upgrade. The message is about this:
NullReferenceException: Object reference not set to an instance of an object
PlayerController.OnPlayerDeath () (at Assets/Scripts/PlayerController.cs:48)
UnityEngine.Component:SendMessage(String)
CollisionHandler:StartDeathSequence() (at Assets/Scripts/CollisionHandler.cs:27)
CollisionHandler:OnTriggerEnter(Collider) (at Assets/Scripts/CollisionHandler.cs:16)

Is this how I check if the GameController instance was found in the Start method of the PlayerController?

private void Start()
    {
         Debug.Log(GetInstanceID() + ": GameController() called."); 
         Debug.Log(GetInstanceID() + ": GameController(), gameController: " + gameController);

        gameController = FindObjectOfType<GameController>();
    }

1 Like

Is this how I check if the GameController instance was found in the Start method of the PlayerController?

Yes, almost.

    private void Start()
    {
         gameController = FindObjectOfType<GameController>();

         Debug.Log(GetInstanceID() + ": GameController() called."); 
         Debug.Log(GetInstanceID() + ": GameController(), gameController: " + gameController);
    }

Of course, you need to look for the GameController first and THEN you evaluate the variable.

1 Like

Okay, I’m testing now to see if the (GameController instance was found in the Start method of the PlayerController) as for the duplicate player health in my scene I believe I found it I provide screenshots. Let me solve the NullReferenceException with your assistance first then we will work on removing the duplicate. If yuo notice under the playerController.cs in the inspector I have Projectiles.cs and a playerHealth.cs I also have the Projectiles.cs and a playerHealth.cs by itself in the inspector.

1 Like

Nina, yes the (GameController instance was found in the Start method of the PlayerController) was called
I providing screenshots with the error message:

1 Like

What happens before OnPlayerDeath gets called? Does anything get destroyed? Maybe the GameController?

Add another Debug.Log to the method and log gameController into your console.

1 Like

Hi, is this what you want me to do to the void OnPlayerDeath()?

 void OnPlayerDeath()
    {
        isControlEnabled = false;
        gameController.GameOver();

        Debug.Log(GetInstanceID() + ": GameController() called.");
        Debug.Log(GetInstanceID() + ": GameController(), gameController: " + gameController);
    }

1 Like

Exactly. Move the Debug.Logs to the top of your method. We want to know what the value of gameController is when the method gets called. If it’s null, something must have happened between your Start method call and the OnPlayerDeath call. In that case, we would go one step back and do the same there and repeat that until we know what happened to your GameController object.

1 Like

I believe it got called I provided a screenshot for you can see

1 Like

If you log a meaningful message into your console, the following numbers will be very helpful:

image

As you can see, there are two different instance ids even though there was supposed to be one GameController in your scene only.

Do the following in the Awake method of the PlayerController class:
Debug.Log(Time.frameCount + " | " + GetInstanceID() + ": GameController was added to: " + gameObject.name, gameObject);

I not following I looked at the player controller I do not find the awake method did you want me to create one like this? where do I place this in the playercontroller if it is correct?

void Awake()
{
Debug.Log(Time.frameCount + " | " + GetInstanceID() + ": GameController was added to: " + gameObject.name, gameObject);
}

This was the message I got.
-389836: GameController(), gameController: Game Controller (GameController)
UnityEngine.Debug:Log(Object)
PlayerController:OnPlayerDeath() (at Assets/Scripts/PlayerController.cs:50)
UnityEngine.Component:SendMessage(String)
CollisionHandler:StartDeathSequence() (at Assets/Scripts/CollisionHandler.cs:27)
CollisionHandler:OnTriggerEnter(Collider) (at Assets/Scripts/CollisionHandler.cs:16)

1 Like

If there is no Awake method, you need to create one. And log a more meaningful message into your console. As you can see, I also added the frameCount to get more information on when the other GameController appears. Does it happen in the same frame? Does the second GameController appear later?

When you click on the message once, the game object to which the instance is attached will get highlighted in your hierarchy.

1 Like

When I run the game the messages in the console appear separately one after the other.
I added the awake method and this is what message came in the console I provide a screenshot. I am also updating Visual Studio and GitHub in Visual Studio.

1 Like

Where does this GameController object come from? And to which game object is it attached?

image

1 Like

I don’t know how to find where it is coming from when I click on it nothing gets highlighted in the hierarchy /inspector. if this is what you mean? Only this gets highlighted below in my screenshot. Everything else when I click on it nothing happens.

1 Like

The highlighted message should appear twice because the Awake method should have been called for the other GameController object, too.

Interestingly, your Player Ship in your screenshot does not have a GameController attached, whereas some Player Ship (Clone) obviously does. Where does the clone come from?

1 Like

I could not tell where the clone comes from only this screenshot. Should I attach the game controller to the player ship? These screenshots are what gets highlighted in the hierarchy and in VS Visual Studio. how can we search/find for the clone? btw, when I click on the last screenshot with the player ship thin the it highlights in yellow though it doesn’t show while I take a screenshot.

Screenshot%20(147) Screenshot%20(148)

1 Like

I’m not sure if it was your project or the project of someone else but if it was yours, I asked you multiple times why you spawned multiple player objects, and you always ignored that question.

Is the GameController a logical part of the player? If not, create a separate game object and assign the GameController to that game object.

1 Like

Hi Nina, I not trying to dodge your question believe I looking to have you help me solve this-this is my project all mine I plan to change assets and try and sell the game form my business site I have a lot of plans for this game I really want and need your help. I spawned the player object because I did not know any other way for the code (c#) in Visual Studio to work I had to add this code as I was doing research on how to get the enemy to shoot back. If you remember I told you some of the code I added on my own and some I copied paste from my research. If you can guide to remove this multiple spawn player objects correctly I would appreciate your help and guidance. I thought those where the reason why the scene has clones. Finally, How can I fix this or how can I remove these clones correctly and still meet my goals to get the enemy to shoot back and the player health bar to decrease when the player ship gets hit?

Below is the portion of code for the enemy management and projectiles cs that requires for my to spawn multiple times. I also added the .cs for both scripts.

In the Projectiles.cs

void Shoot()
    {

        if (onRange)
        {

            Rigidbody enemyGun = (Rigidbody)Instantiate(projectile, transform.position + transform.forward, transform.rotation);
            enemyGun.AddForce(transform.forward * enemyGunImpulse, ForceMode.Impulse);
        }
    }

    void Update()
    {
        onRange = Vector3.Distance(transform.position, playerShip.position) < range;

        if (onRange)
            transform.LookAt(playerShip);
    }
}

In EnemyManagement.cs

  void Update()
    {
        Vector3 targetDir = target.position - transform.position;

        // The step size is equal to speed times frame time.
        float step = speed * Time.deltaTime;

        Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
        Debug.DrawRay(transform.position, newDir, Color.red);

        // Move our position a step closer to the target.
        transform.rotation = Quaternion.LookRotation(newDir);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Projectiles : MonoBehaviour
{
    public Transform playerShip;
    public float range = 20.0f;
    public float enemyGunImpulse = 10.0f;
    bool onRange = false;
    public Rigidbody projectile;
    

   void Start()
    {
        float rand = Random.Range(1.0f, 2.0f);
        InvokeRepeating("Shoot", 2, rand);
      
    }
    void Shoot()
    {

        if (onRange)
        {

            Rigidbody enemyGun = (Rigidbody)Instantiate(projectile, transform.position + transform.forward, transform.rotation);
            enemyGun.AddForce(transform.forward * enemyGunImpulse, ForceMode.Impulse);
        }
    }

    void Update()
    {
        onRange = Vector3.Distance(transform.position, playerShip.position) < range;

        if (onRange)
            transform.LookAt(playerShip);
    }
}

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

public class EnemyManagement : MonoBehaviour
{
    // The target marker.
    [SerializeField] Transform target;

    // Angular speed in radians per sec.
    [SerializeField] float speed;

    // Start is called before the first frame update
    void Start()
    {
        AddSphereCollider();
    }

    private void AddSphereCollider()
    {
        Collider sphereCollider = gameObject.AddComponent<SphereCollider>();
        sphereCollider.isTrigger = false;
    }

    void Update()
    {
        Vector3 targetDir = target.position - transform.position;

        // The step size is equal to speed times frame time.
        float step = speed * Time.deltaTime;

        Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
        Debug.DrawRay(transform.position, newDir, Color.red);

        // Move our position a step closer to the target.
        transform.rotation = Quaternion.LookRotation(newDir);
    }
}

1 Like

Privacy & Terms