views:

498

answers:

6

Whenever I try to write graphical programs (whether a game or really any GUI app) I always wind up with one or two god classes with way too many methods (and long methods, too), and each class having far too many responsibilities. I have graphics being done at the same time as calculations and logic, and I feel like this is a really bad way to go about organizing my code. I want to get better at organizing my code and abstracting out responsibilities to different classes. Here's an example of where I'd like to start - I want to write a Minesweeper clone, just sort of as practice and to try to improve my software engineering skills. How would I go about making this nice and object-oriented? For the sake of discussion, let's just say I'm using Java (because I probably will, either that or C#). Here's some things I would think about:

  • should each tile inherit from JButton or JComponent and handle drawing itself?
  • or should the tiles just be stored as some non-graphical MinesweeperTile object and some other class handles drawing them?
  • is the 8-segment display countdown timer (pre-Vista, at least) a separate class that handles drawing itself?
  • when the user clicks, do the tiles have mouse event listeners or does some other collision detection method loop through the tiles and check each one to see if it's been hit?

I realize that there's not just one way to write a GUI application, but what are some pretty basic things I can start doing to make my code more organized, manageable, object-oriented, and just over all write better programs?


edit: I guess I should add that I'm familiar with MVC, and I was originally going to incorporate that into my question, but I guess I didn't want to shoehorn myself into MVC if that's not necessarily what I need. I did searched for topics on MVC with GUI apps but didn't really find anything that answers my specific question.


edit2: Thanks to everyone who answered. I wish I could accept more than one answer..

+2  A: 

use a MVC framework that handles all the hard organization work for you. there's a ton of MVC framework topics on SO.

using high quality stuff written by others will probably teach you faster - you will get further and see more patterns with less headache.

Dustin Getz
MVC provides a clean separation of concerns; look no further
Steven A. Lowe
A: 

Sorry to say it, but it seems you have mess in your head trying to improve your coding too much in one step.

There is no way to answer your question as such, but here we go.

First start with OOP, think about what objects are required for your game/GUI and start implementing them a little at a time, see if there are chances to break up these objects further, or perhaps reunite some objects that make no sense on their own, then try to figure out if you have repeated functionality among your objects, if you do, figure out if this repeated functionality is a (or many) base class or not.

Now this will take you a few days, or weeks to really grok it well, then worry about dividing your logic and rendering.

Robert Gould
+2  A: 

I'm not suggesting this is the only way to do it, but what I would suggest is something like the following. Other people, please feel free to comment on this and make corrections.

  • Each tile should inherit from something and handle drawing itself. A button seems like the best solution because it already has the button drawing functionality (pressed, unpressed, etc) built in.
  • Each tile should also be aware of its neighbors. You would have eight pointers to each of its eight neighbors, setting them to null of course if there is no neighbor. When it goes to draw, it would query each neighbor's IsMine() function and display the count.
  • If none of its neighbors are a mine, it would then recurse into each neighbor's Reveal() method.
  • For the 7-segment display, each digit is its own class that handles drawing. Then I would make a CountdownSegmentDigit class that inherits from this class, but has additional functionality, namely CountDown(), Set(), and Reset() methods, as well as a HitZero event. Then the display timer itself is a collection of these digits, wired up to propagate zeroes left. Then have a Timer within the timer class which ticks every second and counts down the rightmost digit.
  • When the user clicks, see above. The tile itself will handle the mouse click (it is a button after all) and call its Reveal() method. If it is a mine, it will fire the MineExploded event, which your main form will be listening to.

For me, when I think of how to encapsulate objects, it helps to imagine it as a manufacturing process for physical parts. Ask yourself, "How can I design this system so it can be most efficiently built and reused?" Think about future reuse possibilities too. Remember the assembly process takes small pieces and builds them up into larger and larger pieces until the entire object is built. Each bit should be as independent as possible and handle its own logic, but be able to talk to the outside world when necessary.

Take the 7-segment display bit, you could have another use for it later that does not count down. Say you want a speedometer in a car or something. You will already have the digits that you can wire up together. (Think hardware: stock 7-segment displays that do nothing but light up. Then you attach a controller to them and they get functionality.)

In fact if you think hard enough, you might find you want CountUp() functionality too. And an event argument in HitZero to tell whether it was by counting up or down. But you can wait until later to add this functionality when you need it. This is where inheritance shines: inherit for your CountDownDigit and make a CountUpOrDownDigit.

Thinking about how I might design it in hardware, you might want to design each digit so it knows about its neighbors and count them up or down when appropriate. Have them remember a max value (remember, 60 seconds to a minute, not 100) so when they roll over 0, they reset appropriately. There's a world of possibilites.

lc
I'm going to wait and see if anyone else responds, but in the very short time since I've asked this question, I really like your explanation, lc. It sort of confirms my suspicions about everything I'm doing wrong and everything I should be doing but aren't.
dancavallaro
Glad I could help. I would also advise you to go with your gut feelings. If you think a class has too many responsibilities, it probably does. In my book, each object should be responsible for itself, supervising any children, and informing other objects of significant state changes.
lc
I would separate the tile data/behaviour from the rendering. When you want to move away from a desktop app to web, or Swing to JavaFX, you won't be tied to the Button. You can do this by either: the tile publishing events to listeners, or the UI drawing a representation of the data in the button.
jamesh
+7  A: 

Here is a simple (but effective) OO design to get you started:

First create a Game object that is pure Java/C# code. With no UI or anything else platform specific. The Game object handles a Board object and a Player object. The Board object manages a number of Tile objects (where the mines are). The Player object keeps track of "Number of turns", "Score" etc. You will also need a Timer object to keep track of the game time.

Then create a separate UI object that doesn't know anything about the Game object. It is completely stand alone and completely platform dependent. It has its own UIBoard, UITile, UITimer etc. and can be told how to change its states. The UI object is responsible for the User Interface (output to the screen/sound and input from the user).

And finally, add the top level Application object that reads input from the UI object, tells the Game what to do based on the input, is notified by the Game about state changes and then turns around and tells the UI how to update itself.

This is (by the way) an adaption of the MVP (Model, View, Presenter) pattern. And (oh by the way) the MVP pattern is really just a specialization of the Mediator pattern. And (another oh by the way) the MVP pattern is basically the MVC (Model, View, Control) pattern where the View does NOT have access to the model. Which is a big improvement IMHO.

Have fun!

MB
You have an excellent model. I think it does depend on the game you're trying to implement, however. In the Minesweeper case, I feel the UI is the board. There is no AI, or moving objects (or objects that change states independent of the user), so there is no need(?) for a separate game logic layer.
lc
What? No, the UI never is the board. There is an object which changes states a lot: the board. You have an event (user selects one field) and a response (some fields may be uncovered, or the game may end). Sounds like quite some logic to me.
Joachim Sauer
A: 

I have some tutorials that are written in C#. It discusses this very same topic. It is a starting point for a RogueLike game.

Object Oriented Design in C# Converting Legacy Game

Object Oriented Design: Domain Type Objects

Object Oriented Design: Rethinking Design Issues

Object Oriented Design: Baby Steps in Acceptance Testing

Gutzofter
A: 

The central concern of a Graphic User Interface is handling events. The user does X and you need to response or not respond to it. The games have the added complexity in that it needs to change state in real time. In a lot of cases it does this by transforming the current state into a new state and telling the UI to display the results. It does this in a very short amount of time.

You start off with a model. A collection of classes that represents the data the user wants to manipulate. This could represent the accounts of a business or vast frontiers of an unknown world.

The UI starts with defining a series of forms or screens. The idea is that is for each form or screen you create a interface that defines how the UI Controller will interact with it. In general there is one UI Controller classes for each form or screen.

The form passes the event to the UI Controller. The UI Controller then decides which command to execute. This is best done through the Command design pattern where each command is it own class.

The Command then is executed and manipulate the model. The Command then tells the UI Controller that a screen or a portion of a screen needs to be redraw. The UI Control then looks at the data in the model and uses the Screen Interface to redraw the screen.

By putting all the forms and screen behind a interface you can rip out what you have and put something different in. This includes even not having any forms at all but rather mock objects. This is good for automated testing. As long as something implements the Screen Interface properly the rest of the software will be happy.

Finally a game that has to operate in real time will have a loop (or loops) running that will be continually transforming the state of the game. It will use the UI Controller to redraw what it updated. Commands will insert or change information in the model. The next time the loop comes around the new information will be used. For example altering a vector of a object traveling through the air.

I don't like the MVC architecture as I feel it doesn't handle the issues of GUIs well. I prefer the use of a Supervising Controller which you can read about here. The reason for this is that I believe automated tests are one of the most important tools you have. The more you can automate the better off you are. The supervising presenter pattern makes the forms a thin shell so there is very little that can't be tested automatically.

RS Conley