Design question: linking GUI - domain

Started by
4 comments, last by Sam08 13 years, 9 months ago
I'm developping a simple pokemonlike clone, and I've run into a confusing design problem:

Right now, I'm using an interface (abstract class in C++) to connect my controllers to the GUI. This way my controller can make calls to the gui, for example show a message.
You probably all know the pokemon games, so what I really need from the gui is a method to show a message, and a method that allows the user to pick from a list of options (list of strings).
Due to their nature, these calls are blocking calls and the GUI needs to run in a seperate thread. Futhermore, as I understand it, in good design, the GUI is prohibited from performing any logic of itself and simply passes events to the controllers, such as user input, which is then handled by the appropriate controller. (according to the Model View Controller pattern)

Now (finally) my questions are the following:
1. The call that lets the user choose from a list of options displays the list on screen and lets the user pick from it using the arrow buttons. This means that the GUI needs to handle input when the user is busy choosing an option, the result is then passed on to the controller to complete the function call. So not all input is passed on to the controller (cf 'Chain of command' pattern). Does this violate the rules of good software design?

2. I developped the GUI interface before i actually developed the GUI. The interface had a draw function which was called every frame by the controllers. However, since i need a seperate thread to support the blocking calls, the draw function has lost its use, because the GUI needs to be drawn when the user is choosing from among options! Again, does this violate any rules as far as desing goes? It seems to me that every good GUI interface has a draw function.

3. I need a few simple animations when attacks are made. For example make the screen flash. These animations need to be programmed. (By the way, I'm using directx for this project) Should these animations be supported by the GUI? Or should they be done by the controller? Should it be the controllers responsibility to change on-screen coordinates. A good example of this problem is the intro animation. At first the player sprite appears, then the player sprite moves offscreen and makes room for a monster sprite. If this is done by the controller, this would involve being able to set the GUI in 'playermode' to ensure that a player sprite is drawn on the player's side of the screen, and fiddling with the on screen coordinates with a setPlayerCoordinates(int x, int y) function, which would in turn again expand the GUI interface. I have another problem with setting the screen coordinates, namely that they do not prevent misuse. Doing the animation in the GUI does not solve much imo. Any ideas?

There are more of these problems I won't bother you guys with, but if you could help me out by pointing me in the right direction with above question, I would be grateful. I have little to no experience programming GUI, so any general advice as to how to link the GUI to the domain would be useful too.

Thanks in advance,

Sam
Advertisement
1. Seems reasonable enough; it's actually pretty common to "filter" input this way. In fact, implementing input handling as Chain of Responsibility is one of my preferred methods - and one we've used successfully in 2 shipped titles and 1 under development. So I'd say you're safe [wink]

2. Don't worry too much about the "rules." There are no hard and fast rules, including this one. Every guideline has an exception, and every principle has caveats. If you find a clean solution that doesn't have a Draw() function in your interface, cool; what's important is that you have a solution that produces good, maintainable code in your situation. What works great for my design may not work at all for yours - and vice versa.

3. IMHO you shouldn't be doing things like setting coordinates from your domain code. That's solely the responsibility of the GUI system, and anything that specific belongs inside some kind of encapsulation. Otherwise, you'll end up with very brittle code, and little tiny bits of graphical effect implementations scattered who knows where. Instead, have the domain code request that the GUI play an animation or effect; this can be done with a non-blocking call that simply queues up the effect and someone else comes along and handles it internally later. I'd suggest more details but I'm not sure how the guts of your GUI system are built so I can't really get too specific; feel free to post up a description of how your rendering is set up and I'll see if I can suggest a good route for integrating the animation stuff.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Thank you for your clear and swift reply!

I'll try running the animations like you said by queueing them up and let the main GUI handle them.
I've run into another design problem concerning programmed animations:

Allow me to explain the inner workings of my GUI rendering a bit (for the moment only battles are supported, so no walking on worldmaps or anything of the kind):

- I have an abstract class GUI which acts as the interface for the main battleController and supports methods like showMessage(std::string msg), chooseOption(std::vect < std::string >) and playAnimation(Animation animation). During construction the GUI object starts up a thread and every frame calls its draw() method which needs to be implemented by its subclass. This class also tries to abstract the use of directx by starting up the direct3d device and sprite handler before calling the draw() function and properly ending these after use. Finally it supports another drawImage() function which allows drawing of a given image at a given position on screen.

- BattleGUI is my subclass of the GUI class. It implements above mentioned draw(void) method and playAnimation(Animation animation).

Right now i'm trying to figure out how to implement the animation class. An animation needs to be able to draw Images on screen on different frames. And these animations should be stacked by the controllers in the gui (as ApochPiQ mentioned). I'm thinking of centralizing the images in a static ImageFactory, so the animation can freely request images and draw them on screen.
So now I'm thinking, if the animations can draw images on screen, why not let my HUD(eg healthbar) be an animation consisting of a single frame. If this is the case, all drawing is done by the animations, not by the main gui object. So should i rethink above design? How then would i abstract the use of directx? Or should the draw function of BattleGui just draw all the animations?
Generally speaking, is this a good way to do programmed animations? If my HUD is an animation, how could that relate to the stacking of animations considering it needs to be drawn every frame? Or should my BattleGUI just draw the HUD and then draw animations (if any)?

Right now I'm also doubting between two forms of animation. First of, I could have an image containing all the frames, and draw the right frame on screen (lathough this approach seems a litte hard for a pokemon clone). Second I could just have one image and let the animation move it on screen based on the current frame. The latter uses smaller image sizes and seems more appropriate for pokemon since most animation just moves the monster about a bit.

Thanks,

Sam
From a graphics efficiency point of view, it's better to pack multiple frames into a single image so that you're not switching textures as often. You won't get much gain out of packing all the frames of a single character's animation together, as you'll usually only be drawing one of them per frame anyway, but you'd definitely benefit from packing e.g. all the HUD parts into one texture.

The main reason that characters in Pokemon only tend to move about / stretch-squish / recolour / etc is because of the limited storage space on the platform. If you're working on PC, and you've got the time to create more detailed animations, then you're free to do that.

Re stacking: I'd give each active GUI element a Z-index. Keep all the elements sorted by Z-index and then draw them in that order.

The idea of having all GUI elements be single-frame animations seems reasonable to me, but if the animations you're doing are more transform effects (moves, stretches, recolours, etc) then you might be better off with a setup where each GUI element is a single frame, but can have an animation attached to it. Then you can have a library of animations that, if one is set, becomes responsible for drawing the GUI element.

Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse

Thanks for your reply.

With the stacking of animations, I meant queueing them up before playing them, not drawing the GUI elements in the correct order (my bad).
The problem is that if I let the controller queue up animations, they can only be processed one at a time by the GUI even though the GUI runs in a seperate thread. If my HUD elements where one-frame animations, this would mean that the controller needs to add them to the GUI's queue every frame, and imo, the controller shouldn't be responsible for the HUD in any way. Besides if a long animation was queued up, it could be a while before the HUD is redrawn this way.

I'm also hand sketching my sprites, so to save time (There are multiple monsters, so every animation should be hand drawn for every monster in the game, multiply that by the amount of frames...) I'd like to restrict my animations to transformations as much as possible (with a few exceptions).

I am rather curious about your last paragraph, about attaching the animations to a GUI element? Do you mean like a decorator pattern? Or just pass the drawing of the GUI element to its animation if any. I also don't quite understand how this ties in to a library of animations?

Thanks again!

Sam

This topic is closed to new replies.

Advertisement