Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (497)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
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  
  Avoiding main class to be static. Opinions about this lousy hack  (Read 5068 times)
0 Members and 1 Guest are viewing this topic.
Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Posted 2012-02-07 09:58:24 »

Hey!

I think I've done something smelly, but not sure. I want to access some of my main class, Game, fields (SpriteBatch, change current state, etc.). The solution I was using prior libGDX is to make all fields and methods of Game static (smellrometer overflowing!). But libGDX uses an instance to start the game loop, so I had to change the way I do things.

Now I have a Overlord static class which stores all the important instances (right now is only Game) and provides public static methods for accessing its fields.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
public class Overlord
{
    private static Game game;

    public static Game getGame()
    {
         return game;
    }

    public static void setGame(Game game)
    {
        Overlord.game = game;
    }
}

I have global access to the SpriteBatch (the canvas where I draw) via Overlord.getGame().getSpriteBatch().

In a scale from "good idea" to "worse than unjustified GOTO", what do you think about it?

Offline Regenuluz
« Reply #1 - Posted 2012-02-07 10:14:43 »

My game isn't static at all. I just pass references to the object around to those instances that need a reference. Not sure if this is any way better than what you're doing though. Smiley
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 799
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #2 - Posted 2012-02-07 10:30:15 »

According to your motivational speaker kevglass:

1. Make it work
2. Make it fast enough
3. Make it pretty

in that order.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

JGO Kernel


Medals: 378
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #3 - Posted 2012-02-07 11:19:31 »

All my games work more or less like this and I'm making a living from it. QED

Cas Smiley

Offline Damocles
« Reply #4 - Posted 2012-02-07 11:46:13 »

You can make the game even smaller:

This class does not even need a main function to run:

1  
2  
3  
4  
5  
6  
7  
8  
9  
public class Badbad
{

static {
      System.out.println("Bad Coding");
      for (int i=0;i<8;i++) System.out.println(i);
      }

}


Java will wimmer that there is no MAIN! (oh no) function, but it still runs.

Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Reply #5 - Posted 2012-02-07 13:42:41 »

@Regenuluz: Thanks! I used to keep a private reference to Game in all the classes that made use of it. But there are two problems:

1) it escalates really bad (just imagine you have to access to other two classes, more getters/setters, more fields...)

2) it breaks certain symmetry that my OCD didn't allow to happen. Imagine you use game states. Menu is a child of GameStates which in turn is parent to all kind of menus (pause, game over, main menu, etc.). Probably some menus will make use of Game while others don't. Then what? Include special Game fields in the ones that use it (apart from special constructor and/or getters and setters) which makes every Menu child different, or include a Game field in Menu, which is under-efficient.

So I ended up using a static Overlord XD

@Riven, @princec, @Damocles: Thanks for the advice! I knew about kevglass uber-rules that rule (I still have to improve GettingStarted.part 5...) and it certainly is a relief to know that important gamedevs like yourself think it is not too bad not to use it :_)

Offline tom
« Reply #6 - Posted 2012-02-07 14:54:17 »

Having a global Game is perfectly fine. But you should be aware of where you use it. Consider passing data in as parameters to methods or to the constructor instead of getting the data threw the global Game object. It will reduce coupling. So it would be ok to use it in the Menu screen but maybe avoid it in the Font class.

Also, some personal preferences:

Avoid using setter and getters. Just make the fields public if it is a data heavy class, like tuples. If the data is read only then pass it into the constructor and make the field final.

Avoid using inheritance. Especially if you use it as a way to reuse code.

Offline ReBirth
« Reply #7 - Posted 2012-02-08 03:06:25 »

Yes! someone got this when using libgdx Cheesy

@OP I'll share my current structure

GameWindow
Game (has Bitmapfont, main loop and SpriteBatch)
|_____> all states (Game as constructor ref)
            |_____> entities (Game as constructor ref too, so each entity can grab delta time, keyinput, SpriteBatch which is public)

Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Reply #8 - Posted 2012-02-08 08:56:47 »

[...] Consider passing data in as parameters to methods or to the constructor instead of getting the data threw the global Game object. It will reduce coupling. So it would be ok to use it in the Menu screen but maybe avoid it in the Font class.

I don't understand that, especially: "Consider passing data in as parameters to methods or to the constructor instead of getting the data threw the global Game object". Do you mean something like this example?
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
// good
public void draw(SpriteBatch sb)
{
    mySprite.draw(sb);
}

// smelly
public void draw()
{
    mySprite.draw(Overlord.getGame().getSpriteBatch());
}


Or do you mean to have Overlord to return data instead of an instance of Game?
1  
2  
3  
4  
public void draw()
{
    mySprite.draw(Overlord.getSpriteBatch());
}


Avoid using setter and getters. Just make the fields public if it is a data heavy class, like tuples. If the data is read only then pass it into the constructor and make the field final.

I agree. By default I always use getters/setters and never public fields (Effective C++ can be really convincing), but for some read-only fields I think the final field + value passed as constructor parameter could be 1) logically better, 2) prettier :-)

Avoid using inheritance. Especially if you use it as a way to reuse code.

I mainly use it because of polymorphism (I have a GameState field, but store a Menu, a Level, or Cinematic, which are children of GameState).

But also for code reuse. Menu has the methods to check whether the user has touched a menu entry and to call the appropriate Command to execute. So MainMenu, PauseMenu, GameOverMenu, and so do not have to repeat that piece of code.

What is your alternative?

GameWindow
Game (has Bitmapfont, main loop and SpriteBatch)
|_____> all states (Game as constructor ref)
            |_____> entities (Game as constructor ref too, so each entity can grab delta time, keyinput, SpriteBatch which is public)

What do you accomplish by using a local reference to Game instead of having it accessed globally? For an entity-heavy game you could end up with 100+ local references to Game. Isn't it better to use only one reference that is globally accessible?

Thanks for your comments, I'm enjoying very much knowing how other people have dealt with these problems :-)

Offline princec

JGO Kernel


Medals: 378
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #9 - Posted 2012-02-08 09:52:25 »

I use a fairly reasonable amount of inheritance - usually no more than 3 or 4 levels deep - because composition in Java is ugly boilerplate and basically slower to code and a bitch to maintain vs. inheritance.

Cas Smiley

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

JGO Kernel


Medals: 378
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #10 - Posted 2012-02-08 09:54:10 »

What do you accomplish by using a local reference to Game instead of having it accessed globally? For an entity-heavy game you could end up with 100+ local references to Game. Isn't it better to use only one reference that is globally accessible?
Honestly, not much. I use the global method. Not only is it used by just about every class in the system, it's also effectively a singleton; it simply doesn't make a lot of sense to pass it around everywhere unless you're of a mind to do unit testing. If you're doing unit testing for your game you've already wasted half your time making the game.

Cas Smiley

Offline ReBirth
« Reply #11 - Posted 2012-02-08 11:42:39 »

You know, we should have a thread where everyone post their structure. Especially from mods.

Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Reply #12 - Posted 2012-02-08 12:05:21 »

You know, we should have a thread where everyone post their structure. Especially from mods.

I think it's a fantastic idea! I would learn a lot from other people structures and from other people complains about mine.

Offline tom
« Reply #13 - Posted 2012-02-08 12:18:32 »

I don't understand that, especially: "Consider passing data in as parameters to methods or to the constructor instead of getting the data threw the global Game object". Do you mean something like this example?
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
// good
public void draw(SpriteBatch sb)
{
    mySprite.draw(sb);
}

// smelly
public void draw()
{
    mySprite.draw(Overlord.getGame().getSpriteBatch());
}

I meant the first one.

I agree. By default I always use getters/setters and never public fields (Effective C++ can be really convincing), but for some read-only fields I think the final field + value passed as constructor parameter could be 1) logically better, 2) prettier :-)
I meant the opposite. I consider getters/setters as a bad smell and can often be symptomatic of bad design.

What is your alternative?
Composition. Google around and you'll find that most people favor composition over inheritance.

But if all your making is a small game and you don't do unit testing and don't refactor much, then it doesn't matter. Just make it work.

Offline ReBirth
« Reply #14 - Posted 2012-02-08 12:38:27 »

First hit on google: http://www.artima.com/designtechniques/compoinh.html

1998 article but should still apply.

Now wondering where should the thread be made, post about class structure can be long.

Offline OttoMeier

Senior Member


Medals: 4
Projects: 1



« Reply #15 - Posted 2012-02-08 19:06:29 »

There is always a conflict between the right way and the easy way. Atleast its impotant to know the downsides if you go the easy way.  e.g. maintaining a large Application without units test or reading Code with deep inheritance hierachy is a pain.
For me the only way to go fast is go well.

@yuma
global state is bad see why: http://www.youtube.com/watch?v=-FRm3VPhseI
Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Reply #16 - Posted 2012-02-08 22:32:13 »

1  
2  
3  
4  
5  
// good
public void draw(SpriteBatch sb)
{
    mySprite.draw(sb);
}

I meant the first one.

That's good in this case, because all the draw methods are called from Game.draw() and I can pass the SpriteBatch parameter on them. But when things go the other way around (imagine Entity.update() needs information of SomeOtherEntity.getPosition()) then I don't see how to make it. It's just the way I know how to make things work :-(

I meant the opposite. I consider getters/setters as a bad smell and can often be symptomatic of bad design.

That's weird, I consider accessing the field directly to be a bad habit. You are breaking encapsulation for good. I understand that sometimes, when modifying great amounts of data, passing a heavy input parameter to a setter could be less efficient. But accessing the field directly by norm...

Composition. Google around and you'll find that most people favor composition over inheritance.

Hmm, I thought composition was preferred to inheritance when there is no clear is-a relationship, but in my case, MainMenu is-a Menu and Menu is-a GameState. It really don't go further than two/three levels. Also, composition has the great disadvantage of delegating all methods to the implementation (is it more tedious to maintain though might be less coupled to the superclass).


Thanks! I keep it in mind and have to read about composition with interfaces, which the author claims is the real replacement to inheritance.

Maybe it looks I'm just rejecting by default all your advices, but it's not the case. I'm reading and learning with them, even though I might not follow them too strictly. Thank you!

Offline sproingie

JGO Kernel


Medals: 202



« Reply #17 - Posted 2012-02-08 22:41:13 »

MainMenu is-a Menu and Menu is-a GameState.

I'll buy the first, but the second doesn't compute for me at all.

Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Reply #18 - Posted 2012-02-08 22:43:48 »

There is always a conflict between the right way and the easy way. [...] For me the only way to go fast is go well.

I agree with you, completely. But sometimes we can't choose the "right way" because we don't know where it is :-(

Offline ReBirth
« Reply #19 - Posted 2012-02-09 02:22:10 »

Quote
Thanks! I keep it in mind and have to read about composition with interfaces, which the author claims is the real replacement to inheritance.
Honestly I agree with him. Look how easy problem can be solved by interface, and I use interface a lot. Basically it tells you to avoid inheritance and code separately then use interface when you need polymorph.

Offline tom
« Reply #20 - Posted 2012-02-09 08:55:04 »

That's weird, I consider accessing the field directly to be a bad habit. You are breaking encapsulation for good. I understand that sometimes, when modifying great amounts of data, passing a heavy input parameter to a setter could be less efficient. But accessing the field directly by norm...

If you have code like this:
1  
2  
3  
4  
5  
6  
7  
public void setBounds(Rectangle bounds) {
   this.bounds = bounds;
}

public Rectangle getBounds() {
   return bounds;
}

Then all you've done is add boilerplate code that does nothing.

If you've got code like this:
1  
2  
3  
4  
5  
6  
7  
public void setBounds(Rectangle bounds) {
   this.bounds.set(bounds);
}

public Rectangle getBounds() {
   return new Rectangle(bounds);
}

Then fair enough, you've protected your internal state. You should always try to do this.

However you've exposed to the outside that the object has a bounds. The object oriented way would be to have methods on the object that uses the bounds instead of exposing it. So instead of:
1  
2  
3  
4  
5  
public void mousePressed(MouseEvent e) {
    if (object.getBounds().contains(e.getPoint())) {
        object.activate();
    }
}

You could do:
1  
2  
3  
public void mousePressed(MouseEvent e) {
    object.activateIfPointIsInside(e.getPoint());
}


Now in general, things are not black or white. You don't always use one method over another. But knowing about different ways of doing things can help you write better code.

Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Reply #21 - Posted 2012-02-09 09:04:15 »

@tom, @sproingie, @ReBirth: I read Item 16 of Effective Java. This item example is clear on when composition is better than inheritance. It took me long but now I'm convinced that composition is a real alternative, thanks! :-)


Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Reply #22 - Posted 2012-02-09 09:16:17 »

If you have code like this:
1  
2  
3  
4  
5  
6  
7  
public void setBounds(Rectangle bounds) {
   this.bounds = bounds;
}

public Rectangle getBounds() {
   return bounds;
}

Then all you've done is add boilerplate code that does nothing.

Stupid, stupid me! You are so right that I feel ashamed! I translated from C++ without realizing it doesn't work like this in Java.

However you've exposed to the outside that the object has a bounds. The object oriented way would be to have methods on the object that uses the bounds instead of exposing it. So instead of:
1  
2  
3  
4  
5  
public void mousePressed(MouseEvent e) {
    if (object.getBounds().contains(e.getPoint())) {
        object.activate();
    }
}

You could do:
1  
2  
3  
public void mousePressed(MouseEvent e) {
    object.activateIfPointIsInside(e.getPoint());
}


That makes sense, but I'm not sure I know how to implement it in the design I have so far :_(

Ok, the thing I get from this discussion is I have to keep reading/learning to improve my code AND kevglass/Riven advice 1) make a game, 2) make it efficient enough so it is fast, and 3) make it pretty. I'll try to advance in both paths in parallel!

Offline dishmoth
« Reply #23 - Posted 2012-02-09 10:03:49 »

2) make it efficient enough so it is fast
Kev's actual advice is "Make it quick enough."
Or to put it another way, make it efficient enough so it is not slow.
A subtle but important difference. Wink
Simon

Offline princec

JGO Kernel


Medals: 378
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #24 - Posted 2012-02-09 11:12:27 »

In general I find that exposing the fields of objects makes my toes curl and hang my head in shame, and I've always tried to design systems such that no such access is required for classes of any reasonable abstraction beyond what amounts to a struct (eg. tuples and such).

But the longer I code games and need to get shit out of the door the more I find myself bodging them in to get something to work quickly. Game ships, money is made, the Perfect Code Angel quietly weeps and the Great Pile Of Money Daemon cackles.

Cas Smiley

Offline yuma

Junior Member


Medals: 2
Projects: 1


Monkeys are listening


« Reply #25 - Posted 2012-02-10 09:03:01 »

I've unleashed the power of the medal gatling to appreciate all your contributions.



Thanks for making this thread so helpful to me :-)

Offline ReBirth
« Reply #26 - Posted 2012-02-10 11:38:00 »

But the longer I code games and need to get shit out of the door the more I find myself bodging them in to get something to work quickly. Game ships, money is made, the Perfect Code Angel quietly weeps and the Great Pile Of Money Daemon cackles.

Cas Smiley
Yes yes! work first! Grin

Offline ra4king

JGO Kernel


Medals: 345
Projects: 3
Exp: 5 years


I'm the King!


« Reply #27 - Posted 2012-02-11 00:07:32 »


GREATEST THING I HAVE EVER SEEN!!!!!!!!

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.

BurntPizza (22 views)
2014-09-19 03:14:18

Dwinin (35 views)
2014-09-12 09:08:26

Norakomi (62 views)
2014-09-10 13:57:51

TehJavaDev (87 views)
2014-09-10 06:39:09

Tekkerue (42 views)
2014-09-09 02:24:56

mitcheeb (65 views)
2014-09-08 06:06:29

BurntPizza (47 views)
2014-09-07 01:13:42

Longarmx (35 views)
2014-09-07 01:12:14

Longarmx (40 views)
2014-09-07 01:11:22

Longarmx (36 views)
2014-09-07 01:10:19
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

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!