From c7711b6cf45c725bc5743a23de07f8122bd8d0f0 Mon Sep 17 00:00:00 2001 From: Miloslav Ciz Date: Mon, 30 Dec 2024 22:19:41 +0100 Subject: [PATCH] Rework main loop --- game.h | 280 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 171 insertions(+), 109 deletions(-) diff --git a/game.h b/game.h index ff1ca20..55eeaf5 100644 --- a/game.h +++ b/game.h @@ -23,6 +23,23 @@ independent of rendering and physics libraries, but out of convenient adopts their coordinate system (X right, Y up, Z forward) and rotations (Euler angles, by Z, then by X, then Y). + + RESOURCE FILE: The game uses so called resource file to store various + resources, mainly maps and replays. There is considered to be one abstract + global file which is just a long text string. Internally the global file is + composed of a hardcoded internal resource file string (stored in assets) with + very basic maps, and an optional user file (appended to the internal file) + that the frontend may provide, allowing adding more resources without + recompiling the game. The user file may be disabled on platforms that e.g. + don't have file systems, but the internal file will be always present. The + format of the resource file is following: it consists of resource strings + separated by '#' character (resource strings cannot contain this character). + Each resource string starts with a magic number: a single character + identifying the type of the resource (map, replay, ...), then the name of the + resource follows, then character ';' and then the resource string itself (up + until next '#' or end of file). The format of the string depends on the type + of resource, i.e. the format of map string has a special format (described in + the map module) etc. */ #ifndef _LCR_GAME_H @@ -157,6 +174,10 @@ uint8_t LCR_gameGetNextAudioSample(void); #define LCR_GAME_STATE_RUN 0x02 #define LCR_GAME_STATE_RUN_FINISHED 0x03 + +#define LCR_RESOURCE_ITEM_CHUNK 8 +#define LCR_MENU_STRING_SIZE 16 + struct { uint8_t state; @@ -168,7 +189,16 @@ struct uint8_t controlMode; uint8_t debugDraw; uint8_t musicVolume; - int resourceFileState; ///< -1 if reading external res. f., else pos. + + struct + { + int state; ///< -1 if reading external res. f., else pos. + + unsigned char loadedItemCount; + char loadedItemNames[LCR_RESOURCE_ITEM_CHUNK * LCR_MENU_STRING_SIZE]; + unsigned int loadedItemsIndices[LCR_RESOURCE_ITEM_CHUNK]; // absolute + unsigned int itemsTotal; // total of items of this type + } resourceFile; } LCR_game; uint8_t LCR_gameGetMusicVolume(void) @@ -249,7 +279,7 @@ void LCR_gameResetRun(void) void LCR_gameRewindResourceFile(void) { LCR_appendResourceStr(""); - LCR_game.resourceFileState = 0; + LCR_game.resourceFile.state = 0; } /** @@ -263,34 +293,34 @@ char LCR_gameGetNextResourceFileChar(void) #if LCR_SETTING_ENABLE_RESOURCE_FILE char c; - if (LCR_game.resourceFileState < 0) // external file? + if (LCR_game.resourceFile.state < 0) // external file? { c = LCR_getNextResourceFileChar(); if (c == 0) - LCR_game.resourceFileState = 0; // move to internal file next + LCR_game.resourceFile.state = 0; // move to internal file next } else // internal file { - c = LCR_internalResourceFile[LCR_game.resourceFileState]; - LCR_game.resourceFileState++; + c = LCR_internalResourceFile[LCR_game.resourceFile.state]; + LCR_game.resourceFile.state++; if (c == 0) { c = LCR_getNextResourceFileChar(); - LCR_game.resourceFileState = c ? -1 : 0; // trust this + LCR_game.resourceFile.state = c ? -1 : 0; // trust this } } return c; #else - if (LCR_internalResourceFile[LCR_game.resourceFileState] == 0) + if (LCR_internalResourceFile[LCR_game.resourceFile.state] == 0) { - LCR_game.resourceFileState = 0; + LCR_game.resourceFile.state = 0; return 0; } - return LCR_internalResourceFile[LCR_game.resourceFileState++]; + return LCR_internalResourceFile[LCR_game.resourceFile.state++]; #endif } @@ -327,7 +357,7 @@ void LCR_seekResourceByIndex(unsigned int index) index--; } - do // skip the name + do // skip magic number and name c = LCR_gameGetNextResourceFileChar(); while (c != LCR_RESOURCE_FILE_SEPARATOR2 && c != LCR_RESOURCE_FILE_SEPARATOR && c != 0); @@ -354,7 +384,19 @@ void LCR_gameInit(void) LCR_racingInit(); LCR_audioInit(); - LCR_game.resourceFileState = 0; + LCR_game.resourceFile.state = 0; + +LCR_game.resourceFile.loadedItemCount = 0; +LCR_game.resourceFile.itemsTotal = 0; + +for (int i = 0; i < LCR_RESOURCE_ITEM_CHUNK; ++i) +{ + for (int j = 0; j < LCR_MENU_STRING_SIZE; ++j) + LCR_game.resourceFile.loadedItemNames[i * LCR_MENU_STRING_SIZE + j] = 0; + + LCR_game.resourceFile.loadedItemsIndices[i] = 0; +} + LCR_game.frame = 0; LCR_game.musicVolume = 255; @@ -362,6 +404,19 @@ void LCR_gameInit(void) LCR_game.nextRacingTickTime = 0; LCR_game.controlMode = LCR_CONTROL_MODE_FREECAM; LCR_gameStartRun(); + +LCR_game.state = LCR_GAME_STATE_RUN; + + +} + +/** + Loads up to LCR_RESOURCE_ITEM_CHUNK items of given type (0 = map, 1 = replay) + into RAM, starting at given index (among items of the same type). +*/ +void LCR_gameLoadResourceFileChunk(uint8_t type, unsigned int startIndex) +{ + // TODO } void LCR_gameEnd(void) @@ -369,10 +424,73 @@ void LCR_gameEnd(void) LCR_LOG0("ending"); } -uint8_t LCR_gameStep(uint32_t time) +void LCR_gameDraw3DView(void) { LCR_GameUnit carTransform[6]; + LCR_GameUnit physicsInterpolationParam = LCR_GAME_UNIT - + ((LCR_game.nextRacingTickTime - LCR_game.time) * LCR_GAME_UNIT) + / LCR_RACING_TICK_MS; + + LCR_racingGetCarTransform(carTransform,carTransform + 3, + physicsInterpolationParam); + + LCR_rendererSetCarTransform(carTransform,carTransform + 3); + + if (LCR_game.controlMode != LCR_CONTROL_MODE_FREECAM) + LCR_rendererCameraFollow(); + +#if LCR_ANIMATE_CAR + LCR_rendererSetWheelState(LCR_racingGetWheelRotation(), + LCR_racingGetWheelSteer() * 2); +#endif + + LCR_rendererDraw(); + + int val = LCR_carSpeedKMH(); + + if (val < 5) // don't show tiny oscillations when still + val = 0; + + char str[6]; + + str[0] = val >= 100 ? '0' + (val / 100) % 10 : ' '; + str[1] = val >= 10 ? '0' + (val / 10) % 10 : ' '; + str[2] = '0' + val % 10; + str[3] = 0; + + LCR_rendererDrawText(str, + LCR_EFFECTIVE_RESOLUTION_X - + LCR_rendererComputeTextWidth(str,2) - 20, + LCR_EFFECTIVE_RESOLUTION_Y - + LCR_rendererComputeTextHeight(2) - 20,0,2); + + val = LCR_racingGetRunTimeMS() / 1000; // seconds + + str[3] = '0' + (val % 60) / 10; + str[4] = '0' + val % 10; + + val = (val / 60) % 100; // minutes + + str[0] = '0' + val / 10; + str[1] = '0' + val % 10; + str[2] = '\''; + str[5] = 0; + + LCR_rendererDrawText(str,20,LCR_EFFECTIVE_RESOLUTION_Y - + LCR_rendererComputeTextHeight(2) - 20,0,2); + +#if LCR_SETTING_DEBUG_PHYSICS_DRAW + LCR_GameUnit camTr[7]; + LCR_rendererGetCameraTransform(camTr,camTr + 3,camTr + 6); + LCR_physicsDebugDraw(camTr,camTr + 3,camTr[6]); +#endif +} + +uint8_t LCR_gameStep(uint32_t time) +{ + uint32_t sleep = 0; + LCR_LOG2("game step start"); LCR_game.time = time; @@ -381,14 +499,47 @@ uint8_t LCR_gameStep(uint32_t time) LCR_keyStates[i] = LCR_keyPressed(i) ? (LCR_keyStates[i] < 255 ? LCR_keyStates[i] + 1 : 255) : 0; - uint32_t sleep = 0; - if (LCR_keyStates[LCR_KEY_B] == 1) LCR_game.controlMode = LCR_game.controlMode == LCR_CONTROL_MODE_FREECAM ? LCR_CONTROL_MODE_DRIVE : LCR_CONTROL_MODE_FREECAM; else if (LCR_keyStates[LCR_KEY_B] == 30) LCR_gameResetRun(); + LCR_GameUnit offsets[5]; + + for (int i = 0; i < 5; ++i) + offsets[i] = 0; + + if (LCR_game.controlMode == LCR_CONTROL_MODE_FREECAM) + { + if (LCR_keyStates[LCR_KEY_A]) + { + if (LCR_keyStates[LCR_KEY_UP]) + offsets[4] = LCR_FREE_CAMERA_TURN_STEP; + else if (LCR_keyStates[LCR_KEY_DOWN]) + offsets[4] -= LCR_FREE_CAMERA_TURN_STEP; + + if (LCR_keyStates[LCR_KEY_RIGHT]) + offsets[3] -= LCR_FREE_CAMERA_TURN_STEP; + else if (LCR_keyStates[LCR_KEY_LEFT]) + offsets[3] = LCR_FREE_CAMERA_TURN_STEP; + } + else + { + if (LCR_keyStates[LCR_KEY_UP]) + offsets[0] = LCR_FREE_CAMERA_STEP; + else if (LCR_keyStates[LCR_KEY_DOWN]) + offsets[0] -= LCR_FREE_CAMERA_STEP; + + if (LCR_keyStates[LCR_KEY_RIGHT]) + offsets[1] = LCR_FREE_CAMERA_STEP; + else if (LCR_keyStates[LCR_KEY_LEFT]) + offsets[1] -= LCR_FREE_CAMERA_STEP; + } + + LCR_rendererMoveCamera(offsets,offsets + 3); + } + while (time >= LCR_game.nextRacingTickTime) { LCR_LOG2("gonna step racing engine"); @@ -427,6 +578,9 @@ uint8_t LCR_gameStep(uint32_t time) LCR_LOG1("crash (big)"); } + int engineIntensity = LCR_carSpeedKMH() * 2; + LCR_audioSetEngineIntensity(engineIntensity < 256 ? engineIntensity : 255); + LCR_game.nextRacingTickTime += LCR_RACING_TICK_MS; } @@ -436,102 +590,10 @@ uint8_t LCR_gameStep(uint32_t time) { LCR_LOG2("gonna render next frame"); - LCR_GameUnit physicsInterpolationParam = LCR_GAME_UNIT - - ((LCR_game.nextRacingTickTime - time) * LCR_GAME_UNIT) - / LCR_RACING_TICK_MS; - - LCR_racingGetCarTransform(carTransform,carTransform + 3, - physicsInterpolationParam); - - LCR_rendererSetCarTransform(carTransform,carTransform + 3); - while (time >= LCR_game.nextRenderFrameTime) LCR_game.nextRenderFrameTime += 1000 / LCR_SETTING_FPS; - - LCR_GameUnit offsets[5]; - - for (int i = 0; i < 5; ++i) - offsets[i] = 0; - - if (LCR_game.controlMode == LCR_CONTROL_MODE_FREECAM) - { - if (LCR_keyStates[LCR_KEY_A]) - { - if (LCR_keyStates[LCR_KEY_UP]) - offsets[4] = LCR_FREE_CAMERA_TURN_STEP; - else if (LCR_keyStates[LCR_KEY_DOWN]) - offsets[4] -= LCR_FREE_CAMERA_TURN_STEP; - - if (LCR_keyStates[LCR_KEY_RIGHT]) - offsets[3] -= LCR_FREE_CAMERA_TURN_STEP; - else if (LCR_keyStates[LCR_KEY_LEFT]) - offsets[3] = LCR_FREE_CAMERA_TURN_STEP; - } - else - { - if (LCR_keyStates[LCR_KEY_UP]) - offsets[0] = LCR_FREE_CAMERA_STEP; - else if (LCR_keyStates[LCR_KEY_DOWN]) - offsets[0] -= LCR_FREE_CAMERA_STEP; - - if (LCR_keyStates[LCR_KEY_RIGHT]) - offsets[1] = LCR_FREE_CAMERA_STEP; - else if (LCR_keyStates[LCR_KEY_LEFT]) - offsets[1] -= LCR_FREE_CAMERA_STEP; - } - - LCR_rendererMoveCamera(offsets,offsets + 3); - } - else - LCR_rendererCameraFollow(); - -#if LCR_ANIMATE_CAR - LCR_rendererSetWheelState(LCR_racingGetWheelRotation(), - LCR_racingGetWheelSteer() * 2); -#endif - - LCR_rendererDraw(); - - int val = LCR_carSpeedKMH(); - -LCR_audioSetEngineIntensity((2 * val) < 256 ? (2 * val) : 255); - - if (val < 5) // don't show tiny oscillations when still - val = 0; - - char str[6]; - - str[0] = val >= 100 ? '0' + (val / 100) % 10 : ' '; - str[1] = val >= 10 ? '0' + (val / 10) % 10 : ' '; - str[2] = '0' + val % 10; - str[3] = 0; - - LCR_rendererDrawText(str, - LCR_EFFECTIVE_RESOLUTION_X - - LCR_rendererComputeTextWidth(str,2) - 20, - LCR_EFFECTIVE_RESOLUTION_Y - - LCR_rendererComputeTextHeight(2) - 20,0,2); - - val = LCR_racingGetRunTimeMS() / 1000; // seconds - - str[3] = '0' + (val % 60) / 10; - str[4] = '0' + val % 10; - - val = (val / 60) % 100; // minutes - - str[0] = '0' + val / 10; - str[1] = '0' + val % 10; - str[2] = '\''; - str[5] = 0; - - LCR_rendererDrawText(str,20,LCR_EFFECTIVE_RESOLUTION_Y - - LCR_rendererComputeTextHeight(2) - 20,0,2); - -#if LCR_SETTING_DEBUG_PHYSICS_DRAW - LCR_GameUnit camTr[7]; - LCR_rendererGetCameraTransform(camTr,camTr + 3,camTr + 6); - LCR_physicsDebugDraw(camTr,camTr + 3,camTr[6]); -#endif + + LCR_gameDraw3DView(); } else {