Throughout the process of developing Soulstice, one thing that made rapid iteration possible was the use of Unity events. I touched on this in the last blog post, but here I will go in depth in their uses in the project.
Part 1: What is an Event?
To be specific, Unity events are methods that can be triggered under custom circumstances. An example of this would be the built in Unity Button component. The ‘circumstances’ for the buttons are on PointerEnter (hovering your mouse over the button), OnClick(clicking on the button), and PointerExit.
Note that Unity allows you to edit the event called for OnClick, but for the PointerEnter and PointerExit events, the component handles them internally for creating visual feedback.
To be specific to Soulstice’s character controller, events were implemented in 3 different ways. Serialized custom events that can be created through scripting, Unity’s Button component, and Unity’s Event Trigger component. This blog will cover their usefulness and their implementation inside of the prototype.
Part 2: Custom Events in the Player
As discussed in the previous dev blog, the player character controller utilizes many different events. All of these events are made through Unity and are serialized so they can be hooked up in the inspector. To start off, the events that I had created for the player were naturally based on what the player was able to do; attack, jump, and open the menu. Attacking was just a function that was called OnMouseDown, where jumping was set to OnButtonDown and OnButtonUp, making the character jump and controlling the height respectively. The menu’s activation worked similarly, as pressing down a button opened the menu and releasing closed it, but because of events, a variety of other functions could also be attached with very little code.
Part 3: Unity’s Button
Unity’s button component is a very quick and easy solution to many interfacing needs. It provides a simple way to activate something through an event and most developers are aware of this.
In Soulstice, The menu consisted of 5 button laid out in a half circle around the player. When the player moused over one of the buttons, it would display a preview of the building and its name. Clicking the button would then commit placing the building down.
However useful/powerful/quick Unity’s button component is, if it’s not used strictly for a static menu or something similar, having a custom solution would be much easier. I say this because after trying to use it in Soulstice, I found it very limiting. The only event that was could be customized was OnClick, so for Soulstice’s context heavy menu, there needed to be more functionality.
There was no way to leverage this and instead a compromise had to be made. What was so attractive about the Button component in the first place was that it handled animations very well. It could create animations for each Button state (Normal, Highlighted, Pressed, Disabled) and called their triggers automatically, so that functionality was kept. However, that still left the actual data passing (containing building size, name etc.) and doing this in scripting would have the functionality spread across an editor level and scripting level, meaning a more disjointed project. This is where Event Triggers come into play.
Part 4: Event Triggers
Unity Event Triggers are essentially a more robust version of Unity’s Buttons. You put them on a UI element and this basically allows them to detect multiple interactions.
I call this a more powerful version of a Button because it has a lot more interaction based detection. For example, it can detect hovering, clicking, dragging, dropping, amongst other inputs. Other than that, it shares the same flaws as the button. It’s limited to a UI element, and its triggers are still based on a pool of interactions.
Despite this, it still served its purpose, as events could be called OnPointerEnter and OnPointerExit allowing the call of functions without the need reference each other beforehand. An example of this functionality is the building outline giving a display of the selected building while hovering over the button. Each building is identified with an int value from 0-5, so when a button detects OnPointerEnter, it calls an event that passes the corresponding int to the class that handles the building.
Now what makes events as a whole very useful (especially those that are serialized by Unity) is that they aren’t limited to the amount of actions it can take. One event trigger can call many different events. So in combination with the OpenMenu event, I also hooked up the Camera Controller class. Just by adding a public function to that class, I could now resize the camera based on what events were called. So because the menu was too big to fit on the screen, calling the OpenMenu event also zoomed out the camera. This was a very quick addition to the overall menu system that was extremely easy to implement.
Part 5: Conclusion
Overall, the use of events is very efficient and saves time in a rapid iterative process. Simple functionality can be added almost immediately for quick testing and it makes evaluating certain mechanics easy.
But it is very easy to overuse events–especially Unity component based ones, where some drawbacks include the lack of customizability as they’re limited to interaction based detections (clicking, dragging, etc.). The project can also very easily become bloated with events wherein the inspector loses navigability due to the amount of space they take up and the lack of visual difference between their functions. But all in all, their uses outweigh their drawbacks, especially when being mindful of whether your use is excessive or not.
Custom events are good for hooking up certain script to script functionality, like in a character controller where things like control schemes are subject for change and allows each of the controller scripts to get data from each other without excessive references.
Unity Buttons are good for static interfaces where the functionality of the menu is exactly what a real world button would do, such as for options and confirm/deny selections. It also neatly organizes and can auto-create animations which can be helpful. It does nothing that an Event Trigger can’t do, but is a good way to keep visual feedback separated from functionality.
Unity Event Triggers pick up where Unity Buttons lack, by covering a wider variety of interactions capable of handling more data sensitive cases (as with Soulstice itself) while still fundamentally acting as a button.
In conclusion, the event systems that Unity has provide more choices during development and save on time between iterations. While using them appropriately, they are an extremely powerful optimization, development, and design tool.