Reputation: 9065
According to this tutorial demonstrated on youtube
It is working to make a static variable to hold the score and change it in other scripts when the player should be awarded, but it also advised that using static variable in C# script of Unity might not be recommended.
Flowing is what I do to construct the scoring system:
in ScoreManger
which was bonded to an UI Text component to show the score:
public class ScoreManager : MonoBehaviour {
public static int score;
Text text;
private void Awake()
{
text = GetComponent<Text>();
}
private void FixedUpdate()
{
text.text = "Score: " + score;
}
}
And the procedure to add the score:
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
ScoreManager.score = ScoreManager.score + score;
Destroy(gameObject);
}
}
So what's the best way to do this without a static variable, and if someone could explain why using a static variable is not recommended will be more grateful.
Have tried the event handle way as @rogalski demonstrated in the answer, but the IDE shows that there is an error for type conversion on the lambda function of ExecuteEvents.Execute<T>
Upvotes: 5
Views: 11976
Reputation: 5920
You have to remember that Unity
is a component based engine meaning that components have to do some specific work independently. This can be well combined with event driven programming methodology which mean that application ( or each of it's components ) are dependant on some event input.
Unity
introduced really well designed Event ( or Messaging ) system which you should use instead of making static fields, classes etc.
To point you out in the right way of implementing this I'll use the most trivial example.
( EDIT -> Added definition for EventData
which is required for Unity
's messaging system )
First register your event :
public interface ICoinPickedHandler: IEventSystemHandler
{
void OnCoinPickedUp(CoinPickedEventData eventData);
}
Then implement this EventTarget into your script :
public class ScoreManager
: MonoBehaviour, ICoinPickedHandler
{
private int m_Score;
public void OnCoinPickedUp(CoinPickedEventData eventData)
{
this.m_Score += eventData.Score;
eventData.Use();
}
// code to display score or whatever ...
}
Now to use this you have to just fire the event :
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
// assuming your collision.gameObject
// has the ICoinPicker interface implemented
ExecuteEvents.Execute<ICoinPickedHandler>(collision.gameObject, new CoinPickedEventData(score), (a,b)=>a.OnCoinPickedUp(b));
}
}
Now you have to create EventData
:
public class CoinPickedEventData
: BaseEventData
{
public readonly int Score;
public CoinPickedEventData(int score)
: base(EventSystem.current)
{
Score = score;
}
}
Of course this example requires from you to know the target to which you want to send that event. But if you do not know the target, you can use approach to ExecuteHierarchy
.
More on that topic on docs.unity3d.com.
Upvotes: 5
Reputation: 574
First of all , it would be better to wrap the static variable in a method: addToScore , so in case behavior changes you only have to implement the changes once.
For the static variable: I think it would be better to make the score manager a singleton instance instead of a static variable. Because then if you decide you need more score managers, reset the score manager, save more data in the score manager or whatever it will be a lot easier.
Upvotes: 1