Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on March 30, 2023, between 5 am & 1 pm EST, in the Performance Profiling Dev Blitz Day 2023 - Q&A forum and Discord where you can connect with our teams behind the Memory and CPU Profilers.
    Dismiss Notice

Question How do I link scripts?

Discussion in 'Scripting' started by jonastenhoor, Mar 19, 2023.

  1. jonastenhoor


    Mar 17, 2023

    I am making an FPS game, and the player ofcourse needs to take damage from enemies. In this case, melee damage. I tried doing this by creating a Health script on my player, and a damage dealer script on the enemy(derived from my script "Interactable")

    My health script:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    6. public class Health : MonoBehaviour
    7. {
    8.     float currentHealthPlayer;
    9.     public float maxHealth = 100f;
    10.     public Text healthText;
    13.     // Start is called before the first frame update
    14.     void Start()
    15.     {
    16.         currentHealthPlayer = maxHealth;
    17.     }
    19.     // Update is called once per frame
    20.     void Update()
    21.     {
    22.         if(currentHealthPlayer <= 0)
    23.         {
    24.             Die();
    25.         }
    27.         healthText.text = currentHealthPlayer.ToString();
    28.     }
    30.     public void TakeDamage(float damageAmount)
    31.     {
    32.         currentHealthPlayer -= damageAmount;
    33.     }
    35.     void Die()
    36.     {
    37.         Application.Quit();
    38.     }
    39. }
    My damage dealing script:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    5. public class DamageDealerMan : Interactable
    6. {
    7.     public GameObject player;
    9.     public override void Interact()
    10.     {
    11.         base.Interact();
    12.         TakeDamage();
    13.     }
    16. }
    Code (CSharp):
    1. using UnityEngine;
    3. public class Interactable : MonoBehaviour
    4. {
    5.     public float radius = 3f;
    6.     Transform player;
    7.     bool hasInteracted = false;
    9.     void Start()
    10.     {
    11.         //connects player to this script without gameobjects(to improve scene transition)
    12.         player = PlayerManager.instance.player.transform;
    13.     }
    15.     void Update()
    16.     {
    17.         //creates distance based on player pos and this pos
    18.         float distance = Vector3.Distance(player.position, transform.position);
    19.         if(distance <= radius && !hasInteracted) //if distance <= radius and hasn't already interacted:
    20.         {
    21.             Interact(); //Call interact method
    22.             hasInteracted = true;
    23.         }
    24.     }
    26.     //When clicked in Gizmos(editor)
    27.     void OnDrawGizmosSelected()
    28.     {
    29.         //Draw a sphere with radius 'radius'.
    30.         Gizmos.color = Color.yellow;
    31.         Gizmos.DrawWireSphere(transform.position, radius);
    32.     }
    34.     public virtual void Interact()
    35.     {
    36.         //Virtual void; can be accessed from other scripts
    37.         //meant to be overridden(as in, the function changes per script calling this method)
    38.         Debug.Log("Interacting with " +; //Default message in the Debug(for good measure)
    39.     }
    40. }
    I am trying to get to access 'void TakeDamage' from 'Health' in 'DamageDealerMan' script.
    Help would be very much appreciated! Thanks!:)
  2. Kurt-Dekker


    Mar 16, 2013
    Referencing variables, fields, methods (anything non-static) in other script instances:

    REMEMBER: it isn't always the best idea for everything to access everything else all over the place. For instance, it is BAD for the player to reach into an enemy and reduce his health.

    Instead there should be a function you call on the enemy to reduce his health. All the same rules apply for the above steps: the function must be public AND you need a reference to the class instance.

    That way the enemy (and only the enemy) has code to reduce his health and simultaneously do anything else, such as kill him or make him reel from the impact, and all that code is centralized in one place.
  3. jonastenhoor


    Mar 17, 2023
    I just want to let you know you are a legend kurt
    Kurt-Dekker likes this.
  4. Owen-Reynolds


    Feb 15, 2012
    So you know, Interactable with overrides is "late 1990's OOP". Back in the day people said that extra work saved time down the road, but we since learned through experience that it rarely does. If you want to learn classic medium-difficulty OOP than what you're doing is fine, but if you just want to make a game and learn Unity there may be simpler guides.

    As far as finding the player, it depends. An easy hack is giving the player a static (public static Player thePlayer;). But that won't work if the enemy can attack other things, too. If you attack when you "hit" the player you'll get it from the Collision data.
  5. kdgalla


    Mar 15, 2013
  6. Olipool


    Feb 8, 2015
    Hm, can you maybe explain why this is bad/old practice? I am using a similar approach and the common base class Interactable allows me to find different objects in the scene when the player presses "E" for example and wants to interact. The code then just finds Interactables in the radius of the player and calls Interact() and each subclass can implement different behavior. A door can rotate to open, a tape recorder can start playing music etc.
    Of course, you can just put a UnityEvent on the Interactable and drag and drop actions onto it (for example have a separate unrelated Door script and drag that in and call Open() for example but then I need a gameobject for every script/method I want to invoke. What if I just want to call a Debug.Log for an interaction? I can't drag that in the UnityEvent. Also, the events have a limited number of argument types.
    I am not arguing against your point, I am just surprised a bit.
  7. Owen-Reynolds


    Feb 15, 2012
    Late 90's OOP said to slap on interface and base classes immediately. In this case we have "Interactable" and "DamageDealer" and "Health" before having any game functionality. We don't know if they'll have any purpose. A more modern approach is (after you've planned out the things you know you'll need) to just write functional code and then re-combine as needed (what the cool kids call "refactoring"). That's the idea behind Rule of Three -- create a new interface only when you actually have a bunch of things that want it and you know more about the features it should have.

    In OP's code, an Interactable is something that affects the player when it gets near them (one time only). Hmmm. Maybe we have a lot of those, but it's only used for doing damage so far, and that may very well be the only place. Having DamageDealerMan as a Component make it easy to slap onto Shock Pillars and rolling proximity mines, but makes it more difficult to tweak individual behaviors. The Health class is really a PlayerHealth class (it displays itself in the player's health box and quits the game on death). They all seem slapped on too fast and will probably be removed later or get ugly work-arounds.
    Chubzdoomer, mopthrow and Olipool like this.
  8. Olipool


    Feb 8, 2015
    Ah, I see. Thanks for the clarification!