Now it is time to write some real code :)
I have mentioned why do we move to Unity and how we use the power of Unity Editor so far. And in this section I will explain how to write code in Unity3D.
By default MonoDevelop is the integrated development environment (IDE) supplied with Unity. An IDE combines the familiar operation of a text editor with additional features for debugging and other project management tasks.
If you are using Unity on Windows, Visual Studio (with ReSharper) might be a better choice instead of MonoDevelop. If you are working on MacOS like me, then for now MonoDevelop is the best option. I have tried other simple editors like Sublime Text or Visual Studio Code but unfortunately just editor is not enough for long time development, you need a real IDE. I am looking forward to use Rider (A cross-platform C# IDE based on the IntelliJ platform and ReSharper) soon. It is still in beta. So for now MonoDevelop is the answer.
Me when I code |
Coding part is called Scripting in Unity documentation. It is an essential part of a game, even the simplest game needs scripts to respond to input from the player and arrange for events in the gameplay to happen when they should. Beyond that, scripts can be used to create graphical effects, control the physical behaviour of objects or even implement a custom AI system for characters in the game.
I will mention a few key points of scripting in Unity.
I will mention a few key points of scripting in Unity.
Event Functions
Although Unity uses an implementation of the standard Mono runtime for scripting, it still has its own practices and techniques for accessing the Unity game engine from scripts.
A script in Unity is not like the traditional idea of a program where the code runs continuously in a loop until it completes its task. Instead, Unity passes control to a script intermittently by calling certain functions that are declared within it. Once a function has finished executing, control is passed back to Unity. These functions are known as event functions since they are activated by Unity in response to events that occur during gameplay. Unity uses a naming scheme to identify which function to call for a particular event. For example, the Update function (called before a frame update occurs) and the Start function (called just before the object’s first frame update). Many more event functions are available in Unity; the full list can be found in the script reference page.
Strange IoC
These scripts are special kind of code pieces to integrate your code with UnityEngine. That doesn't mean that all of your code should consist of these kind of scripts. You can have your own software architecture behind the scene and use these special script codes to connect to game objects in the game scene. Actually I strongly recommend to do so, by doing that you could have testable clean code apart from scripts.
We move a step further in our games and create our own architecture based on DI (Dependency Injection). I think I don't need to explain what is DI and why it is needed. It is one of the key patterns of software engineering. We are using StrangeIoC as our DI framework. StrangeIoC is a super-lightweight and highly extensible Inversion-of-Control framework, written specifically for C# and Unity.
Actually we are not using StrangeIoC just for DI, and also to have consistent, modular and clear software design in our code base. Main idea is decouple all our class dependencies and write cleaner, modular code with a highly optimized Reflection/Injection system. Additionally it helps us to have Signals-and-Slots style Signals dispatcher for type-safe communication. View mediation allows us to have clean separation of Views from Controllers and Models with no loss of capability. Strange's architecture is based on the popular Robotlegs micro-framework. This architecture is well founded, highly proven, and lightly urges responsible development that works great for individuals or teams.
Component Driven Architecture
There are plenty of discussion on what is Component Driven Architecture and how should be implemented. If you are coming strong background of OOP development like me you will need quite amount of time to adapt and fully leverage this concept. I know they are not opposite to each other, on the contrary they can be used together very smoothly. OOP is a way to build a logical hierarchy of classes, while components is a way of aggregating the different behaviour of an objects.
Unity is by design a component driven product. And it forces you to use it even if you are not comfortable with this concept. Every functionality (or behaviour in Unity jargon) that you will add to your game objects is already a component.
Let me give you an example from our games. We have quite amount of popups in our games. Not directly the board/main area of the game, but other parts like rooms, lobby, inbox, campaigns have a lot of popups, and the coordination of these popups is not an easy problem to solve. Sometimes you have to queue them and show them one by one, sometimes you need to show them immediately, sometimes you have to clear them, sometimes you have to convert them from popup to inbox message etc...
Instead of creating a popup class hierarchy, and having popup functions and fields in various types of classes. We choose to define popup functions as a set of behaviours. If a game object needs to have popup functions (in whole life cycle or for a certain period of time) it can attach and enable this component and can be treated as a popup by the rest of the code. Besides we define popup functions with an IPopup protocol to be able to give all the management to a manager object that will deal with different implementations of this interface.
Everything can be a popup |
By doing that we can enrich popup definitions with different implementations (and believe me we are going to need various types of popups in our games) and also we make sure that any game object what ever it's original purpose is, can be treated and behave like a popup.
Coroutines
One important most used technic in Unity is coroutines. Let's go with an example; when you call a function, it runs to completion before returning. This effectively means that any action taking place in a function must happen within a single frame update; a function call can’t be used to contain a procedural animation or a sequence of events over time. As an example, consider the task of gradually reducing an object’s alpha (opacity) value until it becomes completely invisible.
As it stands, the Fade function will not have the effect you might expect. In order for the fading to be visible, the alpha must be reduced over a sequence of frames to show the intermediate values being rendered. However, the function will execute in its entirety within a single frame update. The intermediate values will never be seen and the object will disappear instantly.
It is possible to handle situations like this by adding code to the Update function that executes the fade on a frame-by-frame basis. However, it is often more convenient to use a coroutine for this kind of task.
A coroutine is like a function that has the ability to pause execution and return control to Unity but then to continue where it left off on the following frame. It is essentially a function declared with a return type of IEnumerator and with the yield return statement included somewhere in the body. The yield return line is the point at which execution will pause and be resumed the following frame.
Screen Management
One last topic I want to share is screen management. Unity has game scenes, and transition from one scene to other is not a trivial thing from performance point of view. It needs to load everything inside the scene and then show the scene and this takes a lot of time in most of the cases.
While loading the scene game freezes, there might be some Unity games without these scene loading glitches but as a producer or as a consumer I didn't see so far.
We do not want to face these glitches in our games. So decided use one giant scene. It has different drawbacks of course, but so far so good. We could manage to handle all the drawbacks and create a smooth screen transitions between the different sections of the game.
Board games like us does not need levels or very different atmospheres in the game area, focus is different. And we change this difference as an advantage. As I say our entire game is in one big scene, but from player point of view, we still need to create a navigation / transition from one section to other. It is a very basic problem (not a problem actually) in a native iOS or Android mobile game/app. They have build-in mechanism and solutions. But here we need to find a way to make that simple transition.
So we use similar concept of iOS ViewController transition states like ViewWillAppear, ViewDidAppear, ViewWillDisappear, ViewDidDisappear. And in addition to that we add some camera moves on screen transitions. In above movie, please give attention inside the scene view and camera moves.
There are much more things that we can talk about, but may be in future posts. Now we are going to concentrate on testing our code.
Hiç yorum yok:
Yorum Gönder