Examples of CanvasGroup application in Unity.

Today I would like to tell you about one component from GUI library, ignorance of which created many problems in several projects, which resulted in big code, much work, and, as a result, many errors. CanvasGroup. If you already know that such a component exists, you can get comprehensive information about it from documentation and freely apply your knowledge.

I would like to describe all settings of “CanvasGroup” in detail and with examples, so that you have a visual copy of them and can invoke it when needed.

The main purpose of “CanvasGroup” is management of group of UI elements which are below in hierarchy (“inside” CanvasGroup). These options are also applied to the “GameObject” itself which contains “CanvasGroup”component.

For example, we want to manage all elements in a window, group of buttons or group of images at once.

“CanvasGroup” settings

As you can see in the picture above, “CanvasGroup” contains only four settings which purposes you can easily guess from their names. However let’s examine them in detail:


1. Alpha.

Control of transparency of group of UI elements. Changes transparency of  both UI element on which CanvasGroup component is located, and all affiliated UI elements.

One of application variants – make group of objects translucent, without changing colour of each object:

Changing of transparency of UI elements group

Another one widely applied variant – effect of FadeOut and effect FadeIn of a window. Without CanvasGroup component, you would need to get all UI elements located in a window and to change alpha parameter of colour for each found element (for example using CrossFadeAlpha method). Thus, you would still need to do more actions, because some UI-elements in a window can be translucent, and after applying fade out effect by setting alpha to zero, you would need to restore initial alpha parameter at the end. Thus, you would need to save all alpha parameters for each UI-element, to apply effect, and to restore all alpha parameters for each UI-element at the end. Much make-work.

CanvasGroup simplifies the process of creation of these effects.

Fade Out and Fade In effects

I wrote  two tweens which implement fade out (FadeOutTween) and fade in (FadeInTween) effects with the help of CanvasGroup, and which can be used “in one line”:

public void OnGUI()
{
    if (GUILayout.Button("Fade Out/In"))
    {
         TweenSequence.Run(
            () => FadeOutTween.Run(Panel, Duration),
            () => FadeInTween.Run(Panel, Duration).SetDelay(0.25f));
    }
}

2. Interactable.

Makes a group of UI-elements inaccessible for interaction (equivalent of enable/disable from other UI-frameworks). For example, you can make a set of buttons or all elements in a window irresponsive to click.

Making a group of button inaccessible for input

3. Blocks Raycasts.

Blocks all user’s actions over UI-elements which are realized by “Raycasts”. For example, we display a window over another one, and if the overlying window does not block the underlaying ony on size, then the possibility to interact with UI-elements of the underlaying window remains. We can use “BlocksRaycast” parameter to block this possibility  .

Blocking of possibility to interact with UI elements of underlying window

The difference from “Interactable” parameter – “Interactable” makes all UI-elements “disabled”, and if UI-element has a different form  for “disabled” condition, it changes the form for “disabled”. “BlockRaycasts” simply blocks all user’s input without changing the form of elements.

4. Ignore Parent Groups.

Ignore all CanvaGroup settings located upwards in hierarchy of UI-elements (“reset” of all CanvasGroup settings).

One button uses Ingore Parent Group settings

CanvasGroup is a useful component which description needs to be included in all uGUI basic lessons, so that the other people do not repeat my thorny path, but make a small step towards ideal code and world.

All examples can be taken at github.

Примеры использования CanvasGroup в Unity.

Сегодня я хочу рассказать об одной компоненте из библиотеки uGUI, незнание которой породило мной ряд “костылей” в нескольких проектах, что привело к большему количеству кода, работы, и как следствие, ошибок.

Компонента – CanvasGroup.

Если знать про её существование заранее, то исчерпывающую информацию можно получить из документации и спокойно применять полученные знания.

Я же коснусь всех настроек “CanvasGroup” чуть подробнее и с примерами, дабы в памяти остался визуальный слепок и легко извлекся в последствии, когда понадобится.

Основное предназначение “CanvasGroup” – это управление группой UI-элементов, которые находятся ниже по иерархии (“внутри” CanvasGroup). Так же, эти настройки распространяются на сам “GameObject”, содержащий компоненту “CanvasGroup”.
Например, мы хотим управлять сразу всеми элементами в окне, группой кнопок или группой картинок.

Настройки “CanvasGroup”

Как видно из картинки выше, “CanvasGroup” содержит всего четыре настройки, о назначении которых можно легко догадаться из названий. Однако, пройдемся подробнее:

1. Alpha.

Управление прозрачностью группы UI-элементов. Изменяет прозрачность как корневого UI-элемента, на котором находится компонента CanvasGroup, так и всех дочерних UI-элементов.

Один из сценариев использования – сделать группу объектов полупрозрачными, не изменяя цвет каждого объекта:

Меняем прозрачность группы UI-элементов

Continue reading “Примеры использования CanvasGroup в Unity.”

Отчет за март 2015г

Каждый месяц я пишу отчет о том, чем я занимался в прошлом месяце и каких результатов достиг. Добро пожаловать в отчет за март.

1. Фриланс.

Заработком на жизнь я не был сильно занят. Из трех проектов прошлых месяцев два были завершен, теперь работаю надо последним оставшимся. Параллельно, не спеша ищу себе что-нибудь новое и интересное.

Примерно вот так

Continue reading “Отчет за март 2015г”

Methods of organizing the interaction between scripts in Unity3D.

Introduction.

Even average Unity3D project is very quickly filled with a large number of various scripts and there is a question of interaction of these scripts with each other.

This article offers some various approaches to organization of such interactions from simple to advanced and describes to what problems can lead each of approaches, and will also offer ways of solution of these problems.

Approach 1. Appointment through Unity3D editor.

Let it be in our project are two scripts. First scratch is responsible for addition of points in game, and second for user interface, which displays number of scored points on game screen.

We will call both scripts – managers: ScoresManager and HUDManager.

In what way manager, who is responsible for screen menu, can receive current quantity of points from manager, who is responsible for addition of points?

It is supposed, that in hierarchy of objects (Hierarchy) of a scene there are two objects, for one of which ScoresManager script is appointed, and for other – HUDManager script.

One of approaches contains the following principle:

In UIManager script we define a variable type ScoresManager:

public class HUDManager : MonoBehaviour
{
    public ScoresManager ScoresManager;
}

But ScoresManager variable needs to be initialized by instance of a class. For this we will choose object in hierarchy of objects, to which HUDManager script is appointed and in object settings we will see ScoresManager variable with None value.

Further, from a window of hierarchy we move the object, that contain ScoresManager script, in area, where None is written and we appoint it the declared variable:

Then, we have an opportunity from HUDManager code address to ScoresManager script, thus:

public class HUDManager : MonoBehaviour
{
    public ScoresManager ScoresManager;
 
    public void Update ()
    {
        ShowScores(ScoresManager.Scores);
    }
}

Everything is simple, but game isn’t limited to only gathered points, HUD can display the current lives of player, menu available actions of player, information on level and many other things. Game can total in itself tens and hundreds of various scripts, that need to receive information from each other.

To obtain data from other script in one script we should describe every time a variable in one script and to appoint (move manually) it by means of the editor, that on its own tiresome work, which can easily forget to be made and then long to look for what of variables isn’t initialized.

If we want to edit something, rename a script, all old initialization into hierarchies of objects, connected with renamed script, will be reseted and it is necessary to appoint them again.

At the same time, such mechanism doesn’t work for prefab (prefab) – dynamic оbject сonstruction from a template. If any prefab needs to address to manager located in hierarchy of objects, you won’t be able to appoint to prefab an element from hierarchy, and it is necessary firstly to сonstruct an object from prefab and after that programmatically to appropriate an instance manager of variable to just сonstructed object. Blind work, unnecessary code, additional coherence.

Following approach solves all these problems.

Approach 2. “Singltons”.

We will apply the simplified classification of possible scripts, which are used at game construction. First type of scripts: “scripts-managers”, second: “scripts-game-objects”.

The main difference of one from others that “scripts-managers” always have the single copy in game while “scripts-game-objects” can have more instances.

Examples:

As a rule, in a single copy there are scripts which are responsible for general logic of user interface, for playing of music, tracking of level termination condition, system of tasks management, display of special effects and so on.

At the same time, scripts of game objects are in a large number of copies: each birdie from “Angry Birds” is guided by script instance of a birdie with their unique state; for any unit in strategy the unit script instance, containing its current quantity of lives, position in the field and personal purpose is constructed; behavior of five different icons is provided with various instances of the same scripts, which are responsible for this behavior.

In an example from previous step HUDManager and ScoresManager scripts always are in a single copy. For their interaction we will apply a pattern “singleton” (Singleton, same as single).

In ScoresManager class we will describe static ScoresManager property, in which a single copy of  manager of points will be stored:

public class ScoresManager : MonoBehaviour
{
   public static ScoresManager Instance { get; private set; }
   public int Scores;
}

It is also necessary to initialize Instance property with instance of a class, which is constructed by Unity3D framework. As ScoresManager the successor of MonoBehaviour is, so it participates in life cycle of all active scripts in a scene and during initialization of a script it Awake method get called. In this method we place Instance property initialization code:

public class ScoresManager : MonoBehaviour
{
	public static ScoresManager Instance { get; private set; }
	public int Scores;

	public void Awake()
	{
		Instance = this;
	}
}

Then, it is possible to use ScoresManager from other scripts as follows:

public class HUDManager : MonoBehaviour
{             
   public void Update ()
   {
      ShowScores(ScoresManager.Instance.Scores);
   }
}

Now there is no need for HUDManager to describe a ScoresManager field and to appoint it in Unity3D editor, any “script-manager” can provide access to itself through static Instance property, which will initialize as Awake.

Pluses:

  • there is no need to describe a script field and to appoint it through Unity3D editor.
  • it is possible safely to edit a code, if something falls off, the compiler will let know.
  • now it is possible to address to other “scripts-managers” from prefab, through Instance property.

Minuses:

  • approach provides access only to “scripts-managers” existing in a single copy.
  • strong coherence.

We will dwell upon last “minus”.

Let us develop game, in which there are characters (unit) and these characters can die (die).

Somewhere there is a code site, which checks whether our character died:

public class Unit : MonoBehaviour
{
    public int LifePoints;

    public void TakeDamage(int damage)
    {
        LifePoints -= damage;
        if (LifePoints <= 0)
            Die();
    }
}

How game can react on the death of character? Set of various reactions! I will give some variants:

  • it is necessary to remove the character from a game scene that he wasn’t displayed on it any more.
  • in game points for each died character are added, it is necessary to add them and to update value on screen.
  • on the special panel all characters in game are displayed, where we can choose the specific character. When the character died, we need to update the panel, or move away the character from it, or display that he is dead.
  • it is necessary to replay sound effect of death of the character.
  • it is necessary to replay visual effect of death of the character (explosion, blood splashes).
  • the system of game achievements has achievement, which counts total number of the killed characters during all the time. It is necessary to add to the counter of just died character.
  • the system of game analytics sends the fact of death of the character to external server, to us this fact is important for process tracking of the player.

Considering all above-mentioned, Die function can look as follows:

private void Die()
{
   DeleteFromScene();
   ScoresManager.Instance.OnUnitDied(this);
   LevelConditionManager.Instance.OnUnitDied(this);
   UnitsPanel.Instance.RemoveUnit(this);
   SoundsManager.Instance.PlayUnitDieSound();
   EffectsManager.Instance.PlaySmallExplosion();
   AchivementsManager.Instance.OnUnitDied(this);
   AnaliticsManager.Instance.SendUnitDiedEvent(this);
}

It turns out that the character after its death has to send out to all components, which are interested in it, this sad fact, he has to know about existence of these components and has to know that they are interested in it. Isn’t that a bit too much knowledge just for a small unit?

As game, logically, is a very linked structure, so events, occurring in other components, have interest to third, unit isn’t special here.

Examples of such events (by no means all):

  • The condition passing of level depends on number of points scored, if you have 1000 points – you have passed level (LevelConditionManager is connected with ScoresManager).
  • When we score 500 points, we reach an important stage of passing of level, it is necessary to replay a festal melody and visual effect (ScoresManager is connected with EffectsManager and SoundsManager).
  • When the character restores health, it is necessary to replay effect of treatment over the picture of the character in panel of the character (UnitsPanel is connected with EffectsManager).
  • and so on.

As a result of such communications we come to a picture similar on following, where everyone knows about everything:

Example with death of the character is squib, it is necessary to report about death (or other event) to six different components not so often. But variants, when at some event in game, function, in which there was an event, reports about it to 2-3 other components, meets pretty often on all code.

The following approach tries to solve this problem.

Approach 3. World ether (Event Aggregator).

We will enter the special EventAggregator component, main function of which is to store the list of events occurring in game.

Event in game is the functionality giving to any other component opportunity both to subscribe for itself, and to publish the fact of commission of this event. Realization of functionality of event can be any on taste of developer, it is possible to use standard solutions of language or to write own realization.

Example of simple realization of event from last example (about death of a unit):

public class UnitDiedEvent
{
    private readonly List<Action<Unit>> _callbacks = new List<Action<Unit>>(); 

    public void Subscribe(Action<Unit> callback)
    {
        _callbacks.Add(callback);
    }

    public void Publish(Unit unit)
    {
        foreach (Action<Unit> callback in _callbacks)
        callback(unit);
    }
}

We add this event to “EventAggregator”:

public class EventAggregator
{
   public static UnitDiedEvent UnitDied;
}

Now, Die function from previous example with eight lines will be transformed to function with one line of code. We don’t have need to report that the unit died to all interested components and to know about these interested. We simply publish the event fulfillment fact:

private void Die()
{
  EventAggregator.UnitDied.Publish(this);
}

And any component, to which this event is interesting, can react to it as follows (on example of manager, who is responsible for number of points scored):

public class ScoresManager : MonoBehaviour
{
    public int Scores;

    public void Awake()
    {
        EventAggregator.UnitDied.Subscribe(OnUnitDied);
    }

    private void OnUnitDied(Unit unit)
    {
        Scores += CalculateScores(unit);
    }	
}

In Awake function manager subscribes for event and delegate who is responsible for processing of this event. The handler of event accepts an instance of the dead unit as parameter and adds quantity of points depending on type of this unit.

In the same way, all other components, to whom the event of unit death is interesting, can be signed for it and process when the event occurs.

As a result, the chart of communications between components when everyone component knew about each other, turns into the chart when components know only about events which occur in game (only about interesting them events), but thei don’t care, from where these events came. The new chart will look as follows:

I like other interpretation: suppose the “EventAggregator” rectangle stretched extensively and took in itself all other rectangles, turned into world borders. In my head on this chart “EventAggregator” in general is absent. “EventAggregator” it simply the world of game, certain “game air” where various parts of game shout “Hey, people! Unit so-and-so died!”, and all listen to air and if some of the heard events interests them, they will react to it. Thus, there are no communications, each component is independent.

If I am a component and I am responsible for publication of some event, I shout in air that this died, this received level, shell crashed into the tank. And I don’t care if somebody cares. Perhaps, nobody listens to this event now, and it can be one hundred other objects is signed on it. I, as author of event, don’t care, I know nothing about them and I don’t want to know.

Such approach allows to enter easily new functionality without change old. Let’s say we decided to add system of achievements to ready game. We create new to a component system of achievements and subscribe for all interesting us events. No other code changes. It isn’t necessary to go on other components and cause from them system of achievements and tell it to count my event. Besides, everyone, who publish events in the world, knows nothing about system of achievements, even about the fact of its existence.

Remark:

Saying that no other code changes, of course I dissemble a little bit. It can appear so that system of achievements interest events, which earlier simply weren’t published in game because any other system didn’t interest before. And in this case, to us it will be necessary to decide what new events to add to game and who will publish them. But in ideal game are already all possible events, also air is filled with them in spades.

Pluses:

– not coherence of components, it’s suffice just to publish the event and it doesn’t matter who interested in it.

– not coherence of components, I simply subscribe for necessary to me events.

– it is possible to add separate modules without change in the existing functionality.

Minuses:

– it is necessary constantly to describe new events and add them to the world.

– violation of functional atomicity.

We will explore the last minus in full detail:

Put the case we have “ObjectA” object, in which «MethodA» method get called. «MethodA» method consists of three steps and get called in itself three other methods, which carry out these steps consistently (“MethodA1”, “MethodA2” and “MethodA3”). In second «MethodA2» method there is a publication of some event. And there is a following: everyone, who is signed on this event, will start  processing it, carrying out some logic. In this logic there can be also a publication of other events, which processing can also lead to publication of new events and so on. Publications tree and reaction in some cases can expand very strongly. It is so difficult to tweak such long chains.

But the most terrible problem, which can occur here, it when one of chain branches brings back into “ObjectA” and starts processing event by activation of some other «MethodB» method. It turns out that «MethodA» method haven’t executed all steps yet, as it was interrupted on the second step, and comprises now not valid state (in 1 and 2 step we changed a condition of object, but the last change of step 3 wasn’t made yet) and thus “MethodB” in the same object begins to carry out, having such not valid state. Such situations generate mistakes, and very difficult to recognise, lead to that it is necessary to control an activation methods order and publication of events, when, according to the logic, there is no need to do it and enter additional complexity, which it would be desirable to avoid.

Decision point:

It’s not difficult to solve the described problem, it is enough to add functionality of postponed reaction to event. As simple realization of such functionality we can get storage, in which we will put the occurred events. When the event occurred, we don’t carry out it immediately, and simply keep somewhere at ourselves. And at the time of occurrence run queue of functionality some components in game (in Update method, for example) we check for existence of occurred events and processing if there are such events.

Thus, by «MethodA» method execution there is no its interruption, and the published event everyone, who are interested in it, write down to their special storage. And only after they  have their turn, they will get an event from storage and process it. At this moment all “MethodA” will be complete and “ObjectA” will have a valid state.

Conclusion.

Computer game is difficult structure with a large number of components, which closely interact with each other. It is possible to construct a set of mechanisms of organization of this interaction, I prefer the mechanism, described by myself, based on events and to which I came in the evolutionary way overcoming difficulties. I hope somebody will also like it and my article will make things clear and will be useful.

Отчет за февраль 2015г.

Всем привет!

Каждый месяц я пишу отчеты о том, чем я занимался и настало время расквитаться за ушедший февраль. Месяц был наполнен позитивными и положительными движениями: у меня появился новый SSD и рабочий компьютер вернулся в строй, нагрузка по работе немного ослабла, начался прогресс по плагинам и блогу, дружно приступили к формированию сообщества разработчиков игр и я начал перестраивать свои рабочие процессы. А теперь об этом и другом по-подробнее.

1.Фриланс.

Конечно же, первый пункт того, чем я занимался – это фриланс. Он занимает большую часть моего времени и мне очень нравится делать эту работу. Занимался двумя проектами из прошлого месяца и разрабатывал прототип нового. Показать картинки не могу, да и прототипы – они на кубиках, но разработка выглядит примерно так:

В коворкинге кипит работа

Continue reading “Отчет за февраль 2015г.”

Эффекты Shadow и Outline в Unity GUI.

Один из способов сделать текст с тенью – это отобразить текст два раза, второй раз с небольшим смещением и с цветом тени позади первого. Такое решение часто используют, если графическая библиотека не дает собственных механизмов отображения теней.

Неудобство такого подхода в том, что на каждый текст с эффектом тени нужно создавать два объекта и если текст динамический, то следить за тем, чтобы текст обновлялся в обоих объектах.

Простой текст и текст с тенью, созданной вручную

Unity GUI, доступная с версии 4.6, позволяет на текст наложить два эффекта: «Shadow» и «Outline». Как можно догадаться из названия – первый добавляет тень, второй – обводку.

Continue reading “Эффекты Shadow и Outline в Unity GUI.”

Shadow and Outline effects in Unity GUI.

One of the ways to create a text with shadow is displaying the text two times, the second time – with a small shift and shadow colour behind the first one. This solution is widely used, if the graphic library does not provide own means for display of shadows.

Such a solution is inconvenient though, because you need to create two objects for each text with shadow effect, and if the text is dynamic, then you have to ensure updating of text in both objects.

Simple text and text with shadow created manually

Unity GUI available from 4.6 version, allows to match two effects on the text: «Shadow» and «Outline». As you can guess from the names – the first effect adds a shadow and the second one – outline.

But these effects can be applied not only to the text (Text), but also to the image (Image). And since the text and the image are key blocks of all other UI elements, these effects can be applied to any other UI element as well. For example to the button:

Buttons with Shadow and Outline effects

If we look in the initial code of Shadow and Outline components, we will see that these components, in a fact, do the same thing: Shadow creates a copy of UI component’s geometry and shifts it some pixels aside; Outline creates four copies and shifts them in four opposite directions on x and y axes which provide the outline effect.

Let’s ponder what else we can achieve using these components: Simple outline for the selected objects. You do not need to draw two conditions for each image or handle the colour, you can simply add Outline effect and enable it for the selected object.


Extracting of image by enabling Outline component

Shadows of objects which “go beyond” further than usual shadows of UI elements.

For example, you can display some planes and their shadows on the ground, and imitate sun motion by changing one parameter. (Of course you won’t create game mechanism on GUI elements, but if you need only one simple scene, then why not).

Planes shadows and their shift over time  

Effect of double objects.

For example, you want to apply doubling effect on HUD when your hero is heavily hit or drinks much alcohol. This simply script, applied to all UI objects of the window will help you to achieve the necessary result.

Doubling effect in UI element

You are welcome to write your own ideas on using Shadow, Outline and other effects to the maximum extent in comments.

Отчет за январь 2015г

Всем привет!

Добро пожаловать в мой первый месячный отчет в этом году.
Отчет будет маленький: цели я сформулировал в середине января, вместо легкого фриланса пришлось много работать и в конце месяца у меня поломался SSD, что вынудило две недели пытаться работать на MacBook Air и было это не продуктивно.
Все перечисленные события привели к не большому прогрессу за январь.

1. Фриланс.

Почти все проекты, по которым я вел переговоры в декабре, в январе выстрелили одновременно. Фрилансерские будни. Пришлось от нескольких отказаться и взять на себя работу над тремя оставшимися. Они же и съели все мое время. Фрилансил много, активно, делал разное и интересное.

Разработка одного из проектов

В феврале планирую разгрузиться. Буду доделывать старые проекты, а новые постараюсь не брать.

Continue reading “Отчет за январь 2015г”

Цели на 2015 год

Цели на 2015 год

Год назад я начал публично озвучивать свои цели и писать месячные отчеты о результатах.

Первое полугодие прошло в очень активном режиме и мне много чего удалось достичь, к осени накопилась усталость и появилось ощущение, которое программисты любят обзывать словом “перегорел”.

Декабрь я размышлял о будущем и пытался сформулировать цели на ближайший год и 10 лет. Цели на 10 лет оказались стандартными а-ля домик на берегу моря, семья, выход на пенсию в 45 лет, финансовая независимость. А вот цели на год оказались более конкретными и именно они должны помочь мне сделать шаг к десятилетним.

Обдумав различную деятельность, которой я собираюсь заниматься в новом году, сформулировал для себя ряд целей и постарался выразить их в цифрах.

1. Заработок на жизнь фрилансом.
В 2015 году я так же, как и в двух предыдущих, буду зарабатывать на существование путем самостоятельного поиска проектов на фриланс-биржах, переговоров с заказчиками и исполнения их желаний, не выходящих за рамки разработки игр на “движке” Unity.

 

Цель: 

Continue reading “Цели на 2015 год”

Отчет за август 2014г

Всем привет!

В этом блоге я пишу про свои попытки создать источники пассивных доходов, разрабатывая игры на Unity. Настало время подвести итоги августа и поставить цели на следующий месяц.

Часть августа у меня продолжилась небольшими разъездами, зато вторую половину я провел в спокойствие и отдыхе от активных предыдущих месяцев, вернулся в коворкинг NETNATION.RU и мне удалось продуктивно поработать.

Мое рабочее место в коворкинге

Достижения августа:

Continue reading “Отчет за август 2014г”