I. Game framework structure the operation process of a game is similar to that of a movie. Before a movie is made, the actors prepare various costumes and make-up preparations (game initialization) in advance ), the director calls action to start recording movies (the main loop of the game starts). During the recording process, the Director will guide the actors (game input) from time to time, and the actors will follow the line script (game logic) the performances show different pictures (game rendering) until the director calls for work (the game is over) and the filming is coming to an end. At this time, the box lunch should also arrive ......
- Game Initialization
This module initializes game data and allocates memory space for the game.
- Game Main Loop
This module starts to run various operations until the game ends or the user exits the game.
- Game Input
This module monitors user input and changes the corresponding game logic based on input.
- Game Logic
This module is the main part of the game, including collision detection, AI, and physical system in the game. The result affects the formation of the next screen.
- Game Sound
This module is responsible for playing the game sound. The sound will call the speaker to play simple sound effects.
- Game Rendering
This module renders the Screen Based on the game logic. The console game screen consists of characters.
- Frame Rate lock
This module is used for synchronous display. The complexity of the game, the speed and slowness of running the game on different computers at different times, depends on the current CPU load and processing capabilities, so that the game screen update rate is high and low, this affects the gaming experience. Frame Rate locking is synchronized at a certain maximum frame rate to improve the presentation of game images.
- Game ended
This module runs when the game exits and is used to clear game resources and release memory space.
The above roughly describes the basic modules of the game framework, but it does not fully implement various functions. Next we will block other modules and focus on the main game framework, implement a general game framework class. 2. Some basic coding specifications need to be defined for the implementation of the game framework at the beginning of the project:
- Class Name: it must start with a C (console) letter, such as cgame, cdraw, and cmatrix.
- Field name: it must start with an underscore (_), such as m_draw and m_dc_mouse.
- Method Name: it must start with a lowercase letter, such as run () and draw.
The above is just my preferred way of writing, so that you can easily read my code. The attribute field C # does not appear in the project, I have written all the attributes into a clearer method (they are actually methods), and there is nothing special about others.
Static Framework Structure
- The icgame interface defines a run method. The main program communicates with the game subject through this interface, hiding the details of a specific game framework.
- The cgame class is the main game framework class. It provides methods and events required by the game and a series of abstract and Virtual Methods for the specific implementation of the game's derived classes, provides a basic and unified code architecture for game implementation.
- The cgameengine class encapsulates the icgame interface to facilitate the calling of the main program.
- The crun class is the entry point of the program. It communicates with the cgameengine class to start and run a specific game instance.
/// Icgame interface implementation
Using system; namespace cengine {// <summary> // game running interface /// </Summary> Public interface icgame {void run ();}}
/// Cgame class implementation
Using system; using system. threading; namespace cengine {// <summary> // general game class /// </Summary> public abstract class cgame: icgame {# region field // <summary> // screen update rate /// </Summary> private int32 m_updaterate; /// <summary> /// current number of frames /// </Summary> private int32 m_fps; /// <summary> /// number of record frames /// </Summary> private int32 m_tickcount; /// <summary> /// record the last running time /// </Summary> private int32 m_lasttim E; // <summary> /// whether the game is over /// </Summary> private Boolean m_bgameover; # endregion # region constructor // <summary> // constructor // </Summary> Public cgame () {m_bgameover = false ;} # endregion # region game running function // <summary> // game initialization // </Summary> protected abstract void gameinit (); /// <summary> /// game logic /// </Summary> protected abstract void gameloop (); /// <summary> // end of the game /// </Summary> protected ABS Tract void gameexit (); # endregion # region game setting function /// <summary> /// sets the screen update rate /// </Summary> /// <Param name = "rate"> </ param> protected void setupdaterate (int32 rate) {This. m_updaterate = rate;} // <summary> // get the screen update rate /// </Summary> /// <returns> </returns> protected int32 getupdaterate () {return 1000/This. m_updaterate;} // <summary> // get FPS /// </Summary> /// <returns> </returns> protected Int32 getfps () {return this. m_fps;} // <summary> // calculate FPS /// </Summary> private void setfps () {int32 ticks = environment. tickcount; m_tickcount + = 1; if (ticks-m_lasttime >=1000) {m_fps = m_tickcount; m_tickcount = 0; m_lasttime = ticks ;}} /// <summary> /// latency /// </Summary> private void delay () {This. delay (1);} protected void delay (int32 time) {thread. sleep (time) ;}/// <summary> /// Game end /// </Summary> /// <Param name = "gameover"> </param> protected void setgameover (Boolean gameover) {This. m_bgameover = gameover;} // <summary> // whether the game is over/// </Summary> /// <returns> </returns> protected Boolean isgameover () {return this. m_bgameover ;} /// <summary> /// set whether the cursor is visible /// </Summary> /// <Param name = "visible"> </param> protected void setcursorvisible (Boolean visible) {console. cu Rsorvisible = visible ;} /// <summary> /// set the console title /// </Summary> /// <Param name = "title"> </param> protected void settitle (String title) {console. title = title ;}/// <summary> // obtain the console title /// </Summary> /// <returns> </returns> protected string gettitle () {return console. title ;}//< summary> /// close the game and release resources /// </Summary> private void close () {}# endregion # region game startup interface /// <summary> // game running /// </Summary> Public void run () {// game initialization this. gameinit (); int32 starttime = 0; while (! This. isgameover () {// start time starttime = environment. tickcount; // calculate FPS this. setfps (); // game logic this. gameloop (); // maintain a certain FPS while (environment. tickcount-starttime <this. m_updaterate) {This. delay () ;}// the game exits this. gameexit (); // release game resources this. close () ;}# endregion }}
The cgame class encapsulates several game functions, including gameinit, gameloop, and gameexit, which correspond to the game initialization, game logic, and game end. They are set as abstract methods and provided to the derived classes for specific implementation; other functions are used to configure running parameters. However, the most important thing is the run function, which is the core of the game framework and encapsulates the logic layers of game operation, in this way, the actual running details of the game are encapsulated, so that developers pay more attention to the specific game design rather than the details of how to drive the game, which improves the development efficiency to a certain extent.Game running frameworkPseudocode:
Game initialization while (! Game ended ){... Game logic... Keep Frame Rate} after the game ends, clear resources and release memory space
We can see that the running of the game is driven by a loop. Here there is no complete running framework, and there is no game input, game sound, and game rendering, as the chapter explains, the content will gradually emerge and the game framework will be improved step by step.
/// Cgameengine class implementation
Using system; namespace cengine {// <summary> // game startup class /// </Summary> Public sealed class cgameengine {public static void run (icgame game) {If (game = NULL) {console. write ("engine not initialized! "); Console. Readline () ;}else {game. Run ();}}}}
/// Crun class implementation
using System;using CEngine;namespace CRun{ class CRun { static void Main(string[] args) { //CGameEngine.Run(new DemoGame()); } } //class DemoGame:CGame { }}
Since there are no specific game instances, the above uses pseudo-code to describe how the program entry point starts a game instance, the actual situation can be modified according to the above format.
Iii. Game framework testing although the game framework is not fully implemented, it can also be used to test its running status, here we use a small example of refreshing frames per second to illustrate how to use the game framework and test its running status. /// Testgame class implementation
Using system; using cengine; namespace game {public class testgame: cgame {private int32 m_ticks; private int32 m_lasttime; /// <summary> // game initialization /// </Summary> protected override void gameinit () {// set the game title settitle ("game framework test "); // set the game screen update rate to setupdaterate (1000) every millisecond; // set the cursor to hide setcursorvisible (false); console. writeline ("game initialization successful! "); M_lasttime = environment. tickcount;} // <summary> // game logic // </Summary> protected override void gameloop () {If (m_ticks ++ <15) {console. writeline (string. format ("in game running, frame {0}, time consumed {1} ms", m_ticks, environment. tickcount-m_lasttime); m_lasttime = environment. tickcount;} else {setgameover (true) ;}/// <summary> // end of the game /// </Summary> protected override void gameexit () {console. writelin E ("the game is over! "); Console. Readline ();}}}
Correspondingly, the crun class is changed:
using System;using CEngine;using Game;namespace CRun{ class CRun { static void Main(string[] args) { CGameEngine.Run(new TestGame()); } }}
Test results: we can see that the testgame class focuses mainly on the logic of a specific game, without considering how the game is loaded and how it runs, so as to spend more time on the design of the game and the user experience, this is the design purpose of this game framework.
Iv. CONCLUSION Although the framework is still so simple, the basic model of a game running framework is basically elaborated. With the in-depth explanation, the framework will be gradually improved.