Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Managing gamestates and entities, singletons  (Read 2130 times)
0 Members and 1 Guest are viewing this topic.
Offline brollysan

Junior Devvie


Medals: 1



« Posted 2013-04-08 15:47:35 »

I am currently in the progress of refactoring my entire code and the singleton approach seems the easiest to me as this is a tilebased RPG game ala Zelda and there is at most ONE instance of the game. There is a whole lot of hate against the singleton (SO hates it) and I can't seem to think of a better way to manage everything in my game. Instead of worrying all the time that I may have created a duplicate of my rendering class or my sfx class I can instead focus on making those classes much more powerful.

One of the downsides I see is that it makes for very sloppy code, the game will work IF and only IF you order the code in a certain way so as to not call something that has not yet been set (or do nullchecks every...sloppy). Are there any other downsides? What is a better way to manage resources and entities and logic and rendering and sfx? What are your experiences with singletons?
Offline actual

JGO Coder


Medals: 24



« Reply #1 - Posted 2013-04-08 17:29:49 »

Some scattered thoughts:

What are the odds that you will accidentally create a new rendering system, audio system, or game instance? I would guess it would be pretty low and so it shouldn't be something you spend a lot of time worrying about.

The order of operations issue you raise will happen whether you use singletons or not.

The issue seems to be more one of convenient access. You have these "system" classes like rendering and sound and you need to be able to get at them easily from anywhere in the code base.

The problem I have with singletons is that they become global variables and as such they tend to get used everywhere. This means your classes may have lots of dependencies and becomes harder to reason about. They can also reveal too much about how something is being done. It is sometimes better to better to hide "System" classes and reduce their scope.

As an example, my game uses message passing. So I had a base Event class from which concrete events (ExplosionEvent, ShipArriveEvent) inherit. These were all managed by an EventSystem. Because anything could send an Event, I made the eventSystem a public static field in my game class. I used it like so:

1  
2  
// Code inside my Missile entity letting a nearby ship know that it has exploded.
MyGame.eventSystem.addEvent(new ExplosionEvent(ship,xPos,yPos,damageScore));


A couple of issues:
1. The Missile (and anything else that sends an Event) is coupled to EventSystem.
2. The Missile is also coupled to MyGame because it needs to be able to get the eventSystem reference.
3. Why does the Missile care about how Events are sent?

So I made a few changes. I created a private static EventSystem field in the base Event class and added a public static setEventSystem() method. I also added a "post()" method to the Event:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
public abstract class Event {
   
   private static EventSystem eventSystem;

   // Associate an EventSystem with all Events
   public static void setEventSystem(EventSystem es) {
      eventSystem = es;
   }

   // Posts the event to the event system.
   public void post() {
      Event.eventSystem.addMessage(this);
   }
}

// In my game initialization code I have something like this
EventSystem eventSys = new EventSystem();
Event.setEventSystem(eventSys);


// So now back in my missile class I use it like:
new ExplosionEvent(ship,xPos,yPos,damageScore).post();


The dependancy is hidden within the Event class. The only thing senders care about is the specific Event they are creating and, semantically, "post()" exists at a better level of abstraction than "eventSystem.addEvent()".

How big of a difference does this make? In this one case, not a huge difference, but as globals and systems pile up, it can start to add up.




Offline Geemili

Senior Devvie


Medals: 9
Projects: 1
Exp: 2 years


No Games Finished


« Reply #2 - Posted 2013-04-08 21:54:24 »

I don't know if singletons are the way to go, and certainly aren't the simplest way, but I am using singletons myself. I handle this similar to a way minecraft handles blocks. However, unlike minecraft, I use two classes; an Entity class, which holds information, and an Abstract Controller class, which does the logic.

The abstract Controller has a few static variables/functions. Here is the basic code:
1  
2  
3  
4  
5  
6  
private static Controller[] controllers = new Controller[128];

public static Controller getController(int id) {
    if(id<0 || id>controllers.length) return null;
    return controllers[id];
}

This is where minecraft stops, and where minecraft gets block/item ids (assuming you've played enough minecraft to know that).

I take it a bit further. To increase compatibility/readability, I include a static HashMap:
1  
2  
3  
4  
5  
6  
private static HashMap<String, Integer> names = new HashMap<String, Integer>();

public static Controller getController(String name) {
    if(names.containsKey(name)) return getController(names.get(name));
    return null;
}


Next, we need to make a few controllers, but first they need a way to be added to the list. So in our abstract class, add in the following constructor/variables:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
public final int id;
public final String name;
public Controller(String name) {
    for(int index=0; index<controllers.length; index++) {
   if(controllers[index]==null) {
       controllers[index] = controller;
       names.put(name, index);
       id = index;
            this.name = name;
        }
    }
}


Now, anytime we make one of our singleton controllers, it will be kept in our array of controllers. The last things to do are make something for the controllers to act on, and make the controllers act on it. I handled this by first making an entity class that has its controllers id:
1  
2  
3  
public class Entity {
    public int controllerId;
}


Then I made an update function in the Controller class:
1  
2  
3  
public void update(Entity entity) {
    //do stuff
}


And an update function in the Entity class:
1  
2  
3  
public void update() {
    Controller.getController(controllerId).update(this);
}


And that is about all for basic singleton Controllers. Of course, you will have to add in more, like an x and y to the Entity class, but I think you can figure that out yourself.   Cheesy
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline jobiho

Senior Newbie





« Reply #3 - Posted 2013-04-11 21:10:49 »

You should avoid singletons wherever you can.
The singleton is reasonable called an anti pattern.

How would you unit-test a singleton?
Offline Grunnt

JGO Kernel


Medals: 95
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #4 - Posted 2013-04-12 09:23:41 »

You should avoid singletons wherever you can.
The singleton is reasonable called an anti pattern.

How would you unit-test a singleton?

Who actually unit-tests game code anyway? And what makes unit-testing a singleton particularly difficult? The reasoning "do not use singletons because it is an anti-pattern" basically says: "do not use singletons because do not use singletons", which is no reason at all.

I use singletons & static functions for certain things and they work just fine. Practice overrules theory as far as I'm concerned. Some things I found singletons to be useful for accessing a global asset manager, the graphics and sound modules, preferences, and some other stuff that needs to be accessed everywhere. For these things using a singleton is much cleaner and more manageable than passing around masses of objects everywhere around your code-base.

That said, like anything in coding you have to take care in using singletons. I try to avoid singletons that allow changes to game state (e.g. an entity system that may be accessed anywhere), as this tends to make debugging much more difficult.

Offline StrideColossus
« Reply #5 - Posted 2013-04-12 09:41:14 »

You should avoid singletons wherever you can.
The singleton is reasonable called an anti pattern.

Any pattern or language construct can be an anti-pattern when used badly or in the wrong circumstances.  Singletons are often used for the wrong reasons or implemented incorrectly, but they do have their place, a good example is to access the 'global' sound system when using OpenAL.

Who actually unit-tests game code anyway?

Burn him! Wink
Offline Grunnt

JGO Kernel


Medals: 95
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #6 - Posted 2013-04-12 09:53:02 »

Singletons are often used for the wrong reasons or implemented incorrectly

I plead guilty Grin You are right though, the primary use I see is in these global systems, not many other cases.

Offline 65K
« Reply #7 - Posted 2013-04-12 10:14:40 »

Who actually unit-tests game code anyway?
Everybody who likes to save development time and raise the overall quality level.

Offline jobiho

Senior Newbie





« Reply #8 - Posted 2013-04-12 10:33:50 »

Quote
Who actually unit-tests game code anyway?
Well I hope some people do Smiley

Quote
And what makes unit-testing a singleton particularly difficult?
When it comes to unit testing you need a clearly defined state of the class you want to test.
When not using a singleton, a simple
1  
new Foo();
provides you a fresh instance and a clean state.

But how can you ensure that for a singleton?
By definition there is only one instance of it and you can not be sure that it's state is what you expect it to be which makes testing it very very hard and error prone.
So your only chance would be to implement a method to reset the state of your singleton which again is error-prone.
Offline Grunnt

JGO Kernel


Medals: 95
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #9 - Posted 2013-04-12 12:13:35 »

But how can you ensure that for a singleton?

You are right of course, thanks for the heads up.

Everybody who likes to save development time and raise the overall quality level.

Perhaps if you're working in a (large) team and in some specific use-cases this is true. For me it just feels like keeping 2 rapidly evolving code-bases in sync (the code itself and the unit test code meant to test it), resulting in a load of extra work and very little extra value. Maybe for someone who has a different approach to coding it works better.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline StrideColossus
« Reply #10 - Posted 2013-04-12 12:28:32 »

Perhaps if you're working in a (large) team and in some specific use-cases this is true. For me it just feels like keeping 2 rapidly evolving code-bases in sync (the code itself and the unit test code meant to test it), resulting in a load of extra work and very little extra value. Maybe for someone who has a different approach to coding it works better.

I think you're making a mistake in considering unit-test code to be 'extra work' and 'little value', this is often the response I get from new or junior engineers (not meant to be a slur btw!) who have yet to have the epipheny moment.  Personally I now feel nervious (and dirty persecutioncomplex) if I have code that doesn't have comprehensive test coverage.

There are some obvious positives to unit-testing:

- It's a lot easier to fix any bugs or design flaws when the code is fresh in your memory, rather than finding them days or even years later.

- Sections of code are often inter-related (especially highly coupled code like deep inheritance hierarchies), you make a change here and might inadvertently knacker something in an unrelated section over there, how are you going to ensure all your code still works after making changes without a test suite?

But there are some more subtle benefits as well:

- If you develop the unit-tests and code in parallel you are effectively exercising your design as you code, i.e. you become a sort of 'user', and can therefore spot and resolve any design flaws sooner rather than later.  I've often found myself thinking "this sucks" and completely redesigning a class or package.

- Unit-tests are also essentially documentation for how to use your code, again handy if you come back to re-use a chunk of code and need a refresher on how it works.

Of course if you're a hobbyist then you can do what you like Smiley but I'd advice you to give the above some consideration.  Try it, you might just like it.
Offline ReBirth
« Reply #11 - Posted 2013-04-12 12:40:09 »

I have fairly acceptable reasons to use singleton: audio and player's data (score etc). Still doing it.

Offline Grunnt

JGO Kernel


Medals: 95
Projects: 8
Exp: 5 years


Complex != complicated


« Reply #12 - Posted 2013-04-12 13:30:46 »

Of course if you're a hobbyist then you can do what you like Smiley but I'd advice you to give the above some consideration.  Try it, you might just like it.

Haha, you tell a convincing story Grin For my hobby project which I'm working on alone it still seems to be too much overhead, but especially on large complex projects with multiple people working on it I can see how it would be great (maybe even indispensable). I may play around with it a bit.

Offline actual

JGO Coder


Medals: 24



« Reply #13 - Posted 2013-04-12 14:20:48 »

I prefer not to use singletons/static methods because it makes my code less OOP-like and more procedural which (for me) is harder to reason about. I have never personally had a case where I accidentally created additional instances when I only mean to have one. My biggest driver is that I have some service that is needed all over the place and a public static reference is just very convenient. I have not found an alternative solution to this that was satisfactory other than to try and design my code to limit the scope these static fields/methods need to have.
Offline ctomni231

JGO Wizard


Medals: 99
Projects: 1
Exp: 7 years


Not a glitch. Just have a lil' pixelexia...


« Reply #14 - Posted 2013-04-12 19:42:18 »

Who actually unit-tests game code anyway?

At first, I thought unit testing was a bunch of bologna. However, there are two types of errors in coding. The first is syntax, which is the errors that you can find because your compiler says so. The second type is logic, which usually means that you have to set up breakpoints and search through to find the error yourself.

Unit tests fall into the latter category. They allow you to snapshot your code so you can find out when something is not working logically. The time unit tests become very useful is when your project becomes very large and you want to change a small section. Those tests will prevent you from having to use breakpoints completely (in some cases) and get your code working faster.

I don't recommend it for small projects, but for any project that is very big. Writing those tests can become very beneficial in saving time looking for logic breaks.

Offline HeroesGraveDev

JGO Kernel


Medals: 310
Projects: 11
Exp: 3 years


┬─┬ノ(ಠ_ಠノ)(╯°□°)╯︵ ┻━┻


« Reply #15 - Posted 2013-04-12 20:40:06 »

In most cases, you can use static instead of singleton.
I use static where possible because it's less typing. But if singleton became more convenient in a certain situation, then I would use it for that instance.

In the end, do what's convenient for you (unless you're working on a team Pointing).

Don't worry about following OOP rules if breaking them results in better code/coding.

Programming standards are a lie. persecutioncomplex Using combinations of different standards results in the nicest code.

Offline ReBirth
« Reply #16 - Posted 2013-04-13 12:11:06 »

I thought singleton is static thing, just wrapped in nicer dress.

Offline sproingie

JGO Kernel


Medals: 202



« Reply #17 - Posted 2013-04-17 15:43:46 »

One of the nice effects of sticking to a unit testing regime is that you tend to design your code for testability.  By forcing a little self-contained use-case into every unit (which usually means every public method that isn't just an accessor), you try to avoid coupling and sneaky side effects, which are both great qualities for any codebase.

A slightly more nuanced view of singletons: http://beust.com/weblog/2011/03/10/rehabilitating-the-singleton-pattern/

I don't agree 100% with the broad categorical conclusions he makes, but the overall gist is good.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (34 views)
2014-12-15 09:26:44

Mr.CodeIt (25 views)
2014-12-14 19:50:38

BurntPizza (52 views)
2014-12-09 22:41:13

BurntPizza (85 views)
2014-12-08 04:46:31

JscottyBieshaar (47 views)
2014-12-05 12:39:02

SHC (61 views)
2014-12-03 16:27:13

CopyableCougar4 (63 views)
2014-11-29 21:32:03

toopeicgaming1999 (125 views)
2014-11-26 15:22:04

toopeicgaming1999 (115 views)
2014-11-26 15:20:36

toopeicgaming1999 (33 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!