Search Unity

When health points diminish do something - problem

Discussion in 'Scripting' started by Jeepster, Jul 17, 2019.

  1. Jeepster

    Jeepster

    Joined:
    Jan 23, 2014
    Posts:
    401
    Hi,

    my health script looks like this:
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class Health : Photon.MonoBehaviour {
    7.  
    8.      float hitPoints = 100;
    9.      float currentHitPoints;
    10.     // Use this for initialization
    11.  
    12.  
    13.  
    14.     void Start () {
    15.         currentHitPoints = hitPoints;
    16.     }
    17.     IEnumerator KillBloodFX()
    18.     {
    19.         yield return new WaitForSeconds(.5f);
    20.      
    21.     }
    22.     [PunRPC]
    23.     public void TakeDamage(float amt)
    24.     {
    25.        
    26.  
    27.         currentHitPoints -= amt;
    28.    
    29.  
    30.         if (currentHitPoints <= 0)
    31.         {
    32.             Die();
    33.         }
    34.  
    35.  
    36.  
    37.     }
    38.     internal static bool TakeDamage()
    39.     {
    40.         throw new NotImplementedException();
    41.     }
    42.  
    43.     internal bool TakeDamage(float v, object amt)
    44.     {
    45.         throw new NotImplementedException();
    46.     }
    47.  
    48.     void Die()
    49.     {
    50.         if (GetComponent<PhotonView>().instantiationId == 0)
    51.         {
    52.             Destroy(gameObject);
    53.         }
    54.         else
    55.         {
    56.             if (GetComponent<PhotonView>().isMine)
    57.             {
    58.                 PhotonNetwork.Destroy(gameObject);
    59.             }
    60.         }
    61.     }
    62. }
    63.  
    -I want to check if the player has lost any amount of health from another script, and if so 'Do Something'.

    I've tried to make 'currentHitPoints' and 'hitPoints' public to access them from the other script and then use an if statement as such:

    if (h.currentHitPoints < h.hitPoints)
    {
    'Do Something'
    }

    but it doesn't work and I'm also worried that making 'currentHitPoints' and 'hitPoints' public isn't the smartest thing to do.

    Can anyone tell me how to do this?
     
  2. FlashMuller

    FlashMuller

    Joined:
    Sep 25, 2013
    Posts:
    451
    I don't see where you actually use hitPoints and currentHitPoints?
    In spite of that: You can just make your code 'DoSomething' a function of Health that returns a bool.
     
    Jeepster likes this.
  3. GeorgeCH

    GeorgeCH

    Joined:
    Oct 5, 2016
    Posts:
    222
    Whenever you need something to react to something else happening without knowing exactly when it will happen, events are the way to go!

    public UnityEvent PlayerHealthChanged { get; private set } = new UnityEvent();


    Next, turn your currentHitPoints into a property that raises the event whenever it is changed:


    public float CurrentHitPoints
    {
    get { return currentHitPoints; }
    set { currentHitPoints = value; PlayerHealthChanged?.Invoke(); }
    }

    private float currentHitPoints;


    Now, every time the player's hit points are changed, the PlayerHealthChanged event will be raised. All you need to do now is have whatever other class responses to HP changes subscribe to that event. For example:

    Code (CSharp):
    1. public class Foo : MonoBehavior
    2. {
    3.  
    4.     private Health health;
    5.  
    6.     private void Start()
    7.     {
    8.         health = FindObjectOfType<Health>();
    9.         health.PlayerHealthChanged.AddListener(OnPlayerHealthChanged);
    10.     }
    11.  
    12.     private void OnPlayerHealthChanged()
    13.     {
    14.         DoSomething();
    15.     }
    16.  
    17.     private void DoSomething()
    18.     {
    19.         Debug.Log("Player health has changed!");
    20.     }
    21. }
    By the way, making variables public isn't as big a deal as it's made out to be as long as you're the only one working on the project. I agree it's not great practice, but it's not the end of the world either. Usually, to prevent stupid mistakes, I turn my public variables into public properties with a private setter (see the example above). This means that any class can read the contents of the variable but only the class that declares it can change it - thereby massively narrowing the scope of any subsequent debugging effort (if the value of the variable changed, I know exactly which class changed it, because there's only one class that can). There's also a shorthand for it:

    public float CurrentHitPoints {get; private set;}
     
    Jeepster likes this.
  4. Jeepster

    Jeepster

    Joined:
    Jan 23, 2014
    Posts:
    401
    Hi GeorgeHC. Thank you so much for that in depth explanation. I will use a UnityEvent for a lot of different things in my game. And i'll definitely keep in mind that I can turn my public variables into public properties with a private setter. That should keep things nice and easy to find in my project for the future. I appreciate the help very much my friend :) Thank you
     
  5. Jeepster

    Jeepster

    Joined:
    Jan 23, 2014
    Posts:
    401
    So I'm getting the error:
    Assets/Networking/Health.cs(36,60): error CS1644: Feature `null propagating operator' cannot be used because it is not part of the C# 4.0 language specification

    How can I re-write it to fit with C# 4.0 language specification, do you know?
     
  6. Jeepster

    Jeepster

    Joined:
    Jan 23, 2014
    Posts:
    401
    Nevermind, I found this thread discussing the different version of NET and how to change it and it fixed it for me: https://forum.unity.com/threads/fea...t-of-the-c-4-0-language-specification.575008/Thanks again mate :)