Start ghost
This commit is contained in:
parent
c0f5e5cf5b
commit
0a91d5f54e
4 changed files with 105 additions and 9 deletions
3
TODO.txt
3
TODO.txt
|
@ -1,6 +1,9 @@
|
||||||
=========== GENERAL ==============
|
=========== GENERAL ==============
|
||||||
|
|
||||||
- replay validation
|
- replay validation
|
||||||
|
- ghosts: if the replay for the ghost is too long (too many samples for the
|
||||||
|
preallocated array), we can subdivide the sample resolution (i.e. "stretch"
|
||||||
|
the samples) to cover the whole replay (ofc for the price of worse quality).
|
||||||
- add argc/argv to gameInit? could be used to quickly start maps, verify
|
- add argc/argv to gameInit? could be used to quickly start maps, verify
|
||||||
replays etc.
|
replays etc.
|
||||||
- maybe each map could have a target time embedded: when beaten, the map would
|
- maybe each map could have a target time embedded: when beaten, the map would
|
||||||
|
|
72
game.h
72
game.h
|
@ -211,6 +211,12 @@ static inline void LCR_drawPixelXYSafe(unsigned int x, unsigned int y,
|
||||||
#define LCR_MENU_MAX_ITEMS 9 // don't change
|
#define LCR_MENU_MAX_ITEMS 9 // don't change
|
||||||
#define LCR_RESOURCE_ITEM_CHUNK (LCR_MENU_MAX_ITEMS - 1)
|
#define LCR_RESOURCE_ITEM_CHUNK (LCR_MENU_MAX_ITEMS - 1)
|
||||||
#define LCR_MENU_TABS 4
|
#define LCR_MENU_TABS 4
|
||||||
|
|
||||||
|
#if LCR_SETTING_GHOST_MAX_SAMPLES == 0
|
||||||
|
#undef LCR_MENU_TABS
|
||||||
|
#define LCR_MENU_TABS 3
|
||||||
|
#endif
|
||||||
|
|
||||||
#define LCR_MENU_STRING_SIZE 16
|
#define LCR_MENU_STRING_SIZE 16
|
||||||
|
|
||||||
#define LCR_RESOURCE_FILE_SEPARATOR '#'
|
#define LCR_RESOURCE_FILE_SEPARATOR '#'
|
||||||
|
@ -266,6 +272,23 @@ struct
|
||||||
unsigned int firstItemIndex;
|
unsigned int firstItemIndex;
|
||||||
unsigned int itemsTotal;
|
unsigned int itemsTotal;
|
||||||
} dataFile;
|
} dataFile;
|
||||||
|
|
||||||
|
#define LCR_GHOST_SAMPLE_SIZE 5
|
||||||
|
|
||||||
|
#if LCR_SETTING_GHOST_MAX_SAMPLES != 0
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t samples[LCR_SETTING_GHOST_MAX_SAMPLES * LCR_GHOST_SAMPLE_SIZE];
|
||||||
|
/**< Samples, each 5 bytes: 9 bits for X and Z, 10 for Z,
|
||||||
|
4 for each rotation component. */
|
||||||
|
uint8_t stretch; /**< Stretch of the base sample step, as a bit shift
|
||||||
|
(i.e. 1 means the step will be 2x as long etc.). This
|
||||||
|
is to allow ghosts for even long replays. */
|
||||||
|
const uint8_t *currentSample;
|
||||||
|
uint16_t nextSampleIn;
|
||||||
|
} ghost;
|
||||||
|
#endif
|
||||||
|
|
||||||
} LCR_game;
|
} LCR_game;
|
||||||
|
|
||||||
uint8_t LCR_gameMusicOn(void)
|
uint8_t LCR_gameMusicOn(void)
|
||||||
|
@ -314,13 +337,6 @@ void LCR_gameSetState(uint8_t state)
|
||||||
LCR_game.stateStartTime = LCR_game.time;
|
LCR_game.stateStartTime = LCR_game.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
LCR_GameUnit LCR_carSpeedKMH(void)
|
|
||||||
{
|
|
||||||
return // we use 28/8 as an approximation of 3.6 to convers MPS to KMH
|
|
||||||
(28 * LCR_SETTING_CMS_PER_BLOCK * LCR_racingGetCarSpeedUnsigned() *
|
|
||||||
LCR_RACING_FPS) / (800 * LCR_GAME_UNIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LCR_gameResetRun(uint8_t replay)
|
void LCR_gameResetRun(uint8_t replay)
|
||||||
{
|
{
|
||||||
LCR_GameUnit carTransform[6];
|
LCR_GameUnit carTransform[6];
|
||||||
|
@ -336,6 +352,42 @@ void LCR_gameResetRun(uint8_t replay)
|
||||||
LCR_game.runTimeMS = 0;
|
LCR_game.runTimeMS = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _LCR_gamePrepareGhost(void)
|
||||||
|
{
|
||||||
|
LCR_GameUnit carTransform[6];
|
||||||
|
LCR_LOG1("preparing ghost");
|
||||||
|
|
||||||
|
LCR_gameResetRun(1);
|
||||||
|
|
||||||
|
LCR_game.ghost.stretch = 0;
|
||||||
|
|
||||||
|
while (((int) LCR_replay.achievedTime) >
|
||||||
|
(LCR_SETTING_GHOST_STEP << LCR_game.ghost.stretch) *
|
||||||
|
LCR_SETTING_GHOST_MAX_SAMPLES)
|
||||||
|
{
|
||||||
|
LCR_LOG2("stretching replay step");
|
||||||
|
LCR_game.ghost.stretch++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!LCR_replayHasFinished())
|
||||||
|
{
|
||||||
|
if (LCR_racing.tick % (LCR_SETTING_GHOST_STEP << LCR_game.ghost.stretch)
|
||||||
|
== 0)
|
||||||
|
{
|
||||||
|
LCR_racingGetCarTransform(carTransform,carTransform + 3,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LCR_racingStep(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LCR_GameUnit LCR_carSpeedKMH(void)
|
||||||
|
{
|
||||||
|
return // we use 28/8 as an approximation of 3.6 to convers MPS to KMH
|
||||||
|
(28 * LCR_SETTING_CMS_PER_BLOCK * LCR_racingGetCarSpeedUnsigned() *
|
||||||
|
LCR_RACING_FPS) / (800 * LCR_GAME_UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Rewinds the global data file reading head to the beginning.
|
Rewinds the global data file reading head to the beginning.
|
||||||
*/
|
*/
|
||||||
|
@ -1014,6 +1066,12 @@ uint8_t LCR_gameStep(uint32_t time)
|
||||||
if (_LCR_gameIsLoading())
|
if (_LCR_gameIsLoading())
|
||||||
{
|
{
|
||||||
LCR_rendererLoadMap();
|
LCR_rendererLoadMap();
|
||||||
|
|
||||||
|
if (LCR_game.state == LCR_GAME_STATE_LOADING_REP2)
|
||||||
|
{
|
||||||
|
_LCR_gamePrepareGhost();
|
||||||
|
}
|
||||||
|
|
||||||
LCR_gameResetRun(
|
LCR_gameResetRun(
|
||||||
LCR_game.state == LCR_GAME_STATE_LOADING_REP1);
|
LCR_game.state == LCR_GAME_STATE_LOADING_REP1);
|
||||||
}
|
}
|
||||||
|
|
24
racing.h
24
racing.h
|
@ -295,7 +295,10 @@ for (int i = 0; i < 8; ++i) // hash
|
||||||
uint8_t LCR_replayGetNextInput(void)
|
uint8_t LCR_replayGetNextInput(void)
|
||||||
{
|
{
|
||||||
if (LCR_replay.currentEvent >= LCR_replay.eventCount)
|
if (LCR_replay.currentEvent >= LCR_replay.eventCount)
|
||||||
|
{
|
||||||
|
LCR_replay.currentFrame++; // has to be here
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (LCR_replay.currentFrame ==
|
if (LCR_replay.currentFrame ==
|
||||||
(LCR_replay.events[LCR_replay.currentEvent] >> 4))
|
(LCR_replay.events[LCR_replay.currentEvent] >> 4))
|
||||||
|
@ -312,7 +315,19 @@ uint8_t LCR_replayGetNextInput(void)
|
||||||
|
|
||||||
int LCR_replayHasFinished(void)
|
int LCR_replayHasFinished(void)
|
||||||
{
|
{
|
||||||
return LCR_replay.currentEvent >= LCR_replay.eventCount;
|
if (LCR_replay.currentEvent == LCR_replay.eventCount)
|
||||||
|
{
|
||||||
|
uint32_t totalTime = LCR_replay.currentFrame;
|
||||||
|
|
||||||
|
for (int i = 0; i < LCR_replay.eventCount; ++i)
|
||||||
|
totalTime += LCR_replay.events[i] >> 4;
|
||||||
|
|
||||||
|
return totalTime >= LCR_replay.achievedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LCR_replay.currentEvent > LCR_replay.eventCount;
|
||||||
|
|
||||||
|
// return LCR_replay.currentEvent >= LCR_replay.eventCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1084,8 +1099,13 @@ uint32_t LCR_racingStep(unsigned int input)
|
||||||
if (LCR_racing.tick == 0)
|
if (LCR_racing.tick == 0)
|
||||||
LCR_replayInitPlaying();
|
LCR_replayInitPlaying();
|
||||||
|
|
||||||
input = LCR_replayGetNextInput();
|
if (LCR_replayHasFinished())
|
||||||
|
{
|
||||||
|
LCR_LOG1("replay finished");
|
||||||
|
return LCR_RACING_EVENT_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
input = LCR_replayGetNextInput();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
15
settings.h
15
settings.h
|
@ -205,4 +205,19 @@
|
||||||
#define LCR_SETTING_TIME_MULTIPLIER 100
|
#define LCR_SETTING_TIME_MULTIPLIER 100
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef LCR_SETTING_GHOST_STEP
|
||||||
|
/** Step (in physics engine ticks) by which the samples for ghost car will be
|
||||||
|
spaced (positions inbetween will be interpolated). Lower step along with more
|
||||||
|
ghost samples should result in more accurate ghost animation, but will eat up
|
||||||
|
more memory. This should ideally be kept a power of two. */
|
||||||
|
#define LCR_SETTING_GHOST_STEP 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LCR_SETTING_GHOST_MAX_SAMPLES
|
||||||
|
/** Maximum number of samples the ghost car will be able to use. Higher value
|
||||||
|
should generally result in more accurate ghost animation, but will eat up more
|
||||||
|
memory. Value 0 disables ghosts. */
|
||||||
|
#define LCR_SETTING_GHOST_MAX_SAMPLES 128
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // guard
|
#endif // guard
|
||||||
|
|
Loading…
Reference in a new issue