From time to time, its handy or necessary to communicate with the underlying OS (Android, iOS, Windows, etc) from Unity. You may want to integrate a third party Android SDK, or you may want to access device data that is exposed by the OS, but is not exposed by Unity. For example, I mentioned in a previous post on save data that Unity exposes a single data path variable, whereas Android actually has two, one for internal storage and one for external (such as an SD card). You can write a simple plugin that gives you access to both pieces of data (which is exactly what we’ll do here).
Unity, as a component-based game engine, strongly encourages you to use “components” attached to “game objects” as the basis for your game. The starter documentation points you towards components, and all new scripts you create in Unity automatically inherit from Monobehaviour – which is the class you inherit from in Unity to create a component.
While it is certainly easy to use Monobehaviours, it isn’t always the best solution: you could also just create a class that doesn’t inherit from anything. Before making that decision, you ought to understand what Monobehaviours offer you over a plain old class. That’s what this post is all about.
As a programmer of sometimes complex systems, you may find that it is valuable to keep your code as simple as possible in order to reduce the potential for error or madness as a codebase grows. One of my favorite “comfort” mechanisms for maintaining clean and understandable code is encapsulation. In a nutshell, encapsulation attempts to reduce code complexity by keeping the majority of a class’s inner workings concealed from other classes. There are a number of reasons that this is quite effective:
- If you are debugging an error in a class, you will have the comfort and luxury of knowing that outside classes are not unintentionally affecting the class you are debugging. Let’s say you have a bug where a particular variable is sometimes giving the wrong value. In a badly encapsulated class, maybe that variable is public, so it is possible that any other class in your code base is changing that value. In a well encapsulated class, that variable is private, which means that the variables value is only being changed internally. The possible sources of error are greatly reduced.
- Similarly, exposing only needed functions to outside classes means that you stop other classes from changing the state of your class in unexpected ways.
- The fewer paths available to classes to communicate, the easier it will be to do refactoring in the future without having to make changes everywhere in the system.
- Only mark methods and variables as “public” if they ought to be visible for outside classes to access. If it is unclear whether a method needs to be public or private, make it private until a compelling reason appears for it to be public. It is easier to change from private to public than the other way around.
- Make the collection of functions and variables that you expose to the public (the “interface”) as coherent, easy to understand, and consistent as possible (relates to abstraction mainly).
- It is best to use accessor methods for variables as opposed to exposing the variables themselves publicly. If you want to change the type or behavior of a variable, this makes it much easier. Also, what if you want other behavior to occur every time you change a variables value? It isn’t possible unless you have accessors.
This post is mainly about that thirdbullet point. In Unity, the public and private keywords implicitly define whether a variable appears in the inspector or not, which at times, can go against the encapsulation goals of the class. For example, you may want to expose a variable so a designer can tweak the initial value, but that doesn’t necessarily mean you want other parts of the code to be able to mess with it! Luckily, there are some mechanisms built into Unity that allows you to have more control over this.
Recently, I was working on some editor tools for Unity that required database access and a simple web frontend to add, delete, and modify data in the database. This is possible with a MySQL backend and some sort of frontend web page. But considering the workflow for the team, I knew that I didn’t have enough time to make the frontend pretty and very usable. My team would have to learn a different interface/tool to modify the data in the database. It would probably have bugs. And what if I needed to give access to someone outside the company? Then my tool suddenly needs to deal with user authentication. On top of that, the database would need to be stored in a reliable network location for both internal and external use – what a mess.
But then it hit me! Maybe I could make use of Google’s availability, reliability, and excellent user interface to do exactly what I was looking for – which was basically to have an organized and secure collection of data be consumed by my game.
This post will explore the potential benefits of using Google’s architecture. Then, to get started, I’ll explain how I set up Google authentication to access spreadsheets, documents, etc. from Unity.
I’d say that most games have a need to save player progress and stats between play sessions; it’s pretty vital. Unity provides a PlayerPrefs class to save/load int, float, and string data types into a giant key/value pair database between games. This is handy, but not ideal in all cases. Sometimes, you want to save several individual files – maybe one file per profile, or separate files for audio settings, engine settings, etc.
When you want to save data between play sessions, you need to have a path to a “safe” location that is always available. Unity provides a variable called Application.persistentDataPath that returns a directory path to just such a location. It returns a different location for each platform – PC, iOS, Android, etc.
However, the way that Android handles data storage can cause some headaches when working with Unity’s persistentDataPath variable. In this article, I’ll explain how data storage works on Android, and why you need to be careful with persistentDataPath as a result.
Though Unity’s managed memory system should (theoretically) reduce the burden on you, the intrepid game developer, there is still an awful lot to know and be aware of, especially when it comes to mobile development. Most PC titles made with Unity don’t need to worry about running out of memory because modern PCs have a bit to spare and can rely on virtual memory if pushed that far. On mobile devices, however, even a modestly populated Unity scene can start to crash under the stress of a few large textures and sound effects.
This was the position I found myself in recently, and I spent a chunk of time researching the topic. There wasn’t much documentation, and what I did find was scattered among several pages of documentation and questions on UnityAnswers. “Managed memory” sounds like your memory is automatically managed for you, but that isn’t the whole story; managed memory takes its cues from your actions in code to decide if it should allocate or free some memory. Doing the wrong things in your code can cause heaps of trouble and cause unneeded memory to stick around and take up space.
In this article, I’ll go over the different types of memory a Unity game uses, and some tips to optimize your usage in each area. I’ll also discuss how you can ensure that you only have the minimum of assets loaded at any one time, and how you can achieve dynamic loading/unloading of assets during gameplay.
As you may know, the NDK allows you to develop Android apps in C or C++, which allows you to reuse existing code, or write cross-platform code with relative ease. One piece of the NDK puzzle that was difficult to wrap my head around was how exactly my NDK app could receive Android lifecycle events if those calls are going through Java. Well, it turns out there are three distinct ways (that I’m aware of) to solve this problem, which will free you up a bit to focus on your app code instead of the inner-workings of the Android OS.
Those three methods are: using JNI through a Java Activity, using the NativeActivity class directly, and using the NativeActivity class indirectly through the “android_native_app_glue” library.
ADB (Android Debug Bridge) is an essential tool provided by the Android SDK that makes it possible to push and pull data from either a real device or a virtual device, as well as view logs and crash data.
This document won’t explain every facet of ADB (look here for that), but I will go over the commands that I’ve found most useful over the last year and change that I’ve been using the system for game development.
A couple weeks ago, I started fiddling about with Android in hopes of write some cross-platform code (Android + iOS) for a game engine project I’ve been tossing around. Today, I’m finally getting things making sense, so I’ll be creating a series of posts chronicling all the stuff I’m learning as I go, which will hopefully help others in the future.
In this first post, I’m going to simply walk through my setting up of the Android SDK and NDK. This is a topic that’s been done to death, and is explained quite well in Google’s own documentation. However, I found Google’s documentation lacking in many of the pitfalls that can be encountered when adding the NDK to the SDK. If setting this stuff up were an adventure game, there would be several dead ends right in the middle that force you to start from the beginning.