Search Unity

my scritps are not able to communicate with each other! in a GAME JAM :)

Discussion in 'Scripting' started by hkone1, Jul 20, 2017.

  1. hkone1

    hkone1

    Joined:
    Jun 6, 2017
    Posts:
    24
    i am making a first person shooter game in VR for a VRjam, but my scripts don't communicate with each other,
    like when i try to access my health variable from my target object, it says:
    NullReferenceException: Object reference not set to an instance of an object
    Gun.TakeDamage () (at Assets/Scripts/Gun.cs:26)
    Gun.Shoot () (at Assets/Scripts/Gun.cs:44)
    Gun.FixedUpdate () (at Assets/Scripts/Gun.cs:22)

    in a minute if you see my code you'll notice that my error is linked to my scripts not communicating, here's my code, Thanks, any help is appreciated: Gun:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Gun : MonoBehaviour {
    6.     public ParticleSystem GunFlash;
    7.     public Transform initialPos;
    8.     public float speed = 20;
    9.     public Camera fpsCam;
    10.     Rigidbody rb;
    11.     public int damage = 10;
    12.     public float range = 100f;
    13.     public GameObject Enemy;
    14.  
    15.     // Use this for initialization
    16.     void Start () {
    17.         rb = GetComponent<Rigidbody>();
    18.         //target.instance.health = int health2;
    19.     }
    20.    
    21.     // Update is called once per frame
    22.     void FixedUpdate () {
    23.         Shoot();
    24.     }
    25.     public void Shoot()
    26.      
    27.     {
    28.         if (Input.GetButtonDown("Fire1"))
    29.         {
    30.             GunFlash.Play();
    31.             Vector3 forward = Camera.main.transform.forward;
    32.             RaycastHit hit;
    33.             if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
    34.             {
    35.                 if (hit.transform.name == "Enemy")
    36.                 {
    37.                     target.instance.TakeDamage(damage);
    38.                 }
    39.             }
    40.         }
    41.     }
    42. }
    43.  
    Target:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class target : MonoBehaviour {
    6.     public int health = 30;
    7.     public static target instance;
    8.     // Use this for initialization
    9.     void Start()
    10.     {
    11. }
    12.  
    13.  
    14.     // Update is called once per frame
    15.     void Update () {
    16.          
    17.     }
    18.     public void TakeDamage(int amount)
    19.     {
    20.         target.instance.health -= amount;
    21.         if (target.instance.health <= 0)
    22.         {
    23.             Destroy(target.instance.gameObject);
    24.         }
    25.     }
    26. }
    27.  
     
  2. GeorgeCH

    GeorgeCH

    Joined:
    Oct 5, 2016
    Posts:
    222
    First and foremost, check to make sure you're actually hitting the right target - put a Debug.Log line into your Shoot() function that returns the transform.name of the hit.

    Secondly, use tags instead of name to check whether the target is correct - if you've any instantiation going on, copies of the Enemy object will spawn with the Enemy(Clone) name and break your script.

    Try the Debug.Log approach above and post back to see what actually gets hit - the rest of the code seems fine.

    EDIT: Here is an example of how I do something very similar in my current project - not necessarily the best way to do it, but it certainly works. Note that I use a slightly different implementation as I check for multiple touches (hence the array) that intentionally have an "area" to them (hence the OverlapCricleAll), but the broad idea is the same: check what gets hit, and if the right object gets hit, call the damage-dealing method.

    Code (CSharp):
    1. void CheckMultiTouch(Vector3 position) {
    2.  
    3.     Collider2D[] hits = Physics2D.OverlapCircleAll(Camera.main.ScreenToWorldPoint(position), PlayerController.attributes.multitouchRadius);
    4.  
    5.     for (int i = 0; i < hits.Length && i < PlayerController.attributes.multitouchLimit; i++) {
    6.         if (hits[i].tag == "Candy") {
    7.             hits[i].GetComponent<Spawn>().Clicked();
    8.         }
    9.     }
    10. }
     
    Last edited: Jul 20, 2017
  3. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    916
    Well you're accessing the target statically. And you're trying to destroy a target without even first checking if it exists. overall the entire code is poorly written. see about giving the target a script that implements IPointerEnterHandler and IPointerExitHandler, this way you can leverage the system thats already in unity to handle your targeting
    Code (CSharp):
    1. //requires the target to have a collider, an eventsystem to exist in the scene, and the camera to have a physics raycaster
    2. public class GazeTarget: MonoBehaviour, IPointerEnterHandler,IPointerExitHandler
    3. {
    4.     public virtual void OnPointerEnter(PointerEventData eventData)
    5.     {
    6.         if(!enabled) return;
    7.         if(!gameObject.activeInHierarchy)return;
    8.  
    9.         eventData.selectedObject = gameObject;
    10.     }
    11.     public virtual void OnPointerExit(PointerEventData eventData)
    12.     {
    13.         if(!enabled) return;
    14.         if(!gameObject.activeInHierarchy)return;
    15.  
    16.         if(eventData.selectedObject == gameObject)
    17.             eventData.selectedObject = null;
    18.     }
    19. }
    thus by default whatever object you're looking at (which has this script) the event system will consider as the current target.

    then your gun can simply try and attack the current selected gameobject in the event system.
    Code (CSharp):
    1. public class Gun: MonoBehaviour
    2. {
    3.     public string InputName = "Fire1";
    4.     public int attackDamage = 10;
    5.  
    6.     private void Update()
    7.     {
    8.         var system = EventSystem.current;
    9.         if(!system) return;
    10.  
    11.         var targetGo = system.currentSelectedGameObject;
    12.         if(!targetGo) return;
    13.  
    14.         if(!Input.GetButtonDown(InputName)) return;
    15.  
    16.  
    17.         var health = targetGo.GetComponent<HealthScript>();
    18.         if(!health) return;
    19.  
    20.         health.Damage(attackDamage);
    21.     }
    22. }
    but then have it only damage whatever has a health script
    Code (CSharp):
    1. public class HealthScript: MonoBehaviour
    2. {
    3.     public int currentHealth = 30;
    4.     public int maxHealth = 30;
    5.  
    6.     private void OnEnable()
    7.     {
    8.         currentHealth = maxHealth;
    9.     }
    10.  
    11.     public void Damage(int damage)
    12.     {
    13.         currentHealth = Mathf.Max(currentHealth - damage,0);
    14.         if(currentHealth <=0)
    15.             Kill();
    16.     }
    17.  
    18.     public void Kill()
    19.     {
    20.         if(gameObject)
    21.             Destroy(gameObject);
    22.     }
    23. }
    24.  

    Now regarding Game Jams and based on the code I've seen... here's just some honest advice.

    You shouldn't be going to a game jam with the goal of learning how to do something. you should be going to a game jam with the goal of trying to do what you already know how to do faster. Take it from someone who tried to both learn the Unreal Engine and make a game over a 3 day game jam. You will not get very far. just focus one what you already know how to do, and try to do it faster in the game jam.
     
  4. hkone1

    hkone1

    Joined:
    Jun 6, 2017
    Posts:
    24
    Hi Guys, thanks both of you, i know my code is poorly written, because i am a beginner, and i am still doing a course, as you said, i made sure it wasn't null by using the singleton pattern, @GeorgeCH yes ill try using tags, as right now im using string.length to make it work with all enemies, but if i kill one enemy, all of them fall down, now your gonna see more poorly written code, because again im a beginner :), anyway, here;s my code: Thanks!

    GUN:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Enemy : MonoBehaviour {
    6.  
    7.     public static Enemy instance;
    8.     Rigidbody eRb;
    9.     public int speed = 2;
    10.     bool isMoving = true;
    11.  
    12.     // Use this for initialization
    13.     void Start () {
    14.         if (Enemy.instance == null)
    15.         {
    16.             Enemy.instance = this;
    17.         }
    18.         else if (instance != null)
    19.         {
    20.             return;
    21.         }
    22.         eRb = GetComponent<Rigidbody>();
    23.     }
    24.  
    25.     // Update is called once per frame
    26.     void FixedUpdate () {
    27.         FollowPlayer();
    28.     }
    29.  
    30.     void FollowPlayer()
    31.     {
    32.         if (target.instance.isAlive && isMoving)
    33.         {
    34.             transform.LookAt(Camera.main.transform.position);
    35.             float step = Time.deltaTime * speed / 2;
    36.             transform.position = Vector3.MoveTowards(transform.position, Camera.main.transform.position, step);
    37.         }
    38.         else
    39.         {
    40.             isMoving = !isMoving;
    41.         }
    42.     }
    43. }
    44.  
    TARGET:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class target : MonoBehaviour {
    6.     public int health = 30;
    7.     public static target instance;
    8.     float addRot;
    9.     public bool isAlive = true;
    10.     public Rigidbody tRb;
    11.     // Use this for initialization
    12.     void Start()
    13.     {
    14.         if (target.instance == null)
    15.         {
    16.             target.instance = this;
    17.         }
    18.         else if (instance != null)
    19.         {
    20.             return;
    21.         }
    22.         tRb = GetComponent<Rigidbody>();
    23.     }
    24.  
    25.  
    26.     // Update is called once per frame
    27.     void Update () {
    28.         addRot += 8f;
    29.     }
    30.     public void TakeDamage(int amount)
    31.     {
    32.         health -= amount;
    33.         if (health <= 0)
    34.         {
    35.             Fall();
    36.             isAlive = false;
    37.         }
    38.     }
    39.     public void Fall()
    40.     {
    41.         if (!isAlive)
    42.         {
    43.             Vector3 up = new Vector3(0, 1f, 0);
    44.             Vector3 newUp = transform.position + up;
    45.             tRb.MovePosition(newUp);
    46.             transform.Rotate(0, 0, addRot);
    47.             Destroy(gameObject, 10);
    48.         }
    49.     }
    50. }
    51.  
    Enemy:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Enemy : MonoBehaviour {
    6.  
    7.     public static Enemy instance;
    8.     Rigidbody eRb;
    9.     public int speed = 2;
    10.     bool isMoving = true;
    11.  
    12.     // Use this for initialization
    13.     void Start () {
    14.         if (Enemy.instance == null)
    15.         {
    16.             Enemy.instance = this;
    17.         }
    18.         else if (instance != null)
    19.         {
    20.             return;
    21.         }
    22.         eRb = GetComponent<Rigidbody>();
    23.     }
    24.    
    25.     // Update is called once per frame
    26.     void FixedUpdate () {
    27.         FollowPlayer();
    28.     }
    29.  
    30.     void FollowPlayer()
    31.     {
    32.         if (target.instance.isAlive && isMoving)
    33.         {
    34.             transform.LookAt(Camera.main.transform.position);
    35.             float step = Time.deltaTime * speed / 2;
    36.             transform.position = Vector3.MoveTowards(transform.position, Camera.main.transform.position, step);
    37.         }
    38.         else
    39.         {
    40.             isMoving = !isMoving;
    41.         }
    42.     }
    43. }
    44.  
    Thanks Again!