Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

After 3+ years of using Unity and C# full time, here's where most of my bugs come from...

Discussion in 'Game Design' started by astracat111, Aug 20, 2020.

  1. astracat111

    astracat111

    Joined:
    Sep 21, 2016
    Posts:
    714
    Just a little game design thought here, I've been working on a project for almost 4 years now, I started learning C# when I started the project and kept going from there.

    I'm probably no where near an advanced programmer at this point, I'm not at the point of those guys who can whip up quaternion physics functions using linq...but I wanted to share where most of my bugs have come from.

    Basically, let's say that you have three simple states, 'start', 'run' and 'end'. When you're in 'start', your function will change some data, you open up some kind of package so to speak, and opening up that package means switching on like 4 different values or something.

    When it's running, the package is open, right? Well, when I get to 'end' part, there's always a value that I end up not closing back up.

    Let me give you an example.

    I got the asset store plugin InControl at one point so I could implement controller support. Well, when you have multiple players you might have an array (you really should have a list but just for this example let's say you have an array). Well, Player 1 joins, Player 2 joins and Player 4 joins. The arrays slot 0, 1 and 2 are now Player 1, 2 and 4. Well, when Player 2 unjoins, you move Player 4 up, but then you have some kind of method updating and checking for that null value that wasn't updated.

    That's a terrible example...but I digress! x_x

    The most common bugs I've had are null reference exceptions, probably like most people, but it usually comes from starting up some kind of process on a 'start' state, and not remembering that when it comes to it's 'close' state, you need to remember that it needs to reset on ALL ends to exactly where it started from.

    This has especially been the case with scene transitions. Always make sure to reset that data on all ends, if you miss a value it carries over from one scene to the next and you won't catch it until far later usually. Open up the process, close the process. Load the data, make sure the data is disposed of, every last trace of it set exactly to how it was in the beginning.

    The reason I'm mentioning all of this is that I've now clocked in about 5000+ hours on the current project, and about 2000 of those were probably debugging, of course being a programmer that's still learning and everything. I could have maybe cut that by 25% I feel like if I just kept the whole adage in mind 'remember reset it completely to how it was!'
     
  2. Antony-Blackett

    Antony-Blackett

    Joined:
    Feb 15, 2011
    Posts:
    1,772
    Sounds like you need to rethink your design.

    This isn't really an issue in Unity or C#. It would happen in any framework that uses pointers or references in arrays or whatever.

    My rule of thumb is if there's a problem that keeps recurring then that's probably something you need to investigate more, understand better and is also worth solving properly with either improved coding practises or a different design.
     
    Ryiah, angrypenguin and Martin_H like this.
  3. Martin_H

    Martin_H

    Joined:
    Jul 11, 2015
    Posts:
    4,433
    Sounds to me like you should follow KISS more.
     
  4. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    I can't say anything about the programming specifically but I think it's worthwhile to get extra pair of eyes on your work from time to time for high level critique. Not good to work in a vacuum. Ask around and some people may even help for free.

    I try to have periodic reassessments on an actual schedule to help mitigate going too far down wrong paths. I had similar experience where I realized too much time in a project was spent solving user created issues, and thats the point where I consider trying a different approach rather than working endlessly in circles and building something I can't mainttain.
     
  5. astracat111

    astracat111

    Joined:
    Sep 21, 2016
    Posts:
    714
    @BIGTIMEMASTER I think it really depends. There are times when working with others works, but there are times in where doing everything by yourself actually has it's advantages, but I get it with checking where you are, trying to have foresight.

    Well, you say that, but then if you're working on a big coding project you're going to run into all kinds of bugs, big and small, you're going to end up bumping your head against the wall and there are going to be mistakes made.

    To say that bugs and making mistakes really aren't issues with Unity or C#, well, first of all that's probably objectively untrue, and second personally I have a handful of stories in where upgrading a Unity version ended up with either a small or a big bug, even if it was a 'stable' version. This can happen often with Asset Store assets.

    For people making Asset Store assets, I would actually add onto this point about the closing of a process, and say that in the beginning of the process take the time to have the asset check the version of Unity ahead of time for compatibility and simply not start itself up and echo out an error. It goes in line with the point I'm trying to make of having checks and balances.

    ...but, from my experience, cleaning up issues is part of the job. Learning new things as you go is part of the job, and just like with learning a language, making mistakes isn't a bad thing, but it's part of the process. Just from my experience, when someone does things 'their way' in something, they end up enjoying it more because in a way it's more intimately 'theirs', they own their way of doing it so to speak, it really gives you that dopamine high when you own it, at least that's how it is for me.

    Why practice 'good coding practices'? Well, it's one thing if you're working full time for some corporation, but it's another thing if you're trying to get the thing to do what you want it to do. Having fun isn't taken seriously enough, messing around isn't taken as seriously as a boring job, in which case just forget about all the practices if you don't wanna use them.

    When I started 4 years ago, I had used javascript mostly with some C++, I didn't use namespaces and I thought of static variables as global variables. I didn't understand that .NET classes were like objects or methods were like buttons that you press on those objects.

    That's just the way I saw it back then, so when I started programming C# I just had one goal: get the thing to do what I want it to do. So when I started, I was using lots of static variables, and every class that I had was simply inheriting from MonoBehaviour using Unity's 'Create Script' context menu drop down box thing.

    I never looked at one tutorial and I completely ignored all the traditional ways of learning, I just did tons and tons of google searches looking for something I needed, although I did one personal practice, I kept things as organized as humanely possible.

    For example, instead of using classes and namespaces I'd end up using underscores like MG_Manager to name my variables and files.

    Well, the thing worked, and I ended up re-organizing it later into classes sure, which yeah it took a lot of work, but there's something to be said when you follow your own way of doing something, and I'm saying this because I wish I could express this about programming to more people. You can actually do things YOUR way in programming (if you're working for yourself instead of a company or a school), it's rare to have an art actually work this way, and it makes it incredibly exhilarating, to feel like that rebel black sheep that's breaking the rules.

    Programming is amazing because you could be a beginner and still get the computer to do something that impresses people. You can actually uses terrible practices and make something amazing. There's no other art I can think of like that. You can't just be starting on the first week in drawing and making something exceptional like you can with programming. I just can't stand when people turn it into something with traditions, and then when I tell people I love programming and can't put it down they blink at me like "programming? Isn't that boring?".

    I also can't stand when anyone thinking of learning programming thinks it's like math or something. All the math stuff is done for you. I wish anyone thinking of learning coding could be less intimidated and see it in this way.

    In any case, I'm going to stick to my point, trying to share an observation with beginning programmers and game designers, I don't know how entirely to word it, but like when you open something up, make sure to close it down and reset it to how it was, and maybe add on that whole thing in that when you're starting a process have the process simply not start without first checking if it's appropriate for it to run.
     
    Last edited: Aug 21, 2020
  6. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,904
    This sounds a little like what I think you were writing:

    When you start a project you just want to see how it goes andyou know 70% will get tossed away and changed. So you set up your data through the Inspector Start. But then you eventually need it to reset, like when they die. Now you've got to write reset() code. That's a huge pain to test. It's better to totally get rid of Inspector stuff. Start calls reset() and dying also calls reset(). You don't have to test the death reset (as much).

    But reset() logic isn't the same as Start() logic: creating the slots for your armour happens once, then reset() sets them all to empty. So you have to split that out. You end up with
    Start() { init(); reset(); }
    .

    You can think of it as the "don't cut and paste" idea. But the goal here is to avoid weird bits of reset() code that run only in special cases. It's much safer, and not that much slower, to have a central shared "recalculate everything" area.
     
  7. Serinx

    Serinx

    Joined:
    Mar 31, 2014
    Posts:
    785
    With every method that you write, you should consider what happens if the parameters and dependencies are null or in an invalid state.

    Do you want to throw a custom error message and exit because something you need is null? (this is a guard clause)
    Do you just want to ignore any nulls in a list you're looping through?
    Do you want to remove all the nulls from the list before looping through?

    Being proactive about the potential errors in every method is a great way to avoid them.

    I would also suggest writing automated code tests for regression testing if you have a very large codebase (this is much easier to do at the start of a project than half way through, depending on how you've written your code).
    Although this can be tricky with MonoBehaviours, you can at least test your own libraries easily - all the more reason to create new independent classes which you can new up in your MonoBehaviour!