Skip to content

1.1.1 Flow after we start the game

XenoAmess edited this page May 4, 2019 · 1 revision

Flow after we start the game

When we start the game, we will enter GameEntrance. If you want to do anything before you start the game, like editing static values, or startup some components that you added for your game, you can simply write another class to replace GameEntrance class.

GameEntrance is really simple a class, it first use the arguments to build a GameManager.

So what is GameManager?

GameManager is a manager of a game. Each gameManager instance represent a game, and it holds all information and resources the game owes.

There is allowed to have several GameManager running in same time logically, but as I haven't meet demands such yet, I have not tested it fully.

When creating GameManager, it will call generateArgsMap to split args into argsmap and store it.

Then GameEntrance then make the gameManager startup().

In gameManager.startup(), first we do is to call initSteam(). You shall can go steamworks4j for more details. Notice that if DataCenter.ALLOW_RUN_WITHOUT_STEAM == true, even if there be no steam/you don't owe this game, we can still play it. But if DataCenter.ALLOW_RUN_WITHOUT_STEAM == false, then it will exit. If you want to change DataCenter.ALLOW_RUN_WITHOUT_STEAM to false, you shall change it in your own codes, and be careful to change it before you startup your first gameManager instance.

Then it goes into gameManager.loadGlobalSettings();

First you will enter gameManager.loadSettingFile(); it will lookup "SettingFilePath" in argsMap, and then load the file using x8l then we loop the direct children of root nodes. if it is textNode or commentNode, then we just ignore it. if it is contentNode, then we check it must have a name, or ignore it. (a name of contentNode means its first attribute's key) then we will find a map using this name in gameManager.dataCenter. if there be such a map, then gameManager.dataCenter.such map will add the following attribute pairs into the map. otherwise we ignore it. If you want to add some logic with the settingFile, you can just override this function.

then we will enter gameManager.readCommonSettings(); we will set some values using the common settings.

then we will enter gameManager.loadKeymap(); we will load keymap from commonSetting file. we will write more details about keyMap in latter chapters.

then we will enter gameManager.loadText(); we use multi_language to load the text file. then we make sure the language. the language is set to English by default, and then if your specify it settingsfile it will change to the value in your settingsfile. and then if you are with steam it will change to steam's language. so yes, steam is most powerful.

then we make alive the consoleThread. that is not in the core, so you can learn about it yourself.

then we enter gameManager.codePluginManager.apply(this, rightAfterResourceManagerCreate); this is about a new mechanism added in 0.130.0, called codePlugin. in short I made several point in the program, in which you can configue Function<GameManager,Void> in code and config file, then it will apply the functions registered one by one. that is useful when you want to hook some codes in, and does not want to change the code of cyan_potion_base.

then we enter gameManager.initGameWindow(). GameWindow is a class that represent a window. Each gameManager have exactly one GameWindow. GameWindow and GameComponents are bound with specific Graphical library(currently only implemented glfw here), but gameManager is not.

we get the name of gameWindow we want in settings file ("com.xenoamess.cyan_potion.base.GameWindow" by default), then we get a instance and use it as our GameWindow. this is because sometime there really be a need to do it that way. for example, imagine a situation that we want a game have no window. then we can just make a FalseWindow class and make it extend GameWindow, then choose it in config file.

then we set the window's width and height. logicWidth means width in logic, and real width means width the window shows. you can read the logic by yourself if you want more informations.

then we make the GameWindowComponentTree. a setGameWindowComponentTree is something really complex, and I will not put it here. Let's delay it until when we face update() and draw().

then we enter this.getGameWindow().init(); there is a bunch of glfw things in this function and that will not be explained here.

then back to gameManager.startup(); we init the audio manager. we will tell about audio manager at another time, but not now, as audio is not so connected to the main part.

then we init the gamepad input. But as I use JXinput here, and I and really considering about changing to glfw's gamepad, I will not write documents about this parts for now.

then this.setStartingContent(); we instance a AbstractGameWindowComponent according to the setting file, and choose it to be the first scene to show. we will tell about AbstractGameWindowComponent and the whole gui system of cyan_potion later.

Then we start a thread to load a ttf file. well it is tricky to do it so, and we do have a good reason. Some of the language have small number of chars, like english , which have less than 100 chars. but others, they have so many different chars. to put a ttf into memory and make it ready for draw, it need a lot of time. At least several seconds.

So we first start the thread and then put on our logos. When the logo finish, we wait for the ttf to load over, and then we start the real game. this does not change the loading time but it makes players more comfortable. It will be better if we divide the chars into several groups for their use frequency, but it is a work who cost too much time, and I just have no time for it.

then we enter gameManager.loop(). this is the main function of the engine, and until gameManager.alive set to false, we will all stay in this function from now on.

first we enter a loop, and only until gameManager.alive set to false can we leave. we call it "main loop".

for every cycle, first we get the current system time, and calculate the time passed between last frame and this frame. then we add the passed value to variable unprocessed. if unprocessed >= FRAME_CAP, then we enter a logic frame. else, we just wait.

if unprocessed >= FRAME_CAP, then we will enter a logic frame. unprocessed -= DataCenter.FRAME_CAP solveEvents(); update(); this.getResourceManager().suggestGc();

Notice that if the computer we play on cannot afford draw 60 fps, then we only run 60 logic frames in one second, but not actually draw them all.

If entered at least one logic frame this cycle, we will enter a draw frame. draw();

that is the main flow of the game engine.

Clone this wiki locally