/** racing module: implements the racing physics and logic. */ #ifndef _LCR_RACING_H #define _LCR_RACING_H typedef int32_t LCR_GameUnit; ///< abstract game unit #define LCR_GAME_UNIT 1024 ///< length of map square in LCR_GameUnits #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 1024 ///< length of map square for physics engine #include "map.h" #include "tinyphysicsengine.h" #define LCR_CAR_JOINTS 5 #define LCR_CAR_CONNECTIONS 10 struct { TPE_World physicsWorld; TPE_Body carBody; TPE_Joint carJoints[LCR_CAR_JOINTS]; TPE_Connection carConnections[LCR_CAR_CONNECTIONS]; } LCR_racing; TPE_Vec3 LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist) { 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_makeCenterRectFull(LCR_racing.carJoints, LCR_racing.carConnections, LCR_PHYSICS_UNIT / 2, (LCR_PHYSICS_UNIT * 3) / 4, LCR_PHYSICS_UNIT / 8); LCR_racing.carJoints[4].position.y += LCR_PHYSICS_UNIT / 8; 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); TPE_bodyDeactivate(&(LCR_racing.carBody)); } 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 TPE_Vec3 rot = TPE_bodyGetRotation(&(LCR_racing.carBody),0,2,1); rotation[0] = (rot.x * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT; rotation[1] = (rot.y * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT; rotation[2] = (rot.z * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT; } void _LCR_drawPhysicsDebugPixel(uint16_t x, uint16_t y, uint8_t color) { if (x > 1 && x < LCR_EFFECTIVE_RESOLUTION_X - 2 && y > 1 && y < LCR_EFFECTIVE_RESOLUTION_Y - 2) { 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,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_PHYSICS_UNIT / 32; if (input & LCR_RACING_INPUT_BACK) vel.y = LCR_PHYSICS_UNIT / 32; if (input & LCR_RACING_INPUT_RIGHT) vel.x = LCR_PHYSICS_UNIT / 32; if (input & LCR_RACING_INPUT_LEFT) vel.x = -1 * LCR_PHYSICS_UNIT / 32; TPE_bodyAccelerate(&(LCR_racing.carBody),vel); } TPE_bodyApplyGravity(&(LCR_racing.carBody), TPE_FRACTIONS_PER_UNIT / 32 ); TPE_worldStep(&(LCR_racing.physicsWorld)); } void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2], LCR_GameUnit camFov) { TPE_Vec3 cPos, cRot, cView; cPos.x = (camPos[0] * LCR_PHYSICS_UNIT) / LCR_GAME_UNIT; cPos.y = (camPos[1] * LCR_PHYSICS_UNIT) / LCR_GAME_UNIT; cPos.z = (camPos[2] * LCR_PHYSICS_UNIT) / LCR_GAME_UNIT; cRot.x = (camRot[0] * TPE_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; cRot.y = (camRot[1] * TPE_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; cRot.z = 0; cView.x = LCR_EFFECTIVE_RESOLUTION_X; cView.y = LCR_EFFECTIVE_RESOLUTION_Y; cView.z = (camFov * TPE_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; TPE_worldDebugDraw(&(LCR_racing.physicsWorld),_LCR_drawPhysicsDebugPixel, cPos,cRot,cView,16,2 * LCR_PHYSICS_UNIT); } #endif // guard