- Home /
C# - GUI best practices: sending changed values to gui object
First, I do understand that there is no 'best'. However, I fear dropping into anti-patterns, and spaghetti code. All I'm looking for is a couple differing viewpoints with arguments to back the pattern (if necessary).
I'm making a very simple "baby's first GUI" for my current project. I'll have a score, an ammo count, and a couple other objects. It's a breakout game, and thus I'll need to send scoring information based on ball collisions, and ammo count changes based on actions taken within my paddle script.
I haven't structured my code in such a way that there is a 'scene manager' object, or any hierarchy like that.
My question is as to a successful pattern by which my GUI components can track these variables. The ideas I've had are:
Create a public 'thePaddle' variable, same with the ball, and check member variables each frame.
Attach the paddle and ball objects along with the GUI objects to some abstracted scene graph or scene manager.
Have the paddle and ball kick off events like "scoreAdd(int pointsToAdd)" and so on.
The third option seems best to me. However, I've no idea how to hook up events in Unity, beyond utilizing the built-in ones such as OnCollisionEnter. If this is the 'best' method, could someone link me to the manual or a tutorial so that I could start learning from there? I do understand delegates and lambda notation, so that should help.
The second option really rubs me the wrong way, as I see Unity as more of a scripting environment than a traditional coding one, and want to avoid 'tall' hierarchies. The environment seems more suited to AOP than OOP in general.
The first option I see as a slippery slope leading to spaghetti code and possible errors.
Any help would be appreciated.
Answer by whydoidoit · Jan 14, 2013 at 03:44 PM
For me I would be going with option 1 and having the GUI update based on variables associated with the actual objects in question. If your GUI object needs access to these other items you would have two choices: a singleton pattern or actual game object references. I would normally choose the latter and associate the GUI item with the object using the inspector.
I do this for the sake of encapsulation and clarity as I would be defining the variables next to the things that use and update them and referencing from the component that reports on them.
I don't know what GUI you are thinking of using, but OnGUI would work the best that way as it does need to be updated every frame.
Presuming you are using some other GUI system that doesn't need the continual update then events to indicate a change would make sense - in that case I would still be associating the objects per my first point but would wire .NET events to the target objects in the Awake of the GUI components.
If you want to use an event pattern generally there are two ways:
SendMessage (which works very like OnCollisionEnter etc - calling a public or private method on another object or objects with up to one parameter). This can work well (especially Broadcast message and SendMessageUpwards which affect multiple objects) as there is no need for any wiring and coding time - however, it uses reflection and runs like a dog (up to 150x slower than a .NET delegate based event).
.NET events which require wiring and unwiring, but are very fast.
Score.cs
public class Score : MonoBehaviour
{
public Paddle thePaddle;
void Awake()
{
thePaddle.ScoreChanged += UpdateScore;
}
void OnDestroy()
{
thePaddle.ScoreChanged -= UpdateScore;
}
void UpdateScore()
{
var newScore = thePaddle.score;
//Do something with it
}
}
Paddle.cs (part)
public class Paddle : MonoBehaviour
{
public event Action ScoreChanged = delegate {};
public int score;
public void SomethingThatChangesScore()
{
score += 10;
ScoreChanged();
}
}
$$anonymous$$ike, I couldn't have asked for a better answer. Thanks so much. Also, thanks for unitygems... I've studied and restudied those many times.
One further question: my next task is to have multiplayer. Thus I'll be mirroring the gui events and objects for a second player. Would it make sense to create essentially a Plain Old Object which holds all scoring information for a player, and hook up the GUI object to this?
I'm starting to see a pattern where the objects that 'belong' to the player (their paddle, their ammo count, their score) have a common "Player" object which manages and handles player information (assu$$anonymous$$g I end up with profiles to save/load). Is this a common pattern, or would you prefer loose coupling wired through delegates?
Yes that sounds like a good approach, though I haven't got a big issue with that object just being another $$anonymous$$onoBehaviour rather than a POCO object - it really depends on what you will do with it - certainly if you wanted to save and load that information then a POCO makes a lot of sense as they are easier to create than $$anonymous$$onoBehaviours (don't need to be associated with a GameObject and hence can be saved and loaded using BinaryFormatter etc).
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Multiple Cars not working 1 Answer
I have some question about custom Hierarchy 0 Answers
How to get a pop-up window floating next to a gameobject? 1 Answer