unity


CGI Сoffee

Protect Unity Prefabs From Changes With the ISerialization Callback Receiver Interface

Unity prefabs are awesome. They are easy to create, easy to instantiate, and with the current versions of the Unity Editor can be used to create prefab variants and even nest prefabs within prefabs, allowing you to modularize the design of systems and scene objects.

But this simplicity comes at the cost of a higher risk of screwing things up the larger your project or the team grow...

All because of this little "Apply All" Inspector button, which is both a blessing and a curse:

Unity Apply All overrides button

You know what I'm talking about. Imagine having a prefab for an object or an important interactive actor, and scattering it all over the scenes in the project, each one — with its own unique overrides for the position, variable values or even MonoBehavior component scripts attached or removed. Obviously, they are all based on the same shared prefab asset on disk, which is expected to have a certain set of initial values and components, which are then either used "as is" or are changed slightly here and there in the scenes.

The problem is, it only takes one careless press of the "Apply All" button to screw up the prefab for every single instance of that prefab in all the scenes! And chances are, you or a member of your team will eventually press this button and completely change the base prefab on disk, which all scene instances are based upon. And the more prefabs in your project, or members in your team, the higher the chance of this event happening. Sometimes stealthily, which is even worse... Thank Heavens for version control!

Unfortunately, Unity doesn't provide a way to disable this button for certain prefabs (at least I wasn't able to find a way to do so). That's why when designing my previous game, even though I was the only developer and scene builder, I decided to save myself the headache and created a custom bare-bones "ActorLoader" prefab. I would then exclusively use this prefab to place interactive instantiatiables in the scenes. Such a prefab had just a handful of fields which were meant to always be overriden and not to use base properties stored in the shared prefab: a prefab type enum (used to determine which prefab to instantiate from the Resources folder), starting Transform parameters and a couple of modifiers, all overridden right away to ensure that no changes to the base prefab asset would ever break ActorLoaders anywhere in the project. And this approach worked wonderfully.

Such "loaders" are in fact considered standard practice in the industry in contrast to scattering actual prefabs in the scenes, for a lot of reasons, which I won't list here. But this still doesn't solve the original problem of prefabs being modifiable with a press of a button!

A Solution!

Unity prefab is just a serialized object. Which means we can tap into the serialization routine and do something when Unity serializes or deserializes a prefab in the Editor. All you need to do is extend one or several MonoBehavior components attached to the prefab from the ISerializationCallbackReceiver interface, and implement a couple of methods.

Here's how I did it in my current project: inherited a component from MonoBehavior and the interface:

// See: https://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.html
public class MyClass : MonoBehaviour, ISerializationCallbackReceiver

And then implemented a custom OnBeforeSerialize() routine, which is executed right before Unity commits any changes to the serialized object, which is a prefab in our case. I've commented it to help you understand how it works. Nothing special, but gets the job done:

#region ISerializationCallbackReceiver
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
    // This can only be done inside UNITY_EDITOR since we can not check prefab status in a build!
    #if UNITY_EDITOR
    // IMPORTANT: EditorApplication checks must be done first.
    // Otherise Unity may report errors like "Objects are trying to be loaded during a domain backup"
    if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isUpdating) return;
    // Validate the type of your prefab. Useful pre-check.
    if (UnityEditor.PrefabUtility.GetPrefabAssetType(this) != UnityEditor.PrefabAssetType.Regular) return;
    // Override properties only if this is a prefab asset on disk and not any of its scene instances
    if (UnityEditor.PrefabUtility.GetPrefabInstanceHandle(this)) return;
    // Finally, re-set any fields to initial or specific values for the shared asset prefab on disk
    // This protects these fields when "Apply Override" gets called from any of prefab's scene instances
    // Example: enforce default position, rotation and scale values for the prefab
    transform.localPosition = Vector3.zero;
    transform.localRotation = Quaternion.identity;
    transform.localScale = Vector3.one;
    // Example: your variables here
    // myFloat = 1f;
    // myAssetRef = null;
    // myClassInstance.myString = "Default string";
    #endif
}

// OnAfterDeserialize can be left empty
void ISerializationCallbackReceiver.OnAfterDeserialize() { }
#endregion

As you can see, this method makes sure that each serialization call to the shared prefab asset on disk goes through a custom procedure which re-sets values for certain fields and references, and can even check whether specific components are attached to the prefab root or any of its children, and either add them if they're missing, or remove ones that shouldn't be there. This procedure is invoked any time prefab is serialized, which includes the aforementioned "Apply All" button or any other way to apply changes to the original asset.

And there you have it! With this approach each time you create a new prefab you can decide which shared asset fields and references should be protected from accidental overrides, and simply specify default/initial values for them within the ISerializationCallbackReceiver's OnBeforeSerialize() method.

Hello Again, Unity. I Missed You

Some time ago I bashed Unity Game Engine (the Editor in particular) for its instability and lots of quirks and questionable changes that took place over the years following the version 4 release of the Editor.

Fast forward to this September. I'm done with my microcontroller shenanigans and have mostly finished the Design Document for the game I talked about quite a while ago (which took a lot of planning, for I am a project manager after all).

What's the next step then? — Exactly!

Prototyping!

So I've been playing with the latest "LTS" version of the Unity Editor 2021.3.7 and...

Wow!

And I mean a good wow:

  • It's rock solid and hasn't crashed once even when I was importing some of my older code and extension methods from the previous game which I wrote in 2012-2015. And 95% of the code-base ended up being non-obsolete! I guess Unity APIs didn't change that much over the years, huh? How cool is that?
  • Package Manager is amazing. Cutting some of the features of the engine from the binary/default assembly and turning those into officially supported packages with the added convenience of being able to download and update them as you please? What a deal!
  • Unity Addressable Asset system (or "Addressables"). Nuff said. This is a feature Unity devs had been dreaming of for like a decade
  • Nested prefabs. I know, I am a slowpoke, since this is not a new feature, but there is a difference: they work. Compared to my previous experience with nested prefabs in Unity when they would crash the editor like 50% of the time when I was editing them – now we're actually usable! Huzzah!
  • Integration with Visual Studio is very solid, pleasure to work with
  • I looks the same, feels the same and despite adding new features like DOTS and burst compiler, Unity team didn't change the paradigm too much, so being a knuckle-headed brute that I am I can continue using ScriptableObjects and MonoBehaviors for most of my objects and scripts. Yay!
  • C#. Yes, C#. That C#. It's not new of course, but it's C#. It's C#, you see. It's not C or C++. It's C#. I love C#, I guess that's what I'm trying to say
  • Also, Asset Store is still a thing. And can still save hundreds of hours of development for a couple hundred bucks
  • Oh, yeah, it's still free of charge for indie devs. Just sayin'

All in all, the time has come...

Unleash the monkey coder!

monkey-coder

Short and Sweet Ring Fit Adventure Review, Some Nintendo Switch Notes, and What the Hell Happened to Unity Engine!?

hero-image

A follow-up post is available.

When I mentioned I was working on a Design Document for a third person semi-open world game to a good friend of mine several months ago, he immediately asked me whether I had played The Legend of Zelda: Breath of the Wild or Super Mario: Odyssey. Naturally, not being a Nintendo Switch owner, I had no such experience. "Get the console!" — he replied immediately — "You gotta check out what those Zelda and Mario games have to offer in the way of game mechanics and overall flow."

"Yeah, right..." — Was my instant reply — "Getting an overpriced piece of hardware powered by a microwave-grade Tegra X1 SoC with games that cost a fortune each? I'll pass."

And with that, I returned to working on the DD and various side-projects and forgot the conversation ever happened.

🎮 Click/tap here to skip my Unity rant and go straight to the Ring Fit Adventure review.

The pitiful state of the Unity game engine

By mid-February the DD was about 70% done and I considered installing a brand new version of the Unity Engine to start prototyping the basic ideas. I might dedicate a whole post to what I had to go through trying to install and use the latest version of the Unity Editor, but will keep it short for now:

unity-crash

New Unity 2019 2D Sprite Rigging and Lighting Tools

With the latest 2019.1 update Unity team have seriously upgraded the 2D tool-set of the editor:

Seems like a lot of those tools were inspired by the Rayman Legends engine. Something I was drooling over 5 years ago, hoping one day Unity would implement some of those. And they finally did!

It really makes me all warm and fuzzy inside, remembering how most of those automated 2D tools and thingies were not available when I was working on Run and Rock-it Kristie in the freeware version of Unity 4 (which back then lacked even the Sprite packaging functionality!) and had to be either developed from scratch or achieved with some cool Asset Store stuff you would need to purchase and integrate into your product.

memories

Oh, the tools... The tools...

IK and rigging with bone weighting? Check:

Manual sprite atlasing and set-up? Check (atlasing is vital for mesh batching and draw call reduction):

manual-atlasing

Sprite assembly and animation? Check:

Dynamic level-building tools? Check (via modded version of the Ferr2D asset):

Dynamic lighting? Check! — With up to 4 live vertex lights and camera-distance based light culling to make sure the game would run at stable 60 fps on iPhone 4 (heavily reliant on the amazing but now deprecated Core Framework asset by echoLogin):

It was... Fun!

You know what I also remember? I remember almost every day working on the game I felt excited and driven. It was FUN. Even when it was challenging to solve some technical issues (there were a lot of those, especially for a beginner) or work around Unity limitations or bugs, it felt truly rewarding and would give such a powerful motivation boost that I would continue working until the end.

Until the release.

manual-atlasing

But the "serious" CG movie stuff I'm doing now?.. Honestly? Meh. It's so slow and clunky compared to my previous game development experience. Everything needs to be either cached, or rendered... I'm also having some grave issues with hair simulation which I wasn't able to overcome for the last 6+ months, many operations in the "classic" world of 3D editors are still either single-threaded, unstable, or require some very specific knowledge or particular and elaborate set-up... It's almost no fun! No fun means much, much less motivation to continue.

It's a problem.

manual-atlasing

Therefore this July I will instead be checking out the latest Unity Engine and see whether most of what I'm doing right now could be ported into Unity. Starting with simulation and scene assembly and hopefully — ending up animating, rendering and applying post effects right within the Unity Editor where everything is real-time and fun! I miss the real-time aspect! Oh boy, do I miss the ability to tweak materials and see the more or less finalized render of the scene even during assembly. The ability to import assets and build "smart" prefabs (like Softimage Models, but with interactivity and intrinsic scene-aware scripting via MonoBehavior) e.t.c...

I miss you, Unity!

Unity and Unreal Engine: Real-Time Rendering VS Traditional 3DCG Rendering Approach

(Revised and updated as of June 2020)

Preamble

Before reading any further, please find the time to watch these. I promise, you won't regret it:

Now let's analyze what we just saw and make some important decisions. Let's begin with how all of this could be achieved with a "traditional" 3D CG approach and why it might not be the best path to follow in the year 2020 and up.

Linear pipeline and the One Man Crew problem

I touched upon this topic in one of my previous posts.

The "traditional" 3D CG-animated movie production pipeline is quite complicated. Not taking pre-production and animation/modeling/shading stages into consideration, it's a well-known fact that an A-grade animated film treats every camera angle as a "shot" and these shots differ a lot in requirements. Most of the time character and environment maps and even rigs would need to be tailored specifically for each one of those.

tintin-shot-to-shot-differencesShot-to-shot character shading differences in the same scene in The Adventures of Tintin (2011)

For example if a shot features a close-up of a character's face there is no need to subdivide the character's body each frame and feed it to the renderer, but it also means the facial rig needs to have more controls as well as the face probably requires an additional triangle or two and a couple of extra animation controls/blendshapes as well as displacement/normal maps for wrinkles and such.

But the worst thing is that the traditional pipeline is inherently linear.

Digital Production Pipeline

Thus you will only see pretty production-quality level images very late into the production process. Especially if you are relying on path-tracing rendering engines and lack computing power to be able to massively render out hundreds of frames. I mean, we are talking about an animated feature that runs at 24 frames per second. For a short 8-plus-minute film this translates into over 12 thousand still frames. And those aren't your straight-out-of-the-renderer beauty pictures. Each final frame is a composite of several separate render passes as well as special effects and other elements sprinkled on top.

Now imagine that at a later stage of the production you or the director decides to make adjustments. Well, shit. All of those comps you rendered out and polished in AE or Nuke? Worthless. Update your scenes, re-bake your simulations and render, render, render those passes all over again. Then comp. Then post.

Sounds fun, no?

You can imagine how much time it would take one illiterate amateur to plan and carry out all of the shots in such a manner. It would be just silly to attempt such a feat.

Therefore, the bar of what I consider acceptable given the resources available at my disposal keeps getting...

Lower.

There! I finally said it! It's called reality check, okay? It's a good thing. Admitting you have a problem is the first step towards a solution, right?

Right!?..

welcome-to-aa Oups, wrong picture

All is not lost and it's certainly not the time to give up.

Am I still going to make use of Blend Shapes to improve facial animation? Absolutely, since animation is the most important aspect of any animated film.

But am I going to do realistic fluid simulation for large bodies of water (ocean and ocean shore in my case)? No. Not any more. I'll settle for procedural Tessendorf Waves. Like in this RND I did some time ago:

Will I go over-the-top with cloth simulation for characters in all scenes? Nope. It's surprising how often you can get away with skinned or bone-rigged clothes instead of actually simulating those or even make use of real-time solvers on mid-poly meshes without even caching the results... But now I'm getting a bit ahead of myself...

Luckily, there is a way to introduce the "fun" factor back into the process!

And the contemporary off-the-shelf game engines may provide a solution.

game-engines

Run and Rock-it Kristie now completely free on the App Store

Run and rock-it Kristie, a "rayman-esque" iOS platformer was the first game I released publicly. Making the game was quite an experience, but seeing people actually play it was something else.

Less than a week after release it was featured on the European App Store as one of the best games of the week for iPad which was cool as hell.

Run and Rock-it Kristie featured on the App Store

Over half a year has passed since and I think it's time to let everyone experience the whole game for free. In the initial version only the first tour was available free of charge, and it wasn't the most exciting one of them all, which didn't quite let people truly experience the game and its mechanics. Hence, last week I finally decided to remove the only in-app purchase from the title and make it free for everyone to enjoy.

Run and Rock-it Kristie screenshots

So grab a copy of the game for yourself or your kids and have fun =)

Run and Rock-it Kristie menu

And maybe... Just maybe... Android port of the game might be in the works ;)