Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 244 | chris | 1 | #ifndef __BOARD_H__ |
| 2 | #define __BOARD_H__ |
||
| 3 | |||
| 4 | ////////////////////////////////////////////////////////////////////////// |
||
| 5 | // Board.h |
||
| 6 | // |
||
| 7 | // This is the third class to look at in this particular demo |
||
| 8 | // (after main.cpp and GameApp.h/.cpp). The Board class is where most of |
||
| 9 | // your actual game programming will go. It is here that we will do |
||
| 10 | // all our game drawing, updating, and input processing. Of course, in |
||
| 11 | // a larger application, you would probably do drawing and updating in |
||
| 12 | // multiple files, but you would still most likely use something similar |
||
| 13 | // to a Board class as the master game logic class. |
||
| 14 | // |
||
| 15 | // The reason that the Board class is a widget is because when a widget |
||
| 16 | // is added to the GameApp's WidgetManager, it will automatically have its |
||
| 17 | // Update and Draw methods called, and it will automatically receive input |
||
| 18 | // at the appropriate times. Furthermore, by making it a widget and adding |
||
| 19 | // it to the WidgetManager, the game logic loop, Update(), will be guaranteed |
||
| 20 | // to run at a standard 100FPS on all machines. This is extremely important |
||
| 21 | // as you always want your logic code to run at the same speed, but want |
||
| 22 | // the drawing code to run as fast as possible. That way on faster machines |
||
| 23 | // your program doesn't run its logic faster than on a slower machine. |
||
| 24 | // |
||
| 25 | // You can think of the Board as a canvas upon which we do all our |
||
| 26 | // drawing, and a central hub where if we need to, we instruct other |
||
| 27 | // classes where and when to draw to. |
||
| 28 | ////////////////////////////////////////////////////////////////////////// |
||
| 29 | |||
| 30 | #include "SexyAppFramework/Widget.h" |
||
| 31 | #include "SexyAppFramework/ButtonListener.h" |
||
| 32 | |||
| 33 | // Because we're going to be learning about some new widgets, we |
||
| 34 | // need to include some more listener classes so we can respond to each one. |
||
| 35 | #include "SexyAppFramework/EditListener.h" |
||
| 36 | #include "SexyAppFramework/CheckboxListener.h" |
||
| 37 | #include "SexyAppFramework/ListListener.h" |
||
| 38 | |||
| 39 | |||
| 40 | |||
| 41 | // We place all our classes inside the "Sexy" namespace to avoid name collisions |
||
| 42 | // with other libraries that might be added. |
||
| 43 | namespace Sexy |
||
| 44 | { |
||
| 45 | |||
| 46 | |||
| 47 | // Forward declare the graphics class. You will see the graphics class used |
||
| 48 | // and explained in Board.cpp: it is the main object used to draw all |
||
| 49 | // images, fonts, etc. |
||
| 50 | class Graphics; |
||
| 51 | |||
| 52 | // We maintain a pointer to the main game application in the Board class. |
||
| 53 | // The main game app contains functions that are often times needed |
||
| 54 | // by the Board class, such as registry reading/writing, file reading/writing, |
||
| 55 | // etc. |
||
| 56 | class GameApp; |
||
| 57 | |||
| 58 | // forward declare the widgets we're going to use in this demo: |
||
| 59 | class ButtonWidget; |
||
| 60 | class EditWidget; |
||
| 61 | class Checkbox; |
||
| 62 | class ListWidget; |
||
| 63 | class ScrollbarWidget; |
||
| 64 | |||
| 65 | // In this demo, we're going to do some more advanced things like |
||
| 66 | // handle the two cases where Board is added and removed from the |
||
| 67 | // WidgetManager. |
||
| 68 | class WidgetManager; |
||
| 69 | |||
| 70 | ////////////////////////////////////////////////////////////////////////// |
||
| 71 | ////////////////////////////////////////////////////////////////////////// |
||
| 72 | class Board : public Widget, public ButtonListener, |
||
| 73 | public EditListener, public CheckboxListener, |
||
| 74 | public ListListener |
||
| 75 | { |
||
| 76 | |||
| 77 | private: |
||
| 78 | |||
| 79 | GameApp* mApp; |
||
| 80 | ButtonWidget* mButton1; // We'll use these buttons for sound playing |
||
| 81 | ButtonWidget* mButton2; |
||
| 82 | |||
| 83 | // These are explained in the C++ code, they are the new widgets we're learning about. |
||
| 84 | EditWidget* mEditWidget; |
||
| 85 | Checkbox* mCheckboxWidget; |
||
| 86 | ListWidget* mListWidget; |
||
| 87 | ScrollbarWidget* mScrollbarWidget; |
||
| 88 | |||
| 89 | SexyString mText; // When we press enter on the edit box, we'll set this string and print it |
||
| 90 | |||
| 91 | // Both are floats to ensure that the only difference in the movement demo |
||
| 92 | // is the fact that one is updated in UpdateF and the other is in Update. |
||
| 93 | float mMotionX; // For our movement example, this is the X coordinate of the image as it moves rightward |
||
| 94 | float mUpdateFMotionX;// Same as above, but only modified in UpdateF, to illustrate the difference in motion |
||
| 95 | |||
| 96 | public: |
||
| 97 | |||
| 98 | ////////////////////////////////////////////////////////////////////////// |
||
| 99 | // Function: Board |
||
| 100 | // Parameters: |
||
| 101 | // theApp - Pointer to the main application class |
||
| 102 | // |
||
| 103 | // Returns: none |
||
| 104 | ////////////////////////////////////////////////////////////////////////// |
||
| 105 | Board(GameApp* theApp); |
||
| 106 | |||
| 107 | virtual ~Board(); |
||
| 108 | |||
| 109 | ////////////////////////////////////////////////////////////////////////// |
||
| 110 | // Function: EditWidgetText |
||
| 111 | // Parameters: |
||
| 112 | // theId - Integer ID of the edit widget sending this message |
||
| 113 | // theString - The contents of the edit widget |
||
| 114 | // |
||
| 115 | // Returns: none |
||
| 116 | // |
||
| 117 | // Purpose: Called whenever the return/enter key is pressed on |
||
| 118 | // an edit widget. |
||
| 119 | ////////////////////////////////////////////////////////////////////////// |
||
| 120 | void EditWidgetText(int theId, const std::string& theString); |
||
| 121 | |||
| 122 | ////////////////////////////////////////////////////////////////////////// |
||
| 123 | // Function: AllowChar |
||
| 124 | // Parameters: |
||
| 125 | // theId - Integer ID of the edit widget sending this message |
||
| 126 | // theChar - Character just typed in |
||
| 127 | // |
||
| 128 | // Returns: |
||
| 129 | // true - Indicates that the character is acceptible |
||
| 130 | // false - Indicates that the character is invalid |
||
| 131 | // |
||
| 132 | // Purpose: Whenever an ASCII character is typed into the edit box, |
||
| 133 | // this method is called first. If the method returns true, then the |
||
| 134 | // character just typed is accepted and appended to the current edit widget |
||
| 135 | // string. If it returns false, the character is rejected and is not added. |
||
| 136 | ////////////////////////////////////////////////////////////////////////// |
||
| 137 | bool AllowChar(int theId, char theChar); |
||
| 138 | |||
| 139 | ////////////////////////////////////////////////////////////////////////// |
||
| 140 | // Function: CheckboxChecked |
||
| 141 | // Parameters: |
||
| 142 | // theId - Integer ID of the checkbox widget sending this message |
||
| 143 | // checked - Boolean indicating if the widget is checked or not |
||
| 144 | // |
||
| 145 | // Returns: none |
||
| 146 | // |
||
| 147 | // Purpose: Whenever a checkbox widget is checked or unchecked, this |
||
| 148 | // method is called. We're not actually going to do anything with this, |
||
| 149 | // we're just listing it here as an example of how you'd implement a |
||
| 150 | // function to respond to that event. |
||
| 151 | ////////////////////////////////////////////////////////////////////////// |
||
| 152 | void CheckboxChecked(int theId, bool checked) {;} |
||
| 153 | |||
| 154 | ////////////////////////////////////////////////////////////////////////// |
||
| 155 | // Function: ListClicked |
||
| 156 | // Parameters: |
||
| 157 | // theId - Integer ID of the listbox widget sending this message |
||
| 158 | // theIdx - Integer indicating the index of the item selected in the list |
||
| 159 | // theClickCount - An integer indicating which mouse button |
||
| 160 | // was pressed. One of the following: |
||
| 161 | // 1: Left button |
||
| 162 | // 2: Double-left-click |
||
| 163 | // 3: Middle button |
||
| 164 | // -1: Right button |
||
| 165 | // -2: Double-right-click |
||
| 166 | // |
||
| 167 | // Returns: none |
||
| 168 | // |
||
| 169 | // Purpose: Called any time a list widget is clicked on. The list |
||
| 170 | // widget by default doesn't automatically select the item you clicked on, |
||
| 171 | // it instead calls this method and in here you manually select the item. |
||
| 172 | // This is to allow you to prevent the selection of certain items, such as |
||
| 173 | // disabled items, etc. |
||
| 174 | ////////////////////////////////////////////////////////////////////////// |
||
| 175 | void ListClicked(int theId, int theIdx, int theClickCount); |
||
| 176 | |||
| 177 | ////////////////////////////////////////////////////////////////////////// |
||
| 178 | // Function: Draw |
||
| 179 | // Parameters: |
||
| 180 | // g - Graphics object used to draw all images and fonts to the screen. |
||
| 181 | // |
||
| 182 | // Returns: none |
||
| 183 | // |
||
| 184 | // Purpose: Called automatically by GameApp's WidgetManager, this function |
||
| 185 | // is the main method that is responsible for all graphical and textual |
||
| 186 | // displaying. |
||
| 187 | ////////////////////////////////////////////////////////////////////////// |
||
| 188 | virtual void Draw(Graphics* g); |
||
| 189 | |||
| 190 | ////////////////////////////////////////////////////////////////////////// |
||
| 191 | // Function: Update |
||
| 192 | // Parameters: none |
||
| 193 | // Returns: none |
||
| 194 | // |
||
| 195 | // Purpose: Called automatically by GameApp's WidgetManager, this method |
||
| 196 | // is GUARANTEED to be called 100 times per second (100FPS) and is where |
||
| 197 | // all main game logic is performed. Of course, if you had a larger more |
||
| 198 | // complex game, you'd most likely divide your logic between several |
||
| 199 | // other files, but this is commonly the central place where all game |
||
| 200 | // logic begins and is executed. |
||
| 201 | ////////////////////////////////////////////////////////////////////////// |
||
| 202 | virtual void Update(); |
||
| 203 | |||
| 204 | ////////////////////////////////////////////////////////////////////////// |
||
| 205 | // Function: UpdateF |
||
| 206 | // Parameters: |
||
| 207 | // theFrac - The number of updates this time slice represents. |
||
| 208 | // |
||
| 209 | // Returns: none |
||
| 210 | // |
||
| 211 | // Purpose: |
||
| 212 | // There has been a fundamental temporal aliasing issue in the previous |
||
| 213 | // demos because games run at a 100 Hz Update rate while the user's monitor |
||
| 214 | // is refreshing at some other rate, generally between 60 and 85 Hz. The fixed |
||
| 215 | // 100 Hz Update rate is convenient because it allows game logic to proceed |
||
| 216 | // independantly from the refresh rate, but in some cases it's worth the extra |
||
| 217 | // trouble of updating at a variable rate in order to provide smoother animation, |
||
| 218 | // as in the case of a scrolling background, a shark with words written on it, |
||
| 219 | // or an Arkanoid ball. |
||
| 220 | // |
||
| 221 | // To illustrate the aliasing problem, imagine a ball that is supposed to move |
||
| 222 | // 200 pixels per second, running on a 75 Hz monitor. The update rate of the |
||
| 223 | // game is 100 Hz, so that means that we will add 2 pixels to the ball position |
||
| 224 | // every update, and there will be 1.33 updates per monitor refresh (on average). |
||
| 225 | // That means that that 2 out of every 3 monitor refreshes will show the ball |
||
| 226 | // moving 2 pixels, and and the third will show it moving 4 pixels. That isn't |
||
| 227 | // smooth motion. The correct solution would be for the ball to move 2.67 |
||
| 228 | // pixels every monitor refresh. But how do we do that? |
||
| 229 | // |
||
| 230 | // To support smooth motion, we use UpdateF. Widget::UpdateF is similar to |
||
| 231 | // Widget::Update, but Widget::UpdateF gets a float passed into it that |
||
| 232 | // represents how many Update's this time slice represents. In the 75 Hz |
||
| 233 | // example, UpdateF would always be called with 1.33. Update has certainly |
||
| 234 | // not been made obsolete, however, and you can choose which |
||
| 235 | // parts of your game logic should be in Update and which should be in |
||
| 236 | // UpdateF. To facilitate cooperation and good behavior between the two |
||
| 237 | // update methods, there are some rules they follow: Updating always occurs |
||
| 238 | // in blocks, with one or two Update calls followed immediately with an |
||
| 239 | // UpdateF call. This means that the application will never get the chance |
||
| 240 | // to draw or process input between an Update and a Draw without calling |
||
| 241 | // UpdateF in the middle. Therefore, you can assume that focus won't be |
||
| 242 | // lost, nor will input change between an Update and an UpdateF, and you'll |
||
| 243 | // know that you'll have a chance to finalize your state in UpdateF so things |
||
| 244 | // can be left dangling (whatever that means for your app) after Update. |
||
| 245 | // You are also guaranteed that the value passed in to UpdateF will be between |
||
| 246 | // 1.67 (for a 60 Hz monitor) and 1.0 (for a 100 Hz monitor). Even if the |
||
| 247 | // monitor is 60 Hz but the computer is only fast enough to draw at 30 FPS |
||
| 248 | // you will get two Update blocks in a row before the draw, so it will still |
||
| 249 | // appear to your app as if you are updating at 60 Hz. |
||
| 250 | // |
||
| 251 | // IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT |
||
| 252 | // |
||
| 253 | // In order to fully use this, you need to set up a few things. |
||
| 254 | // Set GameApp::mVSyncUpdates to true, override UpdateF(float theFrac), |
||
| 255 | // and move some code from Update that used to look like |
||
| 256 | // this: "mPos += 1.5;", changing it to "mPos += 1.5 * theFrac;". |
||
| 257 | // Check out the C++ code for an example of motion using both Update and |
||
| 258 | // UpdateF. |
||
| 259 | // |
||
| 260 | // IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT |
||
| 261 | // |
||
| 262 | // Because UpdateF is called a variable number of times per second, |
||
| 263 | // you do NOT want to put game logic in it that needs to remain framerate |
||
| 264 | // independant. Use UpdateF ONLY for movement related operations, and not |
||
| 265 | // for your main game code. |
||
| 266 | // |
||
| 267 | // If you really want to avoid shearing in windowed mode, you can |
||
| 268 | // set GameApp::mWaitForVSync to true and set GameApp::mSoftVSyncWait |
||
| 269 | // to false. NOTE: This winds up doing some busy waiting and consumes |
||
| 270 | // more processor time. |
||
| 271 | // IMPORTANT: YOU MUST ALSO DELETE THE FOLLOWING REGISTRY KEY: |
||
| 272 | // Whereever your registry settings are stored |
||
| 273 | // (HKEY_LOCAL_MACHINE\SOFTWARE\SexyAppFramework\Demo4 for this case), |
||
| 274 | // you must delete the key "WaitForVSync". This is VERY important, and it |
||
| 275 | // won't work otherwise. |
||
| 276 | ////////////////////////////////////////////////////////////////////////// |
||
| 277 | virtual void UpdateF(float theFrac); |
||
| 278 | |||
| 279 | ////////////////////////////////////////////////////////////////////////// |
||
| 280 | // Function: ButtonDepress |
||
| 281 | // Parameters: |
||
| 282 | // theId - Integer ID of the button that was clicked |
||
| 283 | // |
||
| 284 | // Returns: none |
||
| 285 | // |
||
| 286 | // Purpose: This method is called by the WidgetManager when a button widget |
||
| 287 | // is first pressed and THEN released. You can use ButtonPress if you want |
||
| 288 | // to know when the button is first pressed (before it is released). |
||
| 289 | // theId is the integer ID that was assigned to the button when it was |
||
| 290 | // first created. |
||
| 291 | ////////////////////////////////////////////////////////////////////////// |
||
| 292 | virtual void ButtonDepress(int theId); |
||
| 293 | |||
| 294 | ////////////////////////////////////////////////////////////////////////// |
||
| 295 | // Function: AddedToManager |
||
| 296 | // Parameters: |
||
| 297 | // theWidgetManager - Pointer to the main widget manager from |
||
| 298 | // GameApp. |
||
| 299 | // |
||
| 300 | // Returns: none |
||
| 301 | // |
||
| 302 | // Purpose: This function is automatically called by the widget manager |
||
| 303 | // which also passes a pointer to itself, when the Board class is |
||
| 304 | // added to its list of widgets. Every widget gets this function |
||
| 305 | // called when it is first added. It useful to use this function to |
||
| 306 | // set up any other widgets that the class might contain, such as buttons. |
||
| 307 | ////////////////////////////////////////////////////////////////////////// |
||
| 308 | virtual void AddedToManager(WidgetManager* theWidgetManager); |
||
| 309 | |||
| 310 | ////////////////////////////////////////////////////////////////////////// |
||
| 311 | // Function: RemovedFromManager |
||
| 312 | // Parameters: |
||
| 313 | // theWidgetManager - Pointer to the main widget manager from |
||
| 314 | // GameApp. |
||
| 315 | // |
||
| 316 | // Returns: none |
||
| 317 | // |
||
| 318 | // Purpose: This function is automatically called by the widget manager |
||
| 319 | // which also passes a pointer to itself, when the Board class is |
||
| 320 | // removed from its list of widgets. Every widget gets this function |
||
| 321 | // called when it is finally removed. It useful to use this function to |
||
| 322 | // also remove any widgets that were added and created in AddedToManager. |
||
| 323 | ////////////////////////////////////////////////////////////////////////// |
||
| 324 | virtual void RemovedFromManager(WidgetManager* theWidgetManager); |
||
| 325 | |||
| 326 | }; |
||
| 327 | |||
| 328 | |||
| 329 | } |
||
| 330 | |||
| 331 | #endif // __BOARD_H__ |