قالب وردپرس درنا توس
Home / IOS Development / Game Development with Device: Lessons learned while building Linia

Game Development with Device: Lessons learned while building Linia



The last months have been intense. Among the many things that happened and kept me from writing, I got married and released the first game I've ever worked with, Linia. Although I'm very fond of both, I'm talking about Linia here and about how we utilize the power of Unity could build their own tools to increase level creation and get into a working game core in just a few weeks.

A few words about Linia

Linia is a 2D puzzle for iOS and Android with a simple and original gameplay: you must find a particular sequence of colors by tracing a line of shapes that rotate, scale and move around on the screen. According to the reviews, it is fun and challenging – just what we were aiming for. Check the video below for a quick preview.

Marco and I worked on the game at leisure, mostly on weekends. We only met personally on some occasions to define the main environments and to sort out the most difficult pieces in the develompent. We needed to be very focused due to our time limits and – thanks to the strength of the device – we ended up with a stable engine for the game in just over 1 month. I have to admit that we had not expected such a solid result so fast.

The game was very well received: We were featured in most Apple App Stores with a very nice editor's note

"Minimalist puzzlers are all rage and this means you have to go up if you want to stand out out. Luckily, Linia is packed with more than any exceptional tricks. When you look at orbs pulse, spin and spin in fascinating patterns, it's hard to find the right color sequence. Then you have to cut it through in a clean motion, which means that you must be accurate. It's not easy, but it's certainly cool. "

and many websites considered the game. Macstories, AppAdvice, stuffTV, GamingCypher are just some of them.

We ended up being very pleased with the final result, so we decided that the team deserved a name … And that was how Black Robot Games was born. Let's get into the technical issues now.

Main Structure, Scenes Directors and Leaders

The main structure of the game was one of the most important parts of our work. We wanted to achieve a very simple, yet strong logic that would enable us to present and manage the scenes. The first choice we had to make was to use a stage for each level or build a monolithic scene where all levels were presented. We picked the first one because we realized that the new Sceneman that comes with Unity is simply amazing! You can actually add more than one scene to the hierarchy and define if you want a new scene to replace the current, or just add a new to scenery hierarchy. That was exactly what we were looking for. We created a main scene where we placed all the shared items (like the main camera) and depending on the user's actions, we created other scenes for the hierarchy. As you can see, each "viewing" of the game is another scene, and it is presented or removed from the screen as needed.

Handling Scenes

As you read later, we used a very strict approach when deciding on the role of each component. We wrote a scene director on the top of Unity Scene Manager, and we assigned it to be the only object that could add a scene to the hierarchy. With this rule in place, it has been very easy to follow the game flow and troubleshoot the user navigation. Despite personal preferences, we used a singleton structure for our executives that allow us to move from one scene to the other with just one line of code, called anywhere in the game:

  SceneDirector.Instance.GoToIntro ();

Internally, the scene director presents an overlay as father screen to black, captures the new scene and fades it in when the new scene is ready. The action of loading and unloading the scenes is still responsible for the default SceneManager :

    Private Idle ShowScene (Strict SceneName) {
if (currentScene! = sceneName) {
if (currentScene! = null) {
SceneManager.UnloadScene (currentScene);
}
currentScene = sceneName;
SceneManager.LoadScene (sceneName, LoadSceneMode.Additive);
}
}

A trick we used to let the scene director know when a new scene was ready was to manually trigger a method on the scene director from Start or Awake the functions of the loaded scene.

Note: We're honest, we are not very happy with how we control this, so if you have a better solution to share the ready state of a scene, just let us know : P

  void Start () {
SceneDirector.Instance.SceneReady ("intro")
...

Distribution of Responsibility with Leaders

If you have written code for a while, you know how easy (and dangerous) is to spaghetti-your code, especially when working with a new tool. A strict definition of how to distribute responsibilities has helped us avoid it. Along with the stage director we already mentioned, here are some of the other players in the game core:

LevelsManager: This is what you would otherwise call "Game Manager" but we wanted to give it a very specific name, considering it is only responsible for initialization and tracking of the levels. From this controller we get to know a number of things: playable levels, locked, the "next" level of game progression, and information about user-friendly advances. It also restores user status from iCloud or Google Play.

EventsManager: This boss triggers some important events inside the game. A simple pub subscription based on c # delegates: You can subscribe to an event to start actions when the event is triggered.

Here's a quick example:

    void Start () {
EventsManager.Instance.OnGameCenterLoggedIn + = HandleGameCenterLogin;

AudioManager: We adopted the same rigorous approach when deciding how to play sounds, so the only item responsible for the sounds is AudioManager. It includes audio sources, it communicates with the user's preferences to mute / deactivate game effects and it plays audio from sources. How to play sound effects:

  AudioManager.Instance.playFX (clip);

PrefsManager: This keeps track of user preferences and local data and communicates with other actors to trigger any change / update.

Now we have written some other actors – each with a well-defined role, but the key to taking care of is that by setting things up properly we ended up knowing exactly which leader to use for each new action we created during the entire production.

Levels, Levels, and Levels: Enter Your Custom Tools or (Slowly) Failure

To be a pay-to-play game, Linia needed a large number of levels to be considered by the casual mobile gaming audience. Therefore, we decided that the starting point would be 80 levels. Level design and construction takes time and had to start over 80 times, would have been a massive time sync. We wanted to set the environment so that we could reduce repetitive tasks to a minimum.

Fortunately, Unity's editor is extremely editable (pun intended), and you can easily build a set of tools to suit your needs.

Each level in Linia is filled with animated shapes – therefore we started creating the animations using the integrated Unity animator. Unfortunately, we immediately realized that this tool can not be easily reused without copying thousands of animator controllers and animations around. In addition, we needed a better control of the movements in our figures.

View this level from the scene editor:

To achieve animations of the top and bottom quarters, we have created a waypoint transition animation. You can easily see the 3 red dots attached to the squares. These items are not part of the default Unity editor.

To build this tool, we pulled into Unity's editor (because you're very cool) with features like OnDrawGizmos . Each square has 3 special game objects attached as a child. The script that we have created (called KeypointsTween ) simply reads the location of its waypoint children, draws the dots and lines and animates the form through these waypoints.

Here is the code:

    Invalid OnDrawGizmos () {
if (editMode) {
drawEditor ();
}
}

private invalid drawEditor () {
if (! Application.isPlaying) {
keypoints = GetKeypoints ();
}

Vector3 previousPoint = new Vector3 ();

if (keypoints.Length> 0) {
for (int i = 0; in < keypoints.Length; i++){
        Gizmos.color = gizmoColor;
        Gizmos.DrawWireSphere(keypoints[i],0.1f);

        if (i > 0) {
Gizmos.color = new color (1.0f, 1.0f, 1.0f, 0.5f);
Gizmos.DrawLine (previous point, keypoints [i]);
}

previous point = keypoints [i];
}
}
}

The feature OnDrawGizmos is called each time the systems need to draw the gizmos, so we can use this feature to draw our custom editing elements. The feature drawEditor lists the key points associated with the shape and draws a red sphere in each point position and a line connecting a point with the previous point using DrawWireSphere and DrawLine functions. We disable the gizmies by setting the variable editMode to false. This helped us prevent having to deal with a crowded editor.

The main points are also used to create transitions in the Update function using Vector3.Lerp with custom curves for smooth animations.

  void Update () {

if (! temporarily stopped) {
if (delay <= 0) {
floating distance = Vector3.Distance (keypoints [currentPoint] transform position);
if (mode == "inout") {
transform.position = Vector3.Lerp (transform .position, keypoints [currentPoint] Time.deltaTime * speed);
} other if (mode == "out") {
transform.position = Vector3.Lerp (transform.position, keypoints [currentPoint] EasingFunctions.easeOut (Time.deltaTime, 1) * speed);
} Other if (mode == "i") {
transform.position = Vector3.Lerp (transform.position, keypoints [currentPoint] EasingFunctions.easeIn (Time.deltaTime, 1) * speed);
}else{
transform.position = Vector3.MoveTowards (transform .position, keypoints [currentPoint] Time.deltaTime * speed);
}

This is how the inspector looks like KeypointsTween script:

We separated editing settings from game settings ]. Within the edit settings, you can define the color of the gizmo (again useful in crowded levels) and disable only the gizmo for the current object. In the playback settings, there are some interesting options for the animations, such as a delay time before the animation begins, and a loop setting. We can also define the transition curve mode (a tooltip shows possible values: linear, inout, in and out).

To set up the inspector in this way, we used some special keywords ( Header and Tooltip ) in the class variable definition of:


 public class KeypointsTween: MonoBehaviour {

private int currentPoint = 0;
private vector3 [] keywords;
private bool isReversed = false;

[Header("EDITOR SETTINGS")]
Public Color gizmoColor = Color.red;
public bool editMode = true;

[Header("PLAY SETTINGS")]
public bool paused = false;
public float delay = 0.0f;
public air velocity = 1.0f;
public bool repeat = false;
public float minDistance = 0.1f;
[Tooltip("linear, inout, in or out")]
public string mode = "linear";

All the animations that we have created have their own custom elements for the Unity Editor. We ended up with a complete set of scripts to achieve rotation, scaling, translation, color change and many other effects that have hugely simplified levels of design work.

Conclusions

As you may have already guessed, we think Unity is a great piece of software. Truth is being said, we have just scrapped the surface of its potential, and we are still studying it while we work on other very interesting projects with Black Robot Games. We could not be more excited about what's next!

What do you think about it? Have you tried Linia? Let's talk to Twitter let me know!  :)




Source link