This commit is contained in:
Miloslav Ciz 2025-01-28 22:27:19 +01:00
parent e695921c5c
commit 6986028e33
4 changed files with 171 additions and 155 deletions

186
racing.h
View file

@ -43,8 +43,8 @@ typedef int32_t LCR_GameUnit; ///< abstract game unit
#define LCR_PHYSICS_UNIT 4096 ///< len. of square for phys. engine
#define TPE_RESHAPE_TENSION_LIMIT 3
#define TPE_RESHAPE_ITERATIONS 8
#define TPE_RESHAPE_TENSION_LIMIT 3
#define TPE_RESHAPE_ITERATIONS 8
#include "general.h"
#include "map.h"
@ -69,10 +69,10 @@ typedef int32_t LCR_GameUnit; ///< abstract game unit
#define LCR_CAR_CRASH_SPEED_SMALL 400
#define LCR_CAR_CRASH_SPEED_BIG 800
// multipliers (in 8ths) of friction and acceleration on concrete:
// Multipliers (in 8ths) of friction and acceleration on concrete:
#define LCR_CAR_GRASS_FACTOR 5
#define LCR_CAR_DIRT_FACTOR 3
#define LCR_CAR_ICE_FACTOR 1
#define LCR_CAR_DIRT_FACTOR 3
#define LCR_CAR_ICE_FACTOR 1
#define LCR_CAR_DRIFT_FACTOR 2 ///< only affects steering friction
#define LCR_CAR_JOINTS 5
@ -87,7 +87,7 @@ struct
TPE_Joint carJoints[LCR_CAR_JOINTS];
TPE_Connection carConnections[LCR_CAR_CONNECTIONS];
uint32_t tick;
uint32_t tick; ///< Physics tick (frame) number.
uint8_t wheelCollisions; /**< In individual bits records for each car wheel
whether it's currently touching the ground.
Lower bits record current collisions, higher
@ -111,19 +111,19 @@ struct
uint16_t crashState;
uint8_t playingReplay;
struct
{
uint16_t eventCount;
uint16_t events[LCR_SETTING_REPLAY_MAX_SIZE];
// for playing
uint16_t currentEvent;
uint16_t currentFrame;
uint32_t achievedTime;
} replay;
} LCR_racing;
struct
{
uint16_t eventCount;
uint16_t events[LCR_SETTING_REPLAY_MAX_SIZE];
// for playing
uint16_t currentEvent;
uint16_t currentFrame;
uint32_t achievedTime;
} LCR_replay; // TODO: move inside LCR_racing?
/**
Gets times of the run in milliseconds.
*/
@ -144,15 +144,15 @@ TPE_Vec3 _LCR_TPE_vec3DividePlain(TPE_Vec3 v, TPE_Unit d)
void LCR_replayInitRecording(void)
{
LCR_LOG1("initializing replay recording");
LCR_replay.eventCount = 0;
LCR_replay.achievedTime = 0;
LCR_racing.replay.eventCount = 0;
LCR_racing.replay.achievedTime = 0;
}
void LCR_replayInitPlaying(void)
{
LCR_LOG1("initializing replay playing");
LCR_replay.currentEvent = 0;
LCR_replay.currentFrame = 0;
LCR_racing.replay.currentEvent = 0;
LCR_racing.replay.currentFrame = 0;
}
/**
@ -185,14 +185,16 @@ void LCR_replayOutputStr(void (*printChar)(char))
// 8 decimal digits are enough to record 24 hours
#define PUTD(order) printChar('0' + (LCR_replay.achievedTime / order) % 10);
#define PUTD(order) \
printChar('0' + (LCR_racing.replay.achievedTime / order) % 10);
PUTD(10000000) PUTD(1000000) PUTD(100000) PUTD(10000)
PUTD(1000) PUTD(100) PUTD(10) PUTD(1)
#undef PUTD
for (int i = 0; i < LCR_replay.eventCount; ++i)
for (int i = 0; i < LCR_racing.replay.eventCount; ++i)
{
uint16_t e = LCR_replay.events[i];
uint16_t e = LCR_racing.replay.events[i];
printChar(':');
for (int j = 0; j < 4; ++j)
@ -208,51 +210,35 @@ void LCR_replayOutputStr(void (*printChar)(char))
/**
Reads replay from string using provided function that returns next character
in the string. The mapHash and nameHash pointers are optional: if non-zero,
they will be filled with the map hash and name hash. Returns 1 on success,
else 0.
the memory they point to will be filled with the map hash and name hash.
Returns 1 on success, else 0.
*/
int LCR_replayLoadFromStr(char (*nextChar)(void),
uint32_t *mapHash, uint16_t *nameHash)
{
char c = ' ';
LCR_replay.eventCount = 0;
LCR_replay.achievedTime = 0;
LCR_racing.replay.eventCount = 0;
LCR_racing.replay.achievedTime = 0;
if (nameHash)
*nameHash = _LCR_simpleStrHash(nextChar,';');
else
_LCR_simpleStrHash(nextChar,';');
if (nameHash)
*nameHash = _LCR_simpleStrHash(nextChar,';');
else
_LCR_simpleStrHash(nextChar,';');
/*
do // map name
if (mapHash)
*mapHash = 0;
for (int i = 0; i < 8; ++i) // hash
{
c = nextChar();
if (c == 0)
if (_LCR_hexDigitVal(c) < 0)
return 0;
} while (c != ';');
*/
if (mapHash)
*mapHash = 0;
for (int i = 0; i < 8; ++i) // hash
{
c = nextChar();
if (_LCR_hexDigitVal(c) < 0)
return 0;
if (mapHash)
*mapHash = ((*mapHash) << 4) | _LCR_hexDigitVal(c);
}
/*
for (int i = 0; i < 8; ++i) // hash
if (_LCR_hexDigitVal(nextChar()) < 0)
return 0;
*/
if (mapHash)
*mapHash = ((*mapHash) << 4) | _LCR_hexDigitVal(c);
}
nextChar();
@ -263,7 +249,8 @@ for (int i = 0; i < 8; ++i) // hash
if (c < '0' || c > '9')
break;
LCR_replay.achievedTime = LCR_replay.achievedTime * 10 + c - '0';
LCR_racing.replay.achievedTime =
LCR_racing.replay.achievedTime * 10 + c - '0';
}
while (c != 0) // events
@ -278,11 +265,11 @@ for (int i = 0; i < 8; ++i) // hash
if (e == 0)
break;
if (LCR_replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE)
if (LCR_racing.replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE)
return 0;
LCR_replay.events[LCR_replay.eventCount] = e;
LCR_replay.eventCount++;
LCR_racing.replay.events[LCR_racing.replay.eventCount] = e;
LCR_racing.replay.eventCount++;
}
c = nextChar();
@ -292,60 +279,61 @@ for (int i = 0; i < 8; ++i) // hash
}
/**
During playing of a replay returns the next input and shifts to next frame.
When playing back a replay this function returns the next recorded input and
shifts to the next frame.
*/
uint8_t LCR_replayGetNextInput(void)
{
if (LCR_replay.currentEvent >= LCR_replay.eventCount)
if (LCR_racing.replay.currentEvent >= LCR_racing.replay.eventCount)
{
LCR_replay.currentFrame++; // has to be here
LCR_racing.replay.currentFrame++; // has to be here
return 0;
}
if (LCR_replay.currentFrame ==
(LCR_replay.events[LCR_replay.currentEvent] >> 4))
if (LCR_racing.replay.currentFrame ==
(LCR_racing.replay.events[LCR_racing.replay.currentEvent] >> 4))
{
LCR_replay.currentEvent++;
LCR_replay.currentFrame = 0;
LCR_racing.replay.currentEvent++;
LCR_racing.replay.currentFrame = 0;
}
LCR_replay.currentFrame++;
LCR_racing.replay.currentFrame++;
return LCR_replay.currentEvent ?
(LCR_replay.events[LCR_replay.currentEvent - 1] & 0x0f) : 0;
return LCR_racing.replay.currentEvent ?
(LCR_racing.replay.events[LCR_racing.replay.currentEvent - 1] & 0x0f) : 0;
}
int LCR_replayHasFinished(void)
{
if (LCR_replay.currentEvent == LCR_replay.eventCount)
if (LCR_racing.replay.currentEvent == LCR_racing.replay.eventCount)
{
uint32_t totalTime = LCR_replay.currentFrame;
uint32_t totalTime = LCR_racing.replay.currentFrame;
for (int i = 0; i < LCR_replay.eventCount; ++i)
totalTime += LCR_replay.events[i] >> 4;
for (int i = 0; i < LCR_racing.replay.eventCount; ++i)
totalTime += LCR_racing.replay.events[i] >> 4;
return totalTime >= LCR_replay.achievedTime;
return totalTime >= LCR_racing.replay.achievedTime;
}
return LCR_replay.currentEvent > LCR_replay.eventCount;
return LCR_racing.replay.currentEvent > LCR_racing.replay.eventCount;
}
/**
Records another input event. Returns 1 on success, or 0 if the event couldn't
be recorded. The event is only added if necessary, i.e. this function can
(and must) be called every frame without worrying about inflating its size.
When the run ends, the LCR_REPLAY_EVENT_END has to be fed!
Records another input event into a replay. Returns 1 on success, or 0 if the
event couldn't be recorded. The event is only added if necessary, i.e. this
function can, and MUST, be called every frame without worrying about inflating
its size. When the run ends, the LCR_REPLAY_EVENT_END has to be fed!
*/
int LCR_replayRecordEvent(uint32_t frame, uint8_t input)
{
LCR_LOG2("recording replay event");
if (LCR_replay.achievedTime)
if (LCR_racing.replay.achievedTime)
return 1; // already finished
if (input == LCR_REPLAY_EVENT_END)
{
LCR_replay.achievedTime = frame;
LCR_racing.replay.achievedTime = frame;
LCR_LOG1("replay recording finished");
return 1;
}
@ -354,10 +342,10 @@ int LCR_replayRecordEvent(uint32_t frame, uint8_t input)
uint8_t previousInput = 0;
uint32_t previousFrame = 0;
for (int i = 0; i < LCR_replay.eventCount; ++i)
for (int i = 0; i < LCR_racing.replay.eventCount; ++i)
{
previousInput = LCR_replay.events[i] & 0x0f;
previousFrame += LCR_replay.events[i] >> 4;
previousInput = LCR_racing.replay.events[i] & 0x0f;
previousFrame += LCR_racing.replay.events[i] >> 4;
}
if (input == previousInput)
@ -368,30 +356,30 @@ int LCR_replayRecordEvent(uint32_t frame, uint8_t input)
frame -= previousFrame; // convert to offset
while (frame > 4095 && LCR_replay.eventCount < LCR_SETTING_REPLAY_MAX_SIZE)
while (frame > 4095 && LCR_racing.replay.eventCount < LCR_SETTING_REPLAY_MAX_SIZE)
{
// add intermediate events
frame -= 4095;
previousFrame += 4095;
LCR_replay.events[LCR_replay.eventCount] =
LCR_racing.replay.events[LCR_racing.replay.eventCount] =
(previousFrame << 4) | previousInput;
LCR_replay.eventCount++;
LCR_racing.replay.eventCount++;
}
if (LCR_replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE)
if (LCR_racing.replay.eventCount >= LCR_SETTING_REPLAY_MAX_SIZE)
return 0;
LCR_replay.events[LCR_replay.eventCount] = (frame << 4) | (input & 0x0f);
LCR_replay.eventCount++;
LCR_racing.replay.events[LCR_racing.replay.eventCount] = (frame << 4) | (input & 0x0f);
LCR_racing.replay.eventCount++;
#endif
return 1;
}
/**
Helper function for _LCR_racingEnvironmentFunction, returns closest point
on a map block placed at coordinate origin.
Helper function for _LCR_racingEnvironmentFunction, returns closest point on
a map block placed at coordinate origin.
*/
TPE_Vec3 _LCR_racingBlockEnvFunc(TPE_Vec3 point, const uint8_t *block)
{
@ -691,8 +679,8 @@ TPE_Vec3 _LCR_racingBlockEnvFunc(TPE_Vec3 point, const uint8_t *block)
}
/**
For tinyphysicsengine, function that defines the shape of physics world,
returns closest point to any given point in space.
For tinyphysicsengine, function that defines the shape of the static physics
world, returns closest point to any given point in space.
*/
TPE_Vec3 _LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
{
@ -795,10 +783,10 @@ LCR_GameUnit LCR_racingGetCarSpeedSigned(void)
uint8_t _LCR_racingCollisionHandler(uint16_t b1, uint16_t j1, uint16_t b2,
uint16_t j2, TPE_Vec3 p)
{
// check which wheels are touching the ground.
#if LCR_SETTING_CRASH_SOUNDS
TPE_Unit speed = TPE_vec3Len( // detect crashes
// Detect crashes:
TPE_Unit speed = TPE_vec3Len(
TPE_vec3Project(
TPE_vec3(
LCR_racing.carBody.joints[j1].velocity[0],
@ -811,6 +799,8 @@ uint8_t _LCR_racingCollisionHandler(uint16_t b1, uint16_t j1, uint16_t b2,
(speed >= LCR_CAR_CRASH_SPEED_SMALL);
#endif
// Check which wheels are touching the ground:
if (j1 < 4) // wheel joint?
LCR_racing.wheelCollisions |= 0x01 << j1;