Thursday, July 9, 2009

I know the basics of OOP in C++ now I am ready to start GUI programming, suggestions anyone?

Okay I been looking around and reading and such, and I keep getting mixed messages about the next step to take for starting gui programming in C++.. Like should I start out with learning MFC, but then again from what I hear that is just good for creating small applications. Or should I just go straight to the win32 api and start working from scratch with the windows library? From what I heard that is good for making games and complex applications. There is also this thing I heard about called WTL, which seems to also be good for making gui applications... Sooo I don't really know where to start, OH btw the type of stuff I want to make is mostly games but I would like to know how to make simple quick applications to. SOOO, any suggestions on what I should do?

I know the basics of OOP in C++ now I am ready to start GUI programming, suggestions anyone?
This really isn't a good answer to your question, but you may want to look into C# too. It's kind of a combination of C++, Java, and VB. It has a simple GUI design interface, but it still allows you a lot of control. Not quite as much as C++, but more than Java. Just an idea for you to ponder ...
Reply:Design your game such that the focal point of all your logic is the objects in the game that the user manipulates and observes.





Read up on the Model-View-Controller (MVC, for short) pattern. The basics of it are so simple, you will think it is crazy that so many people do not "get it". Just do the following.





Create a base class, called Model. Subclass it with classes that represent things that are the focus of the game.





Encapsulate any fields that hold changeable field values if they are ones that when they change - other things in the game will need to be updated, or something on the screen will need to be updated.





If you do it right, you can pretty much just write/test your game's core logical initially with a text based UI, or just by hardcoding some method calls on your model objects to test them.





The trick to it all, is that in your Model class(es), you need to have an addDependentModel and addDependentView method. Those take a Model and a View, respectively, as their arguments.





Internally, have a simple list for dependentModels and dependentViews.





When a Model object changes its state of one of the "interesting" encapsulated field values, notify first all the dependent Model objects, then all the dependent View objects.





How is this done? Have an changed() method in the base class, Model.





Make it have it call 2 other methods in this same class, called notifyModels and then notifyViews. It should pass a pointer to itself (i.e. this) whenever the update method (which should be private) is called.





It is important, vitally important, that you call notifyModels(this) before you call notifyViews(this). No view can safely display itself until all of the models have been updated.





The notifyModels method simply walks the dependentModels list - and calls the notify method of each, passing the this pointer to them.





The notifyViews method simply walks the dependentViews list and calls the notify method of each.





The definition of Model::notify(Model *m) should call the update method, which should be declared as pure virtual in the base class Model, so as to force all concrete subclasses to define what they should do. What they should do, is recompute any field values based on the objects they depend on. If you need to minimize the updates done, then look at the value of the "m" parameter, and only recalculate things that depend on that object.








The definition of View::notify(Model *m) should call the update method, which should be declared as pure virtual in the base class View, so as to force all concrete subclasses to define what they should do. What they should do, is update the display of the view. For example, redraw new image at new location, or update value in control/label. If you need to minimize the updates done, then look at the value of the "m" parameter, and only recalculate things that depend on that object.





Sometimes you get something that changes way faster than you can update the display (like perhaps a game controller whose digital readout changes frequently even when held still). In that case condition your inputs. That could mean averaging the readings and only updating 5 times per second max, or ignoring obviously spurious values. They key point, if your input changes faster than you can react and get the outputs to finish updating, you have to stop reacting to the input directly, and start taking its indications "under advisement". Learn what it is telling you in that case, but do not respond to it directly as if it was "giving the orders".





Coding things this way, your core logic - you models - do not change no matter what GUI you use - Win32, OpenGL, DirectX, Tk, or even a Java GUI Swing GUI you communicate with using JNI.





Your display logic is strictly the only point-of-contact (POC) for your whole application to display stuff on the screen.





You can create a Controller base class too. It could directly read the keyboard one keystroke at a time, for testing it could read buffered command lines from the keyboard or a file, and for a production game build it could read a controller that is managed by whatever - Win32, DirectX, you name it.





Think of your game as a Simulation - one that models reality. Its own reality, that is. The reality in a simulation, is its model - the state of all of its models in aggregation, actually.





What goes on upon the screen, is just shadows falling on a screen. They are not the focus of your application logic, they are just managed by your framework.





Everything that takes place on the screen is just a side effect of a model, notifying a view, which in turn reads the model(s) it depends upon, and makes the appropriate graphics/GUI API calls to display itself.





And that's the Tao.


No comments:

Post a Comment