Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
xgalaxy
Jan 27, 2004
i write code

ToxicSlurpee posted:

You don't actually need to attach things to a GameObject to use them. You can create classes that do not inherit from MonoBehaviour and then just use them like you would normally in non-Unity C# projects. You need to do that to interact directly with Unity but that's it. You can, for example, have an object somewhere in the ether that does those things but never directly interacts with Unity itself.

The file full of enums just needs to exist somewhere in the project. Same with any static classes, singletons, and non-MonoBehaviours; they can't interact directly with Unity but stuff that inherits from MonoBehaviour can interact with them. There isn't any special trick; if it's in the C# project you can use it.

Yep this. I think people new to Unity who are eager to work in the 'Unity way' get confused and start thinking they need to make everything MonoBehaviours. You do not, and most likely should not, do that. In fact try and make as few MonoBehaviours as possible, IMO.

Adbot
ADBOT LOVES YOU

ToxicSlurpee
Nov 5, 2003

-=SEND HELP=-




Pillbug

xgalaxy posted:

Yep this. I think people new to Unity who are eager to work in the 'Unity way' get confused and start thinking they need to make everything MonoBehaviours. You do not, and most likely should not, do that. In fact try and make as few MonoBehaviours as possible, IMO.

That's...mostly true. The only real issue is when you have poo poo loads of MonoBehaviours calling Update every frame; for small games this is irrelevant but as a game gets big it can be a real problem. You can improve performance massively by just removing Update, writing your own ManualUpdate method, and calling it only when relevant.

The really, really nice thing about Unity is that it doesn't force you to do it the "Unity Way." You can seriously just treat it like a rendering engine and doing all your game logic outside of MonoBehaviours; that's they way I tend to do it actually though that's just a good practice in general; best to keep the visuals from touching the game logic. Have the game logic tell Unity what you what rendered and where and leave it at that.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


HaB posted:

Right I get all that - what I don't get is how do I get that stuff into Unity itself?

Like, say I create some sort of class that's a UnitSelectionManager. Where do I attach that so Unity can get at it? Same thing with a file full of enums. Is there some directory or something Unity will just parse all scripts in that directory? I understand how to write the code, I'm just not sure how to get it to play with Unity.

Do I create something like an empty GameObject for Player and attach scripts to it? Since I know that object will always be there?

Unity is c# (3.5 subset). A bunch of the stuff I do is written in DLLs without using any unity classes or notions. Some object will hold a reference to that stuff somewhere, but it's largely unimportant. It's built and tested (nunit) independently.

Similarly, games aren't really that different from other programming projects. Beyond purposefully being contorted into an infinite loop. Or having pretty pictures. Many non-games applications are similarly contorted though.

If you know how to solve a problem outside of the unity context (and it isn't reliant on unity's graphics or physics pipelines, etc) you know how to solve the same problem in the unity context.

Mechanically, at some point you'll need some MonoBehaviour that either implements or holds a reference to whatever functionality you're trying to present. Anything you want to use in the editor (and not in the game) should be in a folder named Editor. I usually keep all code in Assets/Scripts and DLLs in Assets/Plugins, but I don't remember offhand if those directory names are magical (some, like aforementioned Editor or StreamingAssets, are).

Sorry if any of that comes off as being short. I'm supposed to give a related presentation at work, but the concept of understanding c# but being absolutely blank on how to approach a problem in unity is foreign to the way I think about the platform. From my perspective it's just writing archaic c# (all the good stuff came in .net4 ) to frobnicate some state or call some API or w/e. I've probably just internalized enough of the weird things though. Eg, don't create/use constructors for MonoBehaviours.


What unity actually does under the hood is a little weird with the way their introspection works. It's probably not very important to dive into that stuff right off the bat, but remember that Update/Awake/OnStart/etc can be private and will still be called by the engine the way you would want them to. And don't declare them if they're empty.

starkebn
May 18, 2004

"Oooh, got a little too serious. You okay there, little buddy?"


Without trying to read the whole thread, is it a known Unity Editor problem for it not to load and be stuck on the taskmanager waiting for network I/O? If so is there some way to fix it because I can't find anything good via Google, just a handful of other people talking about it without a solution.

I've tried Firewall exceptions, running with antivirus uninstalled etc.

HaB
Jan 5, 2001

What are the odds?


leper khan posted:

Unity is c# (3.5 subset). A bunch of the stuff I do is written in DLLs without using any unity classes or notions. Some object will hold a reference to that stuff somewhere, but it's largely unimportant. It's built and tested (nunit) independently.

Similarly, games aren't really that different from other programming projects. Beyond purposefully being contorted into an infinite loop. Or having pretty pictures. Many non-games applications are similarly contorted though.

If you know how to solve a problem outside of the unity context (and it isn't reliant on unity's graphics or physics pipelines, etc) you know how to solve the same problem in the unity context.

Mechanically, at some point you'll need some MonoBehaviour that either implements or holds a reference to whatever functionality you're trying to present. Anything you want to use in the editor (and not in the game) should be in a folder named Editor. I usually keep all code in Assets/Scripts and DLLs in Assets/Plugins, but I don't remember offhand if those directory names are magical (some, like aforementioned Editor or StreamingAssets, are).

Sorry if any of that comes off as being short. I'm supposed to give a related presentation at work, but the concept of understanding c# but being absolutely blank on how to approach a problem in unity is foreign to the way I think about the platform. From my perspective it's just writing archaic c# (all the good stuff came in .net4 ) to frobnicate some state or call some API or w/e. I've probably just internalized enough of the weird things though. Eg, don't create/use constructors for MonoBehaviours.


What unity actually does under the hood is a little weird with the way their introspection works. It's probably not very important to dive into that stuff right off the bat, but remember that Update/Awake/OnStart/etc can be private and will still be called by the engine the way you would want them to. And don't declare them if they're empty.

Good advice. Didn't come off short at all, so no worries.

My problem is just that I'm experienced as a programmer and even as an architect, but Game Dev is such a different problem space than I am used to working in that the programmer side of me is going "yay new problems!" but the architect side is still going "wait. where does this go now?"

But based on the last few posts, I think I understand now. I'm not used to relying so heavily on the Decorator pattern, which seems to be part and parcel for Unity, since that's basically what a Component is. Plus since I have spent the last couple of years working in the async Javascript world, it's forcing me to do a paradigm shift in two ways: 1 - back to .NET in general, which I did professionally for 11 years, but not at all for the last 6 or so and 2 - mostly away from modern JS's promise/resolve, event/listener paradigm. It's been good tho. I always appreciate learning a new way to do things.

Thanks for all the advice given, everyone.

HaB
Jan 5, 2001

What are the odds?


Kaaaaaay....got another question.

I have created a prefab to render a circle on the ground around selected units. It's a projector and a material. it is a child object of my unit prefab.

My objects are laid out like this:

code:

UnitPrefab
    UnitHead
    UnitBody
    SelectionCircle

(all of the above are GameObjects )
    Selectable
    Unit

(these are both scripts)

Inside of Selectable.cs I am trying to get a reference to the SelectionCircle, but I can't seem to figure out how. The error is that the type or namespace can't be found.

I have tried every combo of the following so far:

code:

private gameObject selectionCircle;
// OR
private SelectionCircle selectionCircle;

void Start() {
	selectionCircle = gameObject.GetComponent<SelectionCircle> ();
	// OR
	selectionCircle = gameObject.GetComponentInParent<SelectionCircle> ();
}

What am I missing?

Lork
Oct 15, 2007
Sticks to clorf


Edit: I reread your post and saw that SelectionCircle isn't the name of one of your scripts. If you want to get anywhere you'll need to answer the following questions: 1. What do you intend to do with your reference to "SelectionCircle". and 2. Which gameobject is your Selectable script attached to?

Lork fucked around with this message at 04:06 on Jul 18, 2016

HaB
Jan 5, 2001

What are the odds?


Lork posted:

Edit: I reread your post and saw that SelectionCircle isn't the name of one of your scripts. If you want to get anywhere you'll need to answer the following questions: 1. What do you intend to do with your reference to "SelectionCircle". and 2. Which gameobject is your Selectable script attached to?

1: I intend to call .SetActive on it, as needed

2: Selectable is attached to UnitPrefab. SelectionCircle is a child object of UnitPrefab

Tiler Kiwi
Feb 26, 2011


ah man, I completed the C# tutorial on pluralsight and was feeling pretty stoked about trying to implement some of what id "learned", then I check out a simple message bus sort of system just to see if I could implement it for good practice for my super simple first prototype thing and man I have only half a clue what it is doing.

whenever i step away from some regimented tutorial i feel like im stepping into some terrible void. got a ways to go still.

Lork
Oct 15, 2007
Sticks to clorf


HaB posted:

1: I intend to call .SetActive on it, as needed

2: Selectable is attached to UnitPrefab. SelectionCircle is a child object of UnitPrefab
Ok, so to clarify things, GameObjects are not components, rather they are the things that house components. Components are scripts that inherit from MonoBehaviour, such as your Selectable. GetComponent won't help you find SelectionCircle because it's just a name you gave one of your GameObjects, not the name of a component.

There are a number of ways to get a reference to a GameObject and which one is most appropriate depends on context and personal preference. One way to do it would be to use Transform.Find(), like so:

code:
Transform circleTrans = transform.Find("SelectionCircle"); //Note the lower case "transform".  This is a cached reference to the Transform component on the same GameObject as your script.
GameObject circleGO = circleTrans.gameObject //Also note that it returned a Transform component.  Luckily all components also have a reference to the GameObject housing them in .gameObject
Since the thing you need a reference to is contained within your prefab, another way to do it would be to make your selectionCircle variable public or put the [SerializeField] attribute over it. This will expose it to the Unity inspector (the right side panel in the Unity editor by default) and you can then drag the child object into it, saving the reference as part of the prefab.

Lork fucked around with this message at 06:53 on Jul 18, 2016

HaB
Jan 5, 2001

What are the odds?


Lork posted:

Ok, so to clarify things, GameObjects are not components, rather they are the things that house components. Components are scripts that inherit from MonoBehaviour, such as your Selectable. GetComponent won't help you find SelectionCircle because it's just a name you gave one of your GameObjects, not the name of a component.

There are a number of ways to get a reference to a GameObject and which one is most appropriate depends on context and personal preference. One way to do it would be to use Transform.Find(), like so:

code:
Transform circleTrans = transform.Find("SelectionCircle"); //Note the lower case "transform".  This is a cached reference to the Transform component on the same GameObject as your script.
GameObject circleGO = circleTrans.gameObject //Also note that it returned a Transform component.  Luckily all components also have a reference to the GameObject housing them in .gameObject
Since the thing you need a reference to is contained within your prefab, another way to do it would be to make your selectionCircle variable public or put the [SerializeField] attribute over it. This will expose it to the Unity inspector (the right side panel in the Unity editor by default) and you can then drag the child object into it, saving the reference as part of the prefab.

The bolded part is a distinction I had missed somehow. Thanks.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


HaB posted:

Kaaaaaay....got another question.

I have created a prefab to render a circle on the ground around selected units. It's a projector and a material. it is a child object of my unit prefab.

My objects are laid out like this:

code:


UnitPrefab
    UnitHead
    UnitBody
    SelectionCircle

(all of the above are GameObjects )
    Selectable
    Unit

(these are both scripts)


Inside of Selectable.cs I am trying to get a reference to the SelectionCircle, but I can't seem to figure out how. The error is that the type or namespace can't be found.

I have tried every combo of the following so far:

code:


private gameObject selectionCircle;
// OR
private SelectionCircle selectionCircle;

void Start() {
	selectionCircle = gameObject.GetComponent<SelectionCircle> ();
	// OR
	selectionCircle = gameObject.GetComponentInParent<SelectionCircle> ();
}


What am I missing?

Selectable is probably a bad name for a class, as it's the unity type for buttons/toggles/etc. since you have this as a prefab, you don't even need to use GetComponent. Just declare the thing like:
code:

[SerializeField]
private SelectionCircle selectionCircle;
Then drag your selection circle onto that in the editor and you can use it as if the reference has been set up correctly (because it has).

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


Tiler Kiwi posted:

ah man, I completed the C# tutorial on pluralsight and was feeling pretty stoked about trying to implement some of what id "learned", then I check out a simple message bus sort of system just to see if I could implement it for good practice for my super simple first prototype thing and man I have only half a clue what it is doing.

whenever i step away from some regimented tutorial i feel like im stepping into some terrible void. got a ways to go still.

Try breaking the problem down into parts. Recurse on the process until you feel like everything listed is already too easy to have bothered splitting up. Do this on paper. Then code it up.

If you're unsure what it's supposed to do, you'll neither be able to break it down or implement it, so maybe read more docs on the concept you're trying to implement.

HaB
Jan 5, 2001

What are the odds?


leper khan posted:

Selectable is probably a bad name for a class, as it's the unity type for buttons/toggles/etc. since you have this as a prefab, you don't even need to use GetComponent. Just declare the thing like:
code:
[SerializeField]
private SelectionCircle selectionCircle;
Then drag your selection circle onto that in the editor and you can use it as if the reference has been set up correctly (because it has).

Ah. Didn't know that about the class name. Will rename to SelectableUnit.

Thanks. I ended up using SerializeField. Didn't like the idea of transform.find - which seems like a weird way to do it. Mostly in the sense that I'm not dealing at all with transforms right now, so it seems odd to use them to try and find an object. SerializeField makes way more sense in my use case.

Thanks again.

Tiler Kiwi
Feb 26, 2011


leper khan posted:

Try breaking the problem down into parts. Recurse on the process until you feel like everything listed is already too easy to have bothered splitting up. Do this on paper. Then code it up.

If you're unsure what it's supposed to do, you'll neither be able to break it down or implement it, so maybe read more docs on the concept you're trying to implement.

Yeah I've been doing this a bit and its helping, this is just sort of the first time I've had to really sit down and think about how a code base ought to be structured rather than just throwing in stuff and seeing what appears in a console window.

This is all amateur hour stuff and not really worth reading but I don't really have any place to vent at so please excuse this tedious nonsense.

I've basically been going at a very simple prototype with Oregon Trail sort of mechanics: player advances down path unit by unit until they hit space 1000, have ~3 events occur around 100-250 units apart that allow a choice, allow pausing, have some kind of UI that notes location / destination / distance etc. Babby's First Program level stuff.

The organizational problems of coding is something I'd only very lightly touched on, since most exercises in tutorials and in classes don't really delve past doing poo poo in Main(). So I had a plan to pretty much have a class for handling the UI, one for PathTracking, one for EventHandling, and one for GameLogic. Since I didn't really get how the whole message bus stuff worked out, I decided to just go with what I knew and have some GameMaster object that would pretty much play referee between all the different parts. But my conception phase kind of broke down when trying to figure out how events would work, since I'd need to have something that knew when an event ought to be fired, and from there grab an appropriate event, which would have to contain stuff about its text, its choices involved, and the consequences, and from there I realized I'd have to add a means for these consequences to be carried out, and I sort of wound up in a bit of a knot trying to figure out how that was going to play out. So I'm going back to paper to better plot stuff out.

The only thing I've really actually implemented is setting up a [FlagAttribute] list detailing locations that the events could hold so the event firing thing could figure out what was and wasn't appropriate to fire off.

Wrangling with all this makes me feel like a bit of a chickenshit, really, and I know I'm over-complicating it instead of going for simpler solutions. Kind of fun on some level, though. Maybe when I'm done I'll show it off so people can format their computers with whatever horrible fault I overlooked when coding.

Explosive Tampons
Jul 9, 2014

I paid money for this.


Someone please tell me of an easy, reliable way of debugging OpenGL applications please

nSight keeps telling me "Non-generated name detected. Using names that aren't generated with glGen* blablablabl" but I have exactly 4 textures, both generated with glGenTextures(2, arrayname). It says that the offending thing is "Type: Texture. Name: 4". WTF. Am I screwing something up here? It works normally without nSight messing with it. (My videocard isn't really compatible with nSight (it's just a meager 950m) but I'm not sure if I should disregard the message or not.)

gDebugger is very unreliable and I cannot do breakpoints (both because my video adapter is not AMD, I guess). Texture view never has the right textures and I was sure it was a problem on my end until I decided to draw all of them in an easy to view way in my app's viewport. (my textures are all for post-processing purposes and only a composite framebuffer is displayed).

goddammit

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.



The common way to get better at things is to just do them and then look back and wish you did everything some other way. Repeat for every project you ever work on (though hopefully the scope of things you would have changed decreases over time). It's just the nature of internalizing the process of predicting and solving problems.

A book on design patterns could help though. I'm partial to Martin Reddy's API Design for C++. It's well written with clear examples and code. The principles apply generally, but you can probably find something similar directed at C#.

Oh, and even though I love it, don't read Alexandrescu's Modern C++ Design until you've had a few real (C++) projects under your belt. I've seen people recommend that book to newish devs, which is frightful. Most (all?) compilers on the market couldn't even build the examples he gives (though they were/are valid per the language specification) at the time of publication. It's super rad though, and I wish I knew a good way to express the concepts covered in that book in C#.

Lork
Oct 15, 2007
Sticks to clorf


HaB posted:

Ah. Didn't know that about the class name. Will rename to SelectableUnit.

Thanks. I ended up using SerializeField. Didn't like the idea of transform.find - which seems like a weird way to do it. Mostly in the sense that I'm not dealing at all with transforms right now, so it seems odd to use them to try and find an object. SerializeField makes way more sense in my use case.

Thanks again.
You've actually been dealing with transforms the whole time, you just didn't realize it. transforms are what handle parenting, so when you added 3 child objects to your prefab, they were linked to the parent gameobject through their transforms. You were right to use the inspector though. In cases where you can use it, it's usually the most efficient and convenient way to do things; I just used Transform.Find() as a way to explain some stuff.

Pollyanna
Mar 5, 2005

Milk's on them.




Do managers, services, god objects, etc. just get added to the top actor level in a scene? Or do they have/need a special place?

HaB
Jan 5, 2001

What are the odds?


Pollyanna posted:

Do managers, services, god objects, etc. just get added to the top actor level in a scene? Or do they have/need a special place?

I just put mine as top-level. When I start having more than one or two, I will group them into an empty GameObject, probs.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro


Fun Shoe

Explosive Tampons posted:

Someone please tell me of an easy, reliable way of debugging OpenGL applications please

nSight keeps telling me "Non-generated name detected. Using names that aren't generated with glGen* blablablabl" but I have exactly 4 textures, both generated with glGenTextures(2, arrayname). It says that the offending thing is "Type: Texture. Name: 4". WTF. Am I screwing something up here? It works normally without nSight messing with it. (My videocard isn't really compatible with nSight (it's just a meager 950m) but I'm not sure if I should disregard the message or not.)

gDebugger is very unreliable and I cannot do breakpoints (both because my video adapter is not AMD, I guess). Texture view never has the right textures and I was sure it was a problem on my end until I decided to draw all of them in an easy to view way in my app's viewport. (my textures are all for post-processing purposes and only a composite framebuffer is displayed).

goddammit

the goon-built renderdoc? https://github.com/baldurk/renderdoc

apitrace? https://github.com/apitrace/apitrace

otherwise, opengl and opengl debugging sucks, bye

Sex Bumbo
Aug 14, 2004


Explosive Tampons posted:

Someone please tell me of an easy, reliable way of debugging OpenGL applications please

Turn on the debug spew and get really good at figuring out why things are going wrong by making educated guesses.


Suspicious Dish posted:

opengl and opengl debugging sucks

It's just really loving bad top to bottom.

Shalinor
Jun 10, 2002

Can I buy you a rootbeer?


Pollyanna posted:

Do managers, services, god objects, etc. just get added to the top actor level in a scene? Or do they have/need a special place?
I usually throw them as children off of a Global Managers object and Prefab the whole thing up. Makes it easy to throw into a new scene without forgetting anything, and since you can inspect 1 layer deep in a prefab in the Project view, tweaking the managers on the prefab directly is easy too.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


Friendly reminder that you should carefully evaluate whether you actually want global state/singleton. In nearly every case you do not.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!


I am pondering prototyping a board game idea as a phone app. I have been monkeying around in Unity, but I wondered if there was something pretty easy to use particularly for Android and iPhone. I only care right now since I want to pick which language in which to prototype. Since I am cozy with a few, I would just pick whatever the best tool used. I figure it would be 2d or 2.5d at best, and I am more worried about processing user input.

Unormal
Nov 16, 2004

Mod sass? This evening?! But the cakes aren't ready! THE CAKES!

Fun Shoe

leper khan posted:

Friendly reminder that you should carefully evaluate whether you actually want global state/singleton. In nearly every case you do not.

Counterpoint: Global state and singletons are great.

FuzzySlippers
Feb 6, 2009




Isn't this where indie game dev and big software development truisms collide?

Large projects with many developers with years of expected maintenance: global state and singletons not so good.

1 programmer (or a couple) with little maintenance: global state and singletons good.

Shalinor
Jun 10, 2002

Can I buy you a rootbeer?


FuzzySlippers posted:

Isn't this where indie game dev and big software development truisms collide?

Large projects with many developers with years of expected maintenance: global state and singletons not so good.

1 programmer (or a couple) with little maintenance: global state and singletons good.
It also depends on engine. Engines encourage (or sometimes force) particular design patterns. If you want property default-type values in Unity for instance, sure, you can persist those off in a separate file, and write a tool for loading them, and for hot-loading them if they're changed, and... and...

... ooorrrr you can just make a global singleton, make the value public, and poof, it does everything you need instantly. You might still want it to exist as a file too, for runtime tweaks when not in the editor, but typical Unity workflow has that as maybe 10% of your dev time, depending on game/app type. edit: That said, if you're data-driven procedural, a lot of the common Unity use-case stuff flies out the window.

Shalinor fucked around with this message at 01:28 on Jul 20, 2016

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


Unormal posted:

Counterpoint: Global state and singletons are great.

Countercounterpoint: until they aren't.

I'm not saying they don't have valid use cases, but I've also spent weeks tearing poo poo apart to put it back together because some idiot didn't know how to not use a singleton.

You can, and probably should, have control of your application split among several classes, each responsible generally for some (single) thing. Most of those should probably not be singletons. These aren't earth shattering ideas.

You probably don't want your popups to be singletons. Or your menus. Or the type that you've implemented for some type of drop down menu. Or your game screens. Or...

Unormal
Nov 16, 2004

Mod sass? This evening?! But the cakes aren't ready! THE CAKES!

Fun Shoe

leper khan posted:

Countercounterpoint: until they aren't.

I'm not saying they don't have valid use cases, but I've also spent weeks tearing poo poo apart to put it back together because some idiot didn't know how to not use a singleton.

You can, and probably should, have control of your application split among several classes, each responsible generally for some (single) thing. Most of those should probably not be singletons. These aren't earth shattering ideas.

You probably don't want your popups to be singletons. Or your menus. Or the type that you've implemented for some type of drop down menu. Or your game screens. Or...

Those things are all true and there are still a vast amount of cases where global state and singletons are the right design choice for any particular scope and project. If you want to be the best engineer you can be, learn to love every pattern out there. They all find a place. Telling people to never or always do something is usually just flat wrong.

The only really important maxim is to ask yourself why you're doing something, if it helps you reach your goal, and if there's something that does a better job meeting your particular requirements. Engineering driven requirements are nice, but if you're making games you're not shipping engineering you're shipping games.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


Unormal posted:

Those things are all true and there are still a vast amount of cases where global state and singletons are the right design choice for any particular scope and project. If you want to be the best engineer you can be, learn to love every pattern out there. They all find a place. Telling people to never or always do something is usually just flat wrong.

The only really important maxim is to ask yourself why you're doing something, if it helps you reach your goal, and if there's something that does a better job meeting your particular requirements. Engineering driven requirements are nice, but if you're making games you're not shipping engineering you're shipping games.

I think we're actually in agreement.
But I'll always hate goto.

Bongo Bill
Jan 17, 2012

From my point of view, the Jedi are evil. But what really is... evil?

Globals are bad.

A correctly-implemented singleton incorporates all of the possible benefits of a global, while avoiding the unnecessary drawbacks. The necessary ones are still present, of course.

Singletons make sense to represent resources that correspond one-to-one with the number of processes that you are running. Games, especially small games, have many such resources.

Try it a little something like this. Use it responsibly. I recommend that you not access the singleton at all inside of constructors. Have the singleton instantiate dependencies, but inject those dependencies as arguments to constructors as normal.

code:
// src/Interface/IMySingleton.cs
public interface IMySingleton
{
    void SomeGlobalBehavior();
    int SomeGlobalProperty { get; set; }
    // ...
}

// src/Implementation/MySingleton.cs
public class MySingleton : IMySingleton
{
    public static IMySingleton Singleton
    {
        get { return GetInstance(); }
        set { _Instance = value; }
    }
    
    private static IMySingleton _Instance;

    private static IMySingleton Instance()
    {
        if (_Instance == null)
        {
            _Instance = new MySingleton();
        }

        return _Instance;
    }

    private MySingleton()
    {
        // ...
    }

    public void SomeGlobalBehavior()
    {
        // ...
    }

    // ...
}

// test/Mocks/MyMockSingleton.cs
public class MyMockSingleton : IMySingleton
{
    // ...
}

// test/TestInitializer.cs

// ...
void InitializeTests()
{
    MySingleton.Singleton = new MyMockSingleton();
}

Bongo Bill fucked around with this message at 04:13 on Jul 20, 2016

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


Bongo Bill posted:

Globals are bad.

A correctly-implemented singleton incorporates all of the possible benefits of a global, while avoiding the unnecessary drawbacks. The necessary ones are still present, of course.

Singletons make sense to represent resources that correspond one-to-one with the number of processes that you are running. Games, especially small games, have many such resources.

Try it a little something like this. Use it responsibly. I recommend that you not access the singleton at all inside of constructors. Have the singleton instantiate dependencies, but inject those dependencies as arguments to constructors as normal.

code:
// src/Interface/IMySingleton.cs
public interface IMySingleton
{
    void SomeGlobalBehavior();
    int SomeGlobalProperty { get; set; }
    // ...
}

// src/Implementation/MySingleton.cs
public class MySingleton : IMySingleton
{
    public static IMySingleton Singleton
    {
        get { return GetInstance(); }
        set { _Instance = value; }
    }
    
    private static IMySingleton _Instance;

    private static IMySingleton Instance()
    {
        if (_Instance == null)
        {
            _Instance = new MySingleton();
        }

        return _Instance;
    }

    public MySingleton()
    {
        // ...
    }

    public void SomeGlobalBehavior()
    {
        // ...
    }

    // ...
}

// test/Mocks/MyMockSingleton.cs
public class MyMockSingleton : IMySingleton
{
    // ...
}

// test/TestInitializer.cs

// ...
void InitializeTests()
{
    MySingleton.Singleton = new MyMockSingleton();
}

You missed the incredibly important test that instantiation of two of the things returns the same thing instead of two disparate ones. You'd also want to take care in implementation of a singleton that it's thread safe. Basically you should probably avoid writing your own singleton wrapper, as carefully built ones should be available. And if you do need to write one for some reason, use real references not half-put-together fragments from a comedy forum.

Bongo Bill
Jan 17, 2012

From my point of view, the Jedi are evil. But what really is... evil?

leper khan posted:

You missed the incredibly important test that instantiation of two of the things returns the same thing instead of two disparate ones. You'd also want to take care in implementation of a singleton that it's thread safe. Basically you should probably avoid writing your own singleton wrapper, as carefully built ones should be available. And if you do need to write one for some reason, use real references not half-put-together fragments from a comedy forum.

The accessor already returns a single instance (it's lazily instantiated). But, good catch, I thought I had made the constructor private. It's fixed now.

The point is to demonstrate how it works.

Slurps Mad Rips
Jan 25, 2009

Bwaltow!



leper khan posted:

Countercounterpoint: until they aren't.

I'm not saying they don't have valid use cases, but I've also spent weeks tearing poo poo apart to put it back together because some idiot didn't know how to not use a singleton.

You can, and probably should, have control of your application split among several classes, each responsible generally for some (single) thing. Most of those should probably not be singletons. These aren't earth shattering ideas.

You probably don't want your popups to be singletons. Or your menus. Or the type that you've implemented for some type of drop down menu. Or your game screens. Or...

I'm having flashbacks to Hellfucker ruining the UI state and loving up my singletons for events on that defunct mobile game we both worked on, thanks.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


Slurps Mad Rips posted:

I'm having flashbacks to Hellfucker ruining the UI state and loving up my singletons for events on that defunct mobile game we both worked on, thanks.

Shortly after that mess ended I worked with someone way worse than Hellfucker. Glad I got let go when I did though; about two months after that Tony stopped paying taxes. But yeah; I shouldn't have to ever tell anyone this, but don't just literally pull huge chunks of code from stack overflow verbatim. It's CC-by-SA licensed and I assure you, you do not want that poo poo anywhere near your commercial project. Don't steal code.

I legit got mad because dude was a senior developer. I'll let you figure out which the applies to (it's both). But I guess in games that just means you either have experience, or that you've been around awhile but are too incompetent to get a job in a more lucrative industry. If the dude couldn't find or coerce working code to what he needed to do out of SO, he reported back that it was impossible or took like a month per 100 LOC.

Within two weeks at that job I burned through all the stuff for my sprint along with half a dozen things he told the producer were impossible (none of which took more than ~45m). Place was a mess.


PS -
That game is still under development (e: the above quote-mentioned project; not the stuff at the other place)
They're trying to do it in house now, and apparently they just dropped all of the mobile code because they couldn't figure it out and instead are re-writing the flash thing as well as the server. That was as of around when the company blew up, anyway.


e: uhhh.. Games jobs are cool and fun everyone; follow your dreams. Stay in school. It's safe there, and research is rad.

leper khan fucked around with this message at 12:05 on Jul 20, 2016

Pollyanna
Mar 5, 2005

Milk's on them.




Okay okay wait. The use case I'm thinking of is creating object Managers/Systems that associate object update code with the objects that they are meant to operate upon, and registering certain objects/prefabs with particular tags that allow them to be picked up by the Managers/Systems. Kind of a hacky lovely version of the Entity-Component Systems architecture. There has to be a place for those Managers/Systems to live.

I hate global state as much as anyone else, lord knows I've beat my head against the wall trying to get a fully FP-functional, immutable data structure-driven game working, but since Unity is based on C# which is a heavily OOP-oriented language then constructs like these become the alternative. Until comes the day that a game engine backed by functional programming comes into existence (and if it ever does it will be written by John Carmack), this is the best option I can think of.

edit: Singletons are good for encapsulating behavior, but you don't want to use them to encapsulate state. Having global state is where poo poo goes wrong, but having an object that does nothing but query for and operate upon a list of other objects isn't that bad.

That said, I am piss-awful at OOP (and FP to be honest) so maybe don't take my advice

Pollyanna
Mar 5, 2005

Milk's on them.




leper khan posted:

I legit got mad because dude was a senior developer. I'll let you figure out which the applies to (it's both). But I guess in games that just means you either have experience, or that you've been around awhile but are too incompetent to get a job in a more lucrative industry. If the dude couldn't find or coerce working code to what he needed to do out of SO, he reported back that it was impossible or took like a month per 100 LOC.

The definition of what a "senior" developer is, is universally poorly defined and no one can actually agree on what the gently caress it means. Criteria range from 2+ years of experience to 5+ years to mentoring capacity to project management and product design experience to 15+ years working with Java and SQL to being the CEO's daughter. Junior vs. senior basically has nothing to do with competence and more to do with title, respect, power, and pay.

That said, this:

quote:

If the dude couldn't find or coerce working code to what he needed to do out of SO, he reported back that it was impossible or took like a month per 100 LOC.

Doesn't even qualify him as a junior developer. That's entry level poo poo.

quote:

Stay in school. It's safe there, and research is rad.

Counterpoint: grad and postgrad work is a hellscape of slave labor, stupid drama, and awful pay. Please don't do a grad school.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.


Pollyanna posted:

Counterpoint: grad and postgrad work is a hellscape of slave labor, stupid drama, and awful pay. Please don't do a grad school.

I'm going to start on my masters soon, but mostly because I can take classes through the extension program of a school I'd never otherwise get into and my current employer is going to cover it.

I figure the piece of paper will be worth at least the $0 I'm going to put into it, and I might even learn some cool things from the courses.

Adbot
ADBOT LOVES YOU

HaB
Jan 5, 2001

What are the odds?


Pollyanna posted:

Okay okay wait. The use case I'm thinking of is creating object Managers/Systems that associate object update code with the objects that they are meant to operate upon, and registering certain objects/prefabs with particular tags that allow them to be picked up by the Managers/Systems. Kind of a hacky lovely version of the Entity-Component Systems architecture. There has to be a place for those Managers/Systems to live.

I hate global state as much as anyone else, lord knows I've beat my head against the wall trying to get a fully FP-functional, immutable data structure-driven game working, but since Unity is based on C# which is a heavily OOP-oriented language then constructs like these become the alternative. Until comes the day that a game engine backed by functional programming comes into existence (and if it ever does it will be written by John Carmack), this is the best option I can think of.

edit: Singletons are good for encapsulating behavior, but you don't want to use them to encapsulate state. Having global state is where poo poo goes wrong, but having an object that does nothing but query for and operate upon a list of other objects isn't that bad.

That said, I am piss-awful at OOP (and FP to be honest) so maybe don't take my advice

I think you're talking about something similar to how I implemented my unit selection manager. I tend to believe you always want one side of that equation (Manager vs the Objects it's managing) to be as dumb as possible, or at the very least, one side doesn't know about the other side and doesn't care. So I did mine basically like this:

each Unit has a SelectableUnit component, which is basically this:

code:
class SelectableUnit : GameObject {
	private bool isSelected;
        private GameObject selectionHighlight;

	public void Select() {
		isSelected = true;
                selectionHighlight.SetActive(true);
        }

	public void Deselect() { ... }// omitted for brevity 
}
It doesn't know anything about the Manager and doesn't need to. Effectively - ANY other object can tell it to select or deselect.

So my manager class is toplevel to the scene because it's having to grab mouse input (in the case of clicking or clicking & dragging to select units). So when you click/drag it first loops over the list of currently selected objects, calling Deselect on each, then it loops over which ever units are in the selection box, checks for a SelectableUnit component, and calls Select on it if it exists. The manager doesn't need to know the state of each unit and doesn't muck about with modifying it either. It only maintains the list of selected ones so it can deselect them. The list may actually move to a higher level object since I will use a similar pattern for moving units, and those two components will need to share the list of what's selected. So I will have a MovableUnit component which will expose Move/Stop/whatever methods.

I haven't done OOP in a long while since I have been doing Javascript for the past 6 years or so, but I'm pretty sure the design is at least solid, with minimal side effects and good maintainability.

That's as "pure" as I could get it. I could write a more genericized "OrderableUnit" class which takes an order type (Move, Stop, Attack, Select, Deselect, etc) as a param, but right now I can't find any good reason to. Plus I will eventually have something like a turret which can Attack but not Move - why would I want that extra movement code in there when it's never going to use it. Unity seems to rely heavily on the Decorator pattern anyway - so why not let it do what it's good at?

Plus after working in the murky depths of Javascript SPAs for the last few years - ANY time I see a nice clean code file that's <50 lines, I just smile.

Re: Senior Developers - I've always said the chief difference is that the Senior is better at googling.. (I say this AS a Senior Dev)

Aside: what's the good, rebindable-at-runtime Input asset thingy everyone was talking about for Unity?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply