Страницы

четверг, 31 августа 2017 г.

Опасный DontDestroyOnLoad

DontDestroyOnLoad позволяет компоненте пережить загрузку/перезагрузку сцены. По сути они живы пока жив процесс приложения. Порой, их становится все больше компонент (по сути почти все что работает с нативом - хелпер крашлитики, загрузчик obb, нотификации, дзендеск и др.). Подводный камень DontDestroyOnLoad в том, что он действует на сам gameObject. Это может быть неожиданно для скриптов, которые уже висели на этом gameObject :) Чтобы подстраховаться от такой неприятной случайности можно не дергать этот метод а вместо этого писать над классом атрибут RequireComponent(typeof(DontDestroyOnLoad)).

public class DontDestroyOnLoad
{
  private void Awake()
  {
    DontDestroyOnLoad(gameObject);
  }
}

Тогда хотя бы в редакторе видно не залезая в код, каким компонентам нужен DontDestroyOnLoad - он добавится автоматически.

Решил поделиться. Хотя вообще проще сделать отдельный gameObject в старт-сцене, а на нем повесить какой-нибудь DontDestroyOnLoadController и все компоненты, которым нужно такое поведение. В этом компоненте еще можно и порядком инициализации управлять.

PS внимание, все что DontDestroyOnLoad всегда висит в памяти, а значит нужно озаботиться о том, чтобы ссылаться на как можно меньше ресурсов и выгружать их как только они стали ненужны

четверг, 15 июня 2017 г.

When Unity loads obb automagically?

When Unity loads obb automagically? When it resumes from pause. So, UnityObbDownloader plugin works because it starts it's own activity (so unity activity paused) after downloading, unity activity resumes so file is downloaded. Of course, obb loaded automagically at unity app start too.

Which code may be used to force check obb:

(javacode, you need to implement regular android activity in java to do that, you may take com.unity3d.UnityPlayerActivity as example)
unityPlayer.pause();
unityPlayer.resume();

Not working code, which you may find all over internet:

1. WWW www = WWW.LoadFromCacheOrDownload("file://" + obbPath, 0);
yield return www;

2. yeild return new WaitForSeconds(3-5);

So, people asking why it's not working for them actually may be not using UnityObbDownloader so no activity, no pause, resume, you've got the point.

It's a shame for Unity that they don't document it anywhere and didn't do a method to check for obb. Because, regular Unity game uses one activity with one UnityPlayer in it and if you download drawing your UI in game style like we all do now you have 2 options after download finish:
1. quit app. On next launch Unity will check for obb and use it
2. trigger pause-resume somehow (invisible activity or code I tested above). Weird

воскресенье, 21 мая 2017 г.

How Unity notifies about innerException: rethrow in stack

Suppose code:

public void TestCodeBelowRxChainExecutedDueExceptionHandled()
        {
            UiLogger.Trace("1");
            Observable.Return(1)
                .Select(a =>
                {
                    throw new InvalidOperationException("aa");
                    return a;
                })
                .Subscribe(
                    Actions.Empty,
                    exception => Debug.LogException(new AssertionFailedException(exception, "mmm assertion failed")); // (*)
            UiLogger.Trace("2"); // not reached if not (*)
        }

четверг, 11 мая 2017 г.

Rx in Unity with favor to synchronous code

Let's look at what rx is. Someone says it's about thinking of asynchronous operations as data flows and of rx operators as flow combining operations - join, merge, concat, transform (select/selectMany), etc. I prefer thinking that way. And yes, rx is somewhat about functional programming, it can be combined with LINQ.

суббота, 6 мая 2017 г.

воскресенье, 9 апреля 2017 г.

Top100 Unity errors

In my programming practice, I encountered many code construction errors. Most worse are hidden. All works, but bugfixing and extending functionality is a nightmare. I will write some which are funny or puzzling in my blog.

1. Created object shows "null" in debugger.

Suppose code:
public class LocationsDB : MonoBehaviour { ... }

locationsDB = new LocationsDB();
Why do you think, debugger can say us, that locationsDB is "null" ?

суббота, 21 января 2017 г.

Why I prefer longer class names even when namespace guarantees no name conflict

Suppose:

namespace Tutorial {
class CarnavalEventTutorial {...}
}


I keep Tutorial at end of class because 2 reasons:
a. you may keep some field with the same name, e.g.

public CarnavalEvent CarnavalEvent { get; private set; }

And you don't get name collision here. And no collision with class name too.

b. Suppose, that you can set that Tutorial as field of Unity component in editor. Unity editor wount show you namespaces, so you'll get 2 CarnavalEvent and can't diferentiate which one is Tutorial and which is not. More ugly example:

namespace Windows
{
    namespace Shop
    {
        public class Window : MonoBehaviour {}
    }
}

So, in Unity you'll see Window component and may decide that it's basic component. While it's not.

And one more bad thing, suppose you want to include that "Window" in code:


public class EventTracker {
private List<Window> windows;
private Windows.Shop.Window shopWindow; // you need that, again, to tell reader that it is ShopWindow. And to fix compiler error.
}

So, trying to make names short you make them longer instead :)

Minuses:
The price for that is longer names. But, again, that rule don't ask to include all the names from namespace. E.g.:

namespace Game {
namespace QuestParts {
namespace Tutorial {
class CarnavalEventGameQuestPartsTutorial {...} // not needed
}
}
}

Because, usually, you wount get CarnavalEventTutorial at different levels of namespaces.

So, the rule is: CONSIDER DUBLICATING NAME FROM ENCLOSING NAMESPACE IN CLASS NAME

вторник, 10 января 2017 г.