Hello, Matheus here. For the second entry on the dev log i’m going to talk about the tech and approuch i’ve been taken on the development so far. Hope you enjoy and take something out of this long, but hopefully, worthy reading.
Since this is a dev log, i figure i would put something about the technology used to build the game.
I am currently using Unity 5.5.1f and Visual Studio 2013 Community Edition. My language of choise is C#.
I started using SVN because i heard it handles binary files better than Git, but i end up going back to Git because merging in SVN seems a bit more complicated, at least for me. And this project won’t have huge ammounts of binary files anyway. I’m hosting on Microsoft’s Visual Studio thing that i don’t know the name.
I’m also using Trello as a task tracker and Yodiz as a bug tracker.
I wasn’t going to use Unity for this game at first. I considered using SFML (C++), libGDX (Java) and Mono (C#). I end up using Unity because of NGUI. This game has a lot of images, text, a window system, and more GUI-releated stuff, so the GUI system has to be powerful, simple and complete. And there’s no better GUI system (that i know of) than NGUI.
In this project i used a different approch to the way i handle some things code-wise. In my day job we also use Unity with C#. And we use a lot of OOP (object oriented programming). And that works fine for the most part, but it gets complicated to handle very big projects with lots and lots of inheritance and method overriding.
That’s because in OOP we tend to use inheritance excessively and that’s no good. No good for performance, for maintainability, for clarity. For nothing. Or at least that’s what i heard the important people saying.
I had never actually thought about inheritance and OOP in that way. I had never actually noticed all these problems – because i knew no different.
With this game, since it’s just me building it – programming, designing and all – i realized that i could do whatever i wanted to do. So i decided that i would go with a more procedural approach. I would also try to be as data-oriented as possible, but that’s not so easy when you’re using a garbage collected language like C# (because you don’t have total control over the memory – yes, i know you can use pointers in C#, but if i were to use pointers in C# i would go to C++).
So for every system in the game (the terminal, windows, file system, programs, devices, etc), i have the entity class (Terminal.cs, File.cs, Folder.cs, Program.cs, etc) and a utility class (FileSystemUtil.cs, TerminalUtil.cs, etc).
The entity class have no inheritance whatsoever – except for very few MonoBehavious (the Unity class that we need to inhert from in order to attach code to GameObjects). The entity classes have almost no behavious as well. It’s all centralized on the utility classes.
So, if i want to find the a file path, insted of doing file.GetPath(), i will go FileSystemUtil.GetFilePath(file). This may seem more complicated than the OOP approach, but it’s acctually a lot simpler to maintain and to change. Because if i want a certain type of file (like image files, for example) to have its path handled differently, i would just call FileSystemUtil.GetImageFilePath(file). If i were on the OOP approach, i would have to put an if inside the GetPath method to make this work – or even worse: override the method on the ImageFile class. When you have overrides, you just make debugging and bug tracking much more difficult than already is.
This is a completelly different approach than the previous prototype of the game – if you don’t know what i am talking about, see __init__ . In the first prototype i did all OOP. And it was just a mess. Maybe i am just too dumb and can’t write good code, but nevertheless, this new approach is working much better.
If you have worked with Unity before you may be wondering: if you don’t have inheritance, how do you talk with Unity, handles specific properties and stuff like that.
Let me use the Program class to aswer that question. Every program has a very different set of funcionallity and properties. In order to maintain the Program entity without inheritance, what i do is create additional classes that have these specific properties. So, for example, the Open program (the program that opens files on the game) needs to know two prefabs. But the OpenRunner (the class that actually runs the behavious of the Open program) has no base class, nor is a MonoBehaviour, so how did i manage to get the reference for these two prefabs?
I created an OpenAdicionalData class that is a ScriptableObject (the class that we inhert from in order to create assets in Unity) and put the prefab references in there. So when the OpenRunner needs those prefabs, it goes to the GameplayReferenceHolder – the class that has references to these aditional classes – and find the references. Simple as that. Much cleaner and simpler than inheriting from a Program class and adding additional properties to it. That’s simpler because it’s very modular, i can add or remove properties from the OpenAditionalData without affecting the whole game. Without messing my ProgramList serialization. Without having to write a custom inspector for the Open program and, best of all, avoiding inheritance.
You now maybe asking yourself why do i want to avoid inheritance so much. That’s because when you have inheritance, your objects have multiple sizes, have different properties, different virtual tables, may or may not override base methods, etc. So the compiler has to do a lot more work figuring out casting, dynamic dispatch, and a lot of other issues.
And this is not even considering the mess of debugging derived methods, problems with stack traces with no useful data and so on.
And, specifically for working with Unity: Unity do NOT serialize inheritance for non-UnityEngine.Object classes. So you either inherts from ScriptableObject/MonoBehaviours or you don’t serialize child classes.
Another point that i want to explain is how do i call the programs behavious if they do NOT inhert from Program.
If the player types in “open file.txt” what i do is i first interpret this command, take out the “open” (the name of the program) and “file.txt” (the parameter). After i have that, i will iterate though my list of available programs matching the name of the program with the name in the element of the array.
So is something like:
for (int i = 0; i < availablePrograms.Length; i++)
if (availablePrograms[i].Command == commandName)
program = availablePrograms[i];
Once i have the program entity that represents which program the player wants to run, i just do a switch-case using the ProgramType enum (that has all possible program types – Open, Cd, Cypher, Clear, etc) and call the respective runner (the actual behaviour of the program):
And the OpenRunner runs the routine of the open program.
I really think this is much simple and easy to scale than OOP. So far it has been great.
If you’ve read this far, thank you. I hope you take something out of this.
If you have something to say, just leave a comment and i’ll reply. Or you can send me an email in the contact page.