diff --git a/constants.h b/constants.h index 89c0d63..f086b5f 100644 --- a/constants.h +++ b/constants.h @@ -21,6 +21,11 @@ #define LCR_MAP_SIZE_BLOCKS 64 +/** Physics FPS, i.e. the number of physics ticks per second. */ +#define LCR_RACING_FPS 25 + +#define LCR_RACING_TICK_MS (1000 / LCR_RACING_FPS) + #define LCR_ANIMATE_CAR (LCR_SETTING_CAR_ANIMATION_SUBDIVIDE != 0) /** Maximum number of triangles of a block shape. */ diff --git a/game.h b/game.h index 589cd5a..3cde768 100644 --- a/game.h +++ b/game.h @@ -74,7 +74,11 @@ uint8_t LCR_gameStep(uint32_t timeMs); //------------------------------------------------------------------------------ -uint32_t LCR_nextRenderFrameTime; +struct +{ + uint32_t nextRenderFrameTime; + uint32_t nextRacingTickTime; +} LCR_game; void LCR_drawPixelXYUnsafe(unsigned int x, unsigned int y, uint16_t color); @@ -92,7 +96,7 @@ static inline void LCR_drawPixelXYSafe(unsigned int x, unsigned int y, #include "renderer.h" uint8_t LCR_keyStates[LCR_KEYS_TOTAL]; /**< Assures unchanging key states - during a single frame. */ + during a single frame. */ void LCR_drawPixelXYUnsafe(unsigned int x, unsigned int y, uint16_t color) @@ -121,6 +125,9 @@ void LCR_gameInit(void) LCR_mapLoad(map1); LCR_rendererInit(); LCR_racingInit(); + + LCR_game.nextRenderFrameTime = 0; + LCR_game.nextRacingTickTime = 0; } void LCR_gameEnd(void) @@ -134,10 +141,27 @@ uint8_t LCR_gameStep(uint32_t time) uint32_t sleep = 0; - if (time >= LCR_nextRenderFrameTime) + while (time >= LCR_game.nextRacingTickTime) { + unsigned int input = 0; + + if (LCR_keyStates[LCR_KEY_B]) + input = + (LCR_keyStates[LCR_KEY_UP] ? LCR_RACING_INPUT_FORW : 0) | + (LCR_keyStates[LCR_KEY_RIGHT] ? LCR_RACING_INPUT_RIGHT : 0) | + (LCR_keyStates[LCR_KEY_DOWN] ? LCR_RACING_INPUT_BACK : 0) | + (LCR_keyStates[LCR_KEY_LEFT] ? LCR_RACING_INPUT_LEFT : 0); + + LCR_racingStep(input); + LCR_game.nextRacingTickTime += LCR_RACING_TICK_MS; + } + if (time >= LCR_game.nextRenderFrameTime) + { + LCR_GameUnit carTransform[6]; + LCR_racingGetCarTransform(carTransform,carTransform + 3); + LCR_rendererSetCarTransform(carTransform,carTransform + 3); @@ -149,7 +173,7 @@ LCR_rendererGetCameraTransform(sss,sss + 3,sss + 6); LCR_physicsDebugDraw(sss,sss + 3,sss[6]); - LCR_nextRenderFrameTime += 1000 / LCR_SETTING_FPS; + LCR_game.nextRenderFrameTime += 1000 / LCR_SETTING_FPS; LCR_GameUnit offsets[5]; @@ -168,7 +192,7 @@ LCR_physicsDebugDraw(sss,sss + 3,sss[6]); else if (LCR_keyStates[LCR_KEY_LEFT]) offsets[3] = LCR_FREE_CAMERA_TURN_STEP; } - else + else if (!LCR_keyStates[LCR_KEY_B]) { if (LCR_keyStates[LCR_KEY_UP]) offsets[0] = LCR_FREE_CAMERA_STEP; @@ -184,7 +208,7 @@ LCR_physicsDebugDraw(sss,sss + 3,sss[6]); LCR_rendererMoveCamera(offsets,offsets + 3); } else - sleep = LCR_nextRenderFrameTime - time; + sleep = LCR_game.nextRenderFrameTime - time; if (sleep) LCR_sleep(sleep); diff --git a/racing.h b/racing.h index 5e83d65..c4af876 100644 --- a/racing.h +++ b/racing.h @@ -9,55 +9,114 @@ typedef int32_t LCR_GameUnit; ///< game spatial units #define LCR_GAME_UNIT 1024 ///< length of map square in game units +#define LCR_RACING_INPUT_FORW 0x01 +#define LCR_RACING_INPUT_RIGHT 0x02 +#define LCR_RACING_INPUT_BACK 0x04 +#define LCR_RACING_INPUT_LEFT 0x08 + #define LCR_PHYSICS_UNIT 512 ///< length of map square for physics engine #include "map.h" #include "tinyphysicsengine.h" +#define LCR_CAR_JOINTS 5 +#define LCR_CAR_CONNECTIONS 8 + struct { TPE_World physicsWorld; TPE_Body carBody; + TPE_Joint carJoints[5]; + TPE_Connection carConnections[8]; } LCR_racing; TPE_Vec3 LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist) { -/* - return -TPE_envHalfPlane(point, - TPE_vec3(0,0,0), - TPE_vec3(0,TPE_FRACTIONS_PER_UNIT,0)); -*/ - return TPE_envAABoxInside(point,TPE_vec3(0,0,0),TPE_vec3( LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS, (LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS) / 2, LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS)); - } void LCR_racingInit(void) { LCR_log("initializing racing engine"); + // make the car body: + TPE_makeCenterRect(LCR_racing.carJoints, + LCR_racing.carConnections, + LCR_GAME_UNIT / 3, + (LCR_GAME_UNIT) / 2, + LCR_GAME_UNIT / 8); + + LCR_racing.carJoints[4].position.y += LCR_PHYSICS_UNIT / 3; + LCR_racing.carJoints[4].sizeDivided *= 3; + LCR_racing.carJoints[4].sizeDivided /= 2; + + TPE_bodyInit(&(LCR_racing.carBody), + LCR_racing.carJoints,LCR_CAR_JOINTS, + LCR_racing.carConnections,LCR_CAR_CONNECTIONS, + TPE_FRACTIONS_PER_UNIT); + TPE_worldInit(&(LCR_racing.physicsWorld), &(LCR_racing.carBody),1,LCR_racingEnvironmentFunction); } +void LCR_racingGetCarTransform(LCR_GameUnit position[3], + LCR_GameUnit rotation[3]) +{ + #define AVERAGE(c) \ + (((((LCR_racing.carBody.joints[0].position.c + \ + LCR_racing.carBody.joints[1].position.c + \ + LCR_racing.carBody.joints[2].position.c + \ + LCR_racing.carBody.joints[3].position.c) / 4) + \ + LCR_racing.carBody.joints[4].position.c) / 2) * \ + LCR_GAME_UNIT) / LCR_PHYSICS_UNIT + + position[0] = AVERAGE(x); + position[1] = AVERAGE(y); + position[2] = AVERAGE(z); + #undef AVERAGE +} + void _LCR_drawPhysicsDebugPixel(uint16_t x, uint16_t y, uint8_t color) { - if (x > 1 && x < LCR_EFFECTIVE_RESOLUTION_X - 1 && - y > 1 && y < LCR_EFFECTIVE_RESOLUTION_Y - 1) + if (x > 1 && x < LCR_EFFECTIVE_RESOLUTION_X - 2 && + y > 1 && y < LCR_EFFECTIVE_RESOLUTION_Y - 2) { - uint16_t color = color; - color = (color << 3) | 0xf800; + uint16_t c = 0x8101 | (0x8f1f << (2 * color)); - for (int j = -1; j < 2; ++j) - for (int i = -1; i < 2; ++i) - LCR_drawPixelXYUnsafe(x + i,y + j,color); + for (int j = -1; j <= 2; ++j) + for (int i = -1; i <= 2; ++i) + LCR_drawPixelXYUnsafe(x + i,y + j,c); } } +// TODO: input +void LCR_racingStep(unsigned int input) +{ + TPE_Vec3 vel = TPE_vec3(0,0,0); + + if (input) + { + if (input & LCR_RACING_INPUT_FORW) + vel.z = LCR_GAME_UNIT / 32; + + if (input & LCR_RACING_INPUT_BACK) + vel.y = LCR_GAME_UNIT / 32; + + if (input & LCR_RACING_INPUT_RIGHT) + vel.x = LCR_GAME_UNIT / 32; + + if (input & LCR_RACING_INPUT_LEFT) + vel.x = -1 * LCR_GAME_UNIT / 32; + + TPE_bodyAccelerate(&(LCR_racing.carBody),vel); + } + + TPE_worldStep(&(LCR_racing.physicsWorld)); +} + void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2], LCR_GameUnit camFov) { diff --git a/renderer.h b/renderer.h index b2938f5..65d0250 100644 --- a/renderer.h +++ b/renderer.h @@ -7,7 +7,7 @@ #define S3L_RESOLUTION_X LCR_SETTING_RESOLUTION_X #define S3L_RESOLUTION_Y LCR_SETTING_RESOLUTION_Y -#define S3L_PIXEL_FUNCTION LCR_pixelFunc3D +#define S3L_PIXEL_FUNCTION _LCR_pixelFuncc3D #define S3L_PERSPECTIVE_CORRECTION 2 #define S3L_NEAR_CROSS_STRATEGY 1 @@ -82,7 +82,18 @@ struct } LCR_renderer; -void LCR_pixelFunc3D(S3L_PixelInfo *pixel) +void LCR_rendererSetCarTransform(LCR_GameUnit position[3], + LCR_GameUnit rotation[3]) +{ + LCR_renderer.carModel->transform.translation.x = + (position[0] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT; + LCR_renderer.carModel->transform.translation.y = + (position[1] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT; + LCR_renderer.carModel->transform.translation.z = + (position[2] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT; +} + +void _LCR_pixelFuncc3D(S3L_PixelInfo *pixel) { // once we get a new triangle, we precompute things for it: if (pixel->triangleID != LCR_renderer.previousTriID)