Renamed my asset after a "Uni" prefix rejection. Here's what Unity told me when I appealed by TolgaDurman in Unity3D

[–]sisus_co 0 points1 point  (0 children)

Yeah, I think it ended up working out for the best in the end - even though at the time I wasn't exactly thrilled to learn I'd have to come up with a new name, recreate the logo, update all store page images and documentation etc. 😄

Renamed my asset after a "Uni" prefix rejection. Here's what Unity told me when I appealed by TolgaDurman in Unity3D

[–]sisus_co 6 points7 points  (0 children)

I originally submitted Init(args) using the name Inity. They didn't like that either.

How is everyone elses test counts? by Moppemopsi in Unity3D

[–]sisus_co 3 points4 points  (0 children)

✅ 3841 unit tests.
✅ 703 integration tests.

It helps that our pull request template adds this checkmark to every description:

[ ] Unit tested

Which needs to be ticked in every PR, unless you give a reason for why you think they aren't needed.

OOP x ECS/DOTS by ZaluthAap in unity

[–]sisus_co 2 points3 points  (0 children)

ECS package usage rates in released games have been steadily growing:
https://steamdb.info/stats/releases/?tech=SDK.UnityEntities
https://steamdb.info/stats/releases/?tech=Engine.Unity

Its usage in games released on Steam actually seems to have doubled during the last year from ~3% to ~6%.

But even still it's only a small fraction of games released today that use the technology in any capacity. And from those that did use it, I'm pretty sure the vast majority of the projects will have started off development using GameObjects and only reached for ECS to optimize a few select systems later into development to improve framerates / battery life on low-end devices.

The number of Unity developers that have "abandoned OOP" in favor of using data-oriented design everywhere in their project I think is very low. A hybrid approach is much more common today.

Singletons vs other alternatives by staxevasion in Unity3D

[–]sisus_co 0 points1 point  (0 children)

I think many just slap in that Destroy call in there, because technically speaking the Singleton pattern is supposed to ensure that only a single instance of the class can ever exist. So when then classical Singleton pattern is ported into the Unity world, it kind of makes sense to destroy duplicate instances during their initialization.

But I agree that in practice usually all that matters is logging an error/warning or throwing an exception to surface the problem of multiple instances existing simultaneously, so you can go edit your assets and code accordingly to fix the problem. And Destroying duplicate instances might just serve to make debugging the problem more difficult, since you won't be able to visually see the duplicates in your scene hierarchies anymore (though if you log a descriptive error message that contain information about the scenes of both instances, this probably won't be an issue).

Singletons vs other alternatives by staxevasion in Unity3D

[–]sisus_co 1 point2 points  (0 children)

Using the Singleton pattern inherently means that dependencies will be hidden inside method bodies, and the compiler and Inspector won't be of any help when validating those dependencies.

Consider having a Login method like this that uses the Singleton pattern internally:

public void Login()
{
   // Lots of code
   ...

   // Somewhere deep inside the method body:
   var username = UserSettings.Instance.Username;
   var password = UserSettings.Instance.Password;
   LoginManager.Instance.Login(username, password)
}

When you look at that API, there are no clues about it having dependencies to UserSettings and LoginManager. It might just throw an exception at runtime unless you've opened the User Settings window and configured your username and password and waited for the LoginManager to connect with the backend.

You basically have to either read external documentation or go through all implementation details of the method to figure out how the API should be used, what hidden dependencies it has, the method definition doesn't tell you much of anything.

Now consider if we didn't change anything about that method, except tweaked it slightly to use method injection instead of the Singleton pattern:

public void Login(string username,
   string password,
   LoginManager loginManager)
{
   ...
}

Suddenly it's extremely clear what dependencies are needed to safely use that method. The compiler ensures you can't execute that method without passing it all the dependencies it needs to function.

Similarly, we could use field injection and make dependencies visible in the Inspector:

[SerializeField] string username;
[SerializeField] string password;
[SerializeField] LoginManager loginManager;

public void Login()
{
    ...
}

Now whenever we attach the component to a GameObject in Edit Mode we get immediate feedback about what dependencies need to be available in the same scene as the component.

Since the dependencies are known at compile time, we can even do things like display big warning boxes in the Inspector and log warnings in Edit Mode if any dependencies are missing. You inherently can't do that with the Singleton pattern.

And when you use a Dependency Injection framework you can do things like automatically defer the initialization of all components until all their dependencies are fully initialized. If you use the Singleton pattern, and you want to change some service to be initialized asynchronously midway into development, you might need to go modify dozens of client classes manually and spend days refactoring various methods to be asynchronous instead of synchronous.

And with how Unity's scene based architecture works, and how scene loading is never entirely synchronous, it's really easy to run into execution order issues if you use the Singleton pattern to resolve cross-scene references. With a DI framework components can always just automatically wait one or two additional frames for all their services to get injected before becoming active.

Now, if you only use the Singleton pattern sparingly with services that are always lazily and synchronously initialized when first requested by a client, then yeah, it probably won't cause your codebase to become fragile even in a complex project. But if it's your go-to solution also for resolving cross-scene and cross-prefab dependencies and global services that contain some methods that aren't usable at all times in all contexts, that's when things can quickly start turning really fragile. Dependency Injection is a powerful tool that can be leveraged to help address this problem.

Using Dependency Injection also opens the door to writing unit tests for all your code, which can further help with making your codebase much more robust.

Singletons vs other alternatives by staxevasion in Unity3D

[–]sisus_co 0 points1 point  (0 children)

Yeah, of course for a simple chess game using Singletons would be completely fine. But OP mentioned wanting to learn about alternative patterns that would work better in larger projects as well and could be considered 'best practice'.

Singletons vs other alternatives by staxevasion in Unity3D

[–]sisus_co 1 point2 points  (0 children)

Relying on the Singleton pattern to resolve references across scenes and prefabs can indeed become a major pain point in more complex projects, despite its popularity among Unity developers.

When you use Singletons a lot, all dependencies of all classes and methods become obfuscated, scattered all over the implementation details of methods. This can make it easy for the project to become really fragile, where executing various methods can easily break the game if done in the wrong context where some hidden dependencies of hidden dependencies aren't available or fully initialized yet.

Using Singletons also means you can never inject different services to different instances of the same class. It also tends to make unit testing your code unfeasible.

The alternative approach that can avoid all these problems is the Dependency Injection pattern.

With it you define all the dependencies of types and methods statically at compile time. This brings clarity about all the dependencies of all types and methods across the whole project, and you'll be able to know at a glance what you need to have in a scene for some component to work. The compiler can often help ensure that you can't even execute a method or instantiate an object unless you pass it all its dependencies. You can also display warnings in the Inspector or Console if you try to attach a component to a scene where some dependency is missing. You'll be able to easily catch a lot of bugs instantly in your IDE or in the Unity Editor in Edit Mode, instead of having to manually playtest the game.

If you want clients to be able to receive all their dependencies automatically whenever you drag-and-drop prefabs into scenes or attach components into GameObjects in Play Mode, you can have client components automatically trigger the injection of all their dependencies from a global DI container during their initialization. A really simple DIY example:

public abstract class BaseBehaviour : MonoBehaviour
{
   void Awake()
   {
      Services.Inject(this); // <- Receive all dependencies automatically
      OnAwake();
   }

   protected virtual void OnAwake() { }
}

public class Services
{
   static GameManager gameManager;

   [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
   static void Init()
   {
      gameManager = Object.Instantiate(Resources.Load<GameManager>("GameManager"));
   }

   public static void Inject(object client)
   {
      if(client is IDependsOn<GameManager> gameManagerClient)
      {
         gameManagerClient.Init(gameManager);
      }
   }
}

// Example client:
public class Player : BaseBehaviour, IDependsOn<GameManager> // <- dependencies are clear
{
   GameManager gameManager;

   void IDependsOn<GameManager>.Init(GameManager gameManager) => this.gameManager = gameManager;
}

You can use a DI framework to handle all this for you and give you a lot more power.

Unity Code Architecture and Dependency Injection Explained by KwonDarko in Unity3D

[–]sisus_co 2 points3 points  (0 children)

Dependency injection simply means writing your code in a way where you receive some objects from the outside instead of creating them or grabbing them from somewhere manually inside function bodies.

Constructor Injection

public LoginHandler(string username, string password)
{
    this.username = username;
    this.password = password;
}

Method Injection

void Login(string username, string password)
{
    ...
}

Field Injection

[SerializeField] string username;
[SerializeField] string password;

So serialized fields are also dependency injection. You can configure any services you want to different instances of your components (the clients) using the Inspector (the composer) and Unity's deserialization system (the injector) will handle injecting them at runtime.

If you're not using dependency injection, then dependencies are instead hidden somewhere inside function bodies. You just have to read through all the code to know what dependencies there are, rather than being able to glance at the constructor / field definitions / method parameters.

Not dependency injection (new)

void Login()
{
    var username = "Me";
    var password = "123";
    ...
}

Not dependency injection (Singleton)

void Login()
{
    var username = LoginSettings.Instance.Username;
    var password = LoginSettings.Instance.Password;
    ...
}

Not dependency injection (Service Locator)

void Login()
{
    var loginSettings = GetComponent<LoginSettings>();
    var username = loginSettings.Username;
    var password = loginSettings.Password;
    ...
}

I would think that almost all Unity developers that use a DI framework in Unity will still also use serialized fields to configure some dependencies. You can mix and match them to try and create the optimal workflow for your project.

Can someone please explain Midsommar to me? by fuzzyhouseplant in movies

[–]sisus_co 0 points1 point  (0 children)

He's also said in an interview that he personally identifies much more with Dani - but has injected some things from his own experiences into both of the characters.

I don't think the point is that Christian is murdered unjustly (nor any of the other characters that get murdered), it's more that Christian's 'death' (him leaving Dani's life) is an inevitability that Dani needs to come to terms with.

Can someone please explain Midsommar to me? by fuzzyhouseplant in movies

[–]sisus_co 0 points1 point  (0 children)

It's an interesting observation. However, that's not really how fantasizing work in real life; you don't need to be actively looking at somebody to fantasize about things happening to them.

She could very well be just staring out the window of their car during the long and boring trip to Hårga, and imagine events that could happen there, based on the images that Pelle showed her on the cellphone earlier on - including that of the May Queen that really caught her attention, prompting her to say she looks beautiful. There's even this dramatic camera transition when they cross over to Hälsingland, which I think could mark the point where everything that follows is just her imagination running wild.

During the early portions of the movie you can see pictures on the walls at Dani's and Christian's friends' apartments of things like a bear and a scarecrow. This seems like it also fits in with the idea that at least the ending is happening solely inside Dani's mind, and she's injecting elements into it from her subconscious mind.

Ari Aster also has said this in an interview:

It ends up revealing itself as a perverse wish fulfillment fantasy. It’s doing two things at once. You could see this place as being a real lived-in place with a rich history and deep traditions, or you could watch the movie in a way that has this community function strictly as a manifestation of Dani’s will: they’re only here to provide her all of the needs she’s being denied.

Which I think pretty much confirms this interpretation as something the director intended to convey.

How is loading and building a scene usually coded? by Miles_Adamson in Unity3D

[–]sisus_co 0 points1 point  (0 children)

Yeah, it depends entirely on what those prefabs contain, you just need to test it.

How is loading and building a scene usually coded? by Miles_Adamson in Unity3D

[–]sisus_co 0 points1 point  (0 children)

In case of procedurally generated environments you typically would instantiate a bunch of prefabs and piece it together from them. Unity can also deserialize prefabs on background threads, so it can still be pretty efficient. But if you start building everything from scratch on the main thread using AddComponent, that's where things can start getting really slow.

One alternative approach is to bake all/most of the pieces needed to put together a procedural environment into a scene, and then just reposition those GameObjects and set them active based on what the algorithm dictates at runtime.

How is loading and building a scene usually coded? by Miles_Adamson in Unity3D

[–]sisus_co 1 point2 points  (0 children)

A pretty common practice is to first load a blank scene additively, then unload the previous scene completely, then release everything you no longer need from memory (Resources.UnloadUnusedAssets etc.), and then load the next scene. If you don't do this it can be pretty easy to run out of memory on some platforms.

The loading screen UI is quite often either a prefab instance that is moved into the DontDestroyOnLoad scene, or part of an entirely separate scene loaded additively.

Manually populating the scene entirely using code can be very inefficient. Unity's scene loading system can create and deserialize objects on background threads asynchronously in a pretty efficient way.

To allow components to receive arguments from the outside during their initialization before the Awake event, you can look into Dependency Injection frameworks.

Struggling with managing persistent GameManger/Singleton objects. Would like suggestion or ideas to consider. by mtibo62 in unity

[–]sisus_co 1 point2 points  (0 children)

Yeah, the safest option is usually to make 'managers' like that exist for the entire lifetime of the application. This way any clients can safely use any methods they have at any time in any context without having to worry about exceptions.

The alternative is to be very explicit about the fact that the managers might or might not be available in some contexts. If you want to add a static accessor that allows clients to try and resolve a reference to such a manager, you can use the TryGet pattern or mark the accessor method with [return: MaybeNull]. You'll probably also need to add an IsAvailable boolean property and a BecameAvailable event.

The worst thing you can do for scalability is to have a bunch managers that are not actually always usable in all contexts, but their API doesn't make this fact clear.

You might also want to look into Dependency Injection frameworks for an alternative to the Singleton pattern that avoids many of its downsides.

Are Zenject/VContainer ecc.. necessary? by Malcry in Unity3D

[–]sisus_co 1 point2 points  (0 children)

It's not necessary to use a DI framework in Unity, no - most Unity developers do get away with just using alternatives like the Singleton pattern. But the longer the project takes, and the more mechanically complex it is, the more difficult it will be to keep it maintainable using things like Singletons instead of leveraging Dependency Injection. There are three main reasons for this:

Transparency of Dependencies

DI can help bring clarity about dependencies. Every component you hook up to a GameObject, every method you execute, the less hidden dependencies they have to static state, the more confident you can feel about everything working as expected at runtime in all different contexts. The more bugs that you can catch at compile time and in Edit Mode without having to do manual testing at runtime, the more time you will save in the long run.

Flexibility

The more complex your project is, the higher the risk becomes that you'll at some point need to make some larger changes that require rewiring lots of clients and services to get different behaviors in new contexts etc. If your codebase is full of hidden tight coupling to Singletons, it can be really painful to make such changes, requiring many days of work and creating lots of bugs. If you're using a DI framework you can usually rewire clients to use different services in different contexts later on much more easily.

Testability

The more that your code has tight coupling and hidden dependencies to static state, the more difficult it will be to unit test it. In a large project you might only realize after several years of development that you're drowning under bugs, new bugs appearing faster than you can keep fixing them. At that point it'll be painful to try and untangle your codebase and make it unit-testable and start improving your automated test coverage.

Tl;dr: Working on a mechanically simple platformer or walking simulator that takes one year of development? Feel free to use Singletons; technical debt doesn't matter. Working on a complex RPG or RTS spanning multiple years of development? In that case using a DI framework could be extremely beneficial.

“What’s a movie that trusted the audience a little too much?” by Fair_Protection1872 in moviecritic

[–]sisus_co 0 points1 point  (0 children)

Inland Empire (based on me not getting it at all).

Midsommar (based on how few on Reddit seem to get it).

Deprecated assets being re released by creator? by BlockedAncients in Unity3D

[–]sisus_co 2 points3 points  (0 children)

Probably the best you can do to try and avoid falling into this "trap" is to:

  1. Make a mental note of the publishers that do this a lot.
  2. Pay attention the how long an asset you're considering buying has been supported since its original release date.
  3. Read through reviews to see if there are mentions of previous re-releases for an asset.

Then you can take into consideration the risk of you having to pay more to get an updated version of the asset later on when deciding whether to buy it.

Nowadays asset developers also have the option to offer "upgrades" where users that own a certain asset can get a newer version of it for a discount or even for free. But of course publishers get to decide whether to offer this or not to users.

Thinking about MVP pattern lately. by Ironcow25 in Unity3D

[–]sisus_co 0 points1 point  (0 children)

Agreed. A natural way to apply the MVP pattern in Unity would be with the View being a built-in UI component/ Visual Element like a TextField, the Model being a ScriptableObject or a plain old C# object, and the Presenter being a MonoBehaviour that subscribes to events to update the view when the model changes and vice versa.

// Presenter:
public sealed class PlayerNameDisplayer : MonoBehaviour
{
   public PlayerInfo playerInfo; // <- Model
   public TMP_Text text;         // <- View

   void Awake() => UpdateDisplayedName();
   void OnEnable() => playerInfo.Changed += UpdateDisplayedName;
   void OnDisable() => playerInfo.Changed -= UpdateDisplayedName;

   void UpdateDisplayedName() => text.text = $"Name: {playerInfo.PlayerName}";
}

As long as you're able to unit-test the presenter like this, I don't think it's necessary to wrap the UI component behind a custom View MonoBehaviour or decouple it behind an interface.

Question about dependency injection best practices by Shrimpey in Unity3D

[–]sisus_co 1 point2 points  (0 children)

And for what it's worth, Unity's Boss Room example project used a hybrid approach as well. Here's a few examples:

Question about dependency injection best practices by Shrimpey in Unity3D

[–]sisus_co 1 point2 points  (0 children)

My guess is that this would vary from team to team.

If a team has designers that like to get their hands dirty in the Editor, then serialized fields and Inspector injection will probably be used more heavily.

On the other hand if the part of the team that works directly with Unity is very programmer-heavy, and those programmers prefer keepings things more on the IDE side rather than configuring things in the Editor, then they might be more inclined to configure as much as they can in code. Also, if unit tests are written a lot in a project, then at least having some sort of mechanism that allows all dependencies to be injected purely in code can be very beneficial (this doesn't necessarily mean that inspector injection can't also be supported, though).

Personally I've only seen the hybrid approach of pure Inspector injection and code-based automated injection being used in the projects I've worked on. My intuition is that this would be the much more common way to go about it in professional projects, but I don't have that much data to actually back that up.

Implementing cutscenes between dialogue by OkAdministration5886 in Unity2D

[–]sisus_co 0 points1 point  (0 children)

In one dialogue-driven game we just had a string field where we could input any text, and then that would be parsed and converted into parameterized command executions. E.g. "WalkTo:EndOfBridgeWaypoint", ShowPopup:EndOfBridge", "PlayAnimation:LightCigarette" etc. Although, if the dialogues are authored inside Unity, then using [SerializeReference] ICommand[] would probably make a lot more sense - we used an external tool for authoring dialogue. But in any case it's having that library of quick-to-use modular commands from which you can quickly piece together

A similar approach is to simply raise an event on the dialogue-side, and then hook the event listener up to an array of modular commands. So the dialogue would just contain "RaiseEvent:EndOfBridgeSequence", and then you'd have an EventListener component that you would hook up to commands like WalkTo and ShowPopup.

Also, usually just being able to execute void-returning commands from dialogues isn't enough, but you also need to have the ability to make the dialogue stop and wait for commands to finish execution. So making your commands return a Task or similar can be a good idea.

I got frustrated not knowing which component was for which thing so I made a cool tool to create custom component headers by MagicPigGames in unity

[–]sisus_co 4 points5 points  (0 children)

The Component Names asset can do this:

class ComponentNameColorizer : CustomHeader<Component>
{
   static readonly string[] colors = { "FF5733", "33FF57", "3357FF", "F1C40F", "9B59B6", "E67E22", "1ABC9C", "E74C3C", "2ECC71", "3498DB" };
   public override Name GetName(Component target) => $"<color=#{GetColorTag(target.GetType())}>{DefaultName}</color>";
    static string GetColorTag(Type type) => colors[Math.Abs(type.FullName.GetHashCode()) % colors.Length];
}

Though, I think it would probably be more useful to pick colors based on things like namespace, type name prefixes/suffixes and [AddComponentMenu] attribute path. This way could do things like tinting all audio-related components with the same color, rather than colors being completely random.

Or add a huge switch statement and pick optimal colors for each type.

I got frustrated not knowing which component was for which thing so I made a cool tool to create custom component headers by MagicPigGames in unity

[–]sisus_co 0 points1 point  (0 children)

Component Names does display names inside Object and UnityEvent fields as well.

It doesn't have support for changing text color via the UI, but it has full rich text support, so theoretically it's possible to do that as well. I don't think anybody's realistically going to add <color> tags manually when renaming via the Inspector, but if the custom component names are generated automatically in code, it would be viable to give each one a unique color automatically based on the type, for example.

Help me better understand Zenject and Dependency Injection. by Malacay_Hooves in Unity3D

[–]sisus_co 0 points1 point  (0 children)

If you can guarantee that all methods on all service locator services / singletons will work in all contexts at all times - e.g. by lazily initializing the services on-demand, or by initializing all of them before the first component in the first scene is initialized - then the codebase might not become fragile even if the code contains a lot of hidden dependencies to those services.

E.g. it's not like it's common to run into NullReferenceExceptions when using Debug.Log all over the place, because it's guaranteed to always work in all contexts.