I am trying to set my game up to where there is a player, you touch the screen to throw the object, once that object collides with another object 1 point is added to the score. I added a script to the instantiated object that prints a message, to the console, when a collision is detected. The script also has a reference to another script holding the score variable.
The script is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrackEgg : MonoBehaviour
{
public Stats stats;
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "BreakEgg")
{
stats.DepositMoney();
Debug.Log("I am actually working");
}
}
}
The Stats script is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Stats : MonoBehaviour
{
[Header("Bank")]
public int bankAmount;
public int depositAmount;
public void DepositMoney()
{
bankAmount += depositAmount;
}
}
I know I have to have the Stats script attached to a game object(I have it attached to an empty game object). The thrown object is a prefab and has the CrackEgg
script as a component. I try to drag the Stats game object into the Stats field of the CrackEgg
script but it doesn't work. It only works if the Stats game object is also a prefab. The main issue I'm having is that even when I have the Stats game object prefab in the hierarchy, when I test the code, the bankAmount
variable does not increase at all. As a summary, I want the instantiated object to detect a collision then run the DepositMoney()
method, from the Stats script, but am not able to find a way to make it work.
Quick check: create a CrackEgg
on the scene. Try to drag the Stats
object into the field. It should work. Now drag this CrackEgg
to the Project View in order to create a prefab. The Stats
field is empty on the prefab. Why?
A prefab can be instantiated anywhere in your game, so it's possible this reference to a scene object is not valid in case the prefab is instantiated in another scene.
So you must get the reference to the Stats
object in runtime.
You can accomplish that in two ways:
METHOD 1
Tag your Stats
object with a "Stats" tag.
Then locate it in the scene whenever you start a CrackEgg
.
class CrackEgg : MonoBehaviour {
void Start() {
stats = GameObject.FindGameObjectWithTag("Stats").GetComponent<Stats>();
}
}
METHOD 2
Make your Stats
class static, and not a MonoBehaviour component.
public class Stats
{
private static int bankAmount;
public static void DepositMoney(int depositAmount)
{
bankAmount += depositAmount;
}
}
Then you don't add it to any object, since there's always a single instance of each parameter on the program. This is an usual pattern for score classes.
To access it, you don't need to store a reference to Stats
, just use the class name:
if (collision.gameObject.tag == "BreakEgg")
{
Stats.DepositMoney(depositAmount);
Debug.Log("I am actually working");
}
Since you can't assign values to static classes on the Editor, I've suggested a modification where the caller defines the deposit amount when calling. You might need to think about the safety issues (don't allow values out of a range, etc).
Also, it's usually recommended you use CompareTag
instead of ==
: https://answers.unity.com/questions/200820/is-comparetag-better-than-gameobjecttag-performanc.html