gameplay: add block breaking

This commit is contained in:
Lephenixnoir 2022-07-17 14:58:19 +01:00
parent 7f93d324d4
commit 1a6cea1e19
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
5 changed files with 89 additions and 2 deletions

View File

@ -36,3 +36,35 @@ bool Game::moveCursorBy(WorldCoord dir)
this->cursorPos = this->world->limits.clampPoint(candidatePos);
return true;
}
int Game::blockBreakingDuration() const
{
BlockInfo *info = this->world->blockInfoAt(this->cursorPos);
if(!info)
return -1;
/* Determine how many ticks would be needed with the current tool */
// TODO: Query the user's current tool
int requiredTicks = info->baseBreakDurationTicks;
return requiredTicks;
}
int8_t Game::blockBreakingProgress() const
{
return this->damageTicks * 4 / this->blockBreakingDuration();
}
void Game::updateBlockBreaking()
{
if(this->damageTicks < 0)
return;
this->damageTicks++;
int requiredTicks = this->blockBreakingDuration();
if(this->damageTicks >= requiredTicks) {
this->world->trySetCellAt(this->cursorPos.x, this->cursorPos.y,
BlockID(AIR));
this->damageTicks = -1;
}
}

View File

@ -9,11 +9,27 @@ struct Game
World *world;
Camera *camera;
/* Current player/cursor positions (they are linked) */
WorldCoord playerPos;
WorldCoord cursorPos;
/* Current ticks spent damaging the pointed block, ≥ 0 when breaking */
int damageTicks;
bool isBreakingBlock() const {
return this->damageTicks >= 0;
}
/* Time required to break currently selected block */
int blockBreakingDuration() const;
/* Block breaking progress as a range 0-3 */
int8_t blockBreakingProgress() const;
/* Move the player by specified amount. */
bool movePlayerBy(WorldCoord dir, bool camera_follow=true);
/* Move the cursor by the specified amount. */
bool moveCursorBy(WorldCoord dir);
// --== Tick update functions ==--
void updateBlockBreaking();
};

View File

@ -57,6 +57,15 @@ static void renderGame(Game *game)
GlyphCluster playerCluster(GLYPH_DEGREE_UNDERLINE, ' ',
GLYPH_CAPITAL_LAMBDA, ' ');
GlyphCluster cursorCluster(0, GLYPH_OPLUS, 0, 0);
if(game->isBreakingBlock()) {
static Glyph breakingGlyphs[4] = {
GLYPH_MIDDLE_DOT, GLYPH_SMALL_SQUARE, GLYPH_CURRENCY_SIGN, 0x7f,
};
int stage = game->blockBreakingProgress();
cursorCluster.glyphs[1] = breakingGlyphs[stage];
}
Nooncraft::renderCamera(26, 12, camera, game->playerPos, playerCluster,
game->cursorPos, cursorCluster);
@ -105,6 +114,7 @@ int main(void)
game.playerPos = world->findSpawnPoint();
// TODO: Potential world border overflow here (unlikely)
game.cursorPos = game.playerPos + WorldCoord::Right;
game.damageTicks = -1;
volatile int nextFrame = 1;
int t = timer_configure(TIMER_ANY, 1000000/20, GINT_CALL_SET(&nextFrame));
@ -129,17 +139,26 @@ int main(void)
key_event_t ev;
while((ev = pollevent()).type != KEYEV_NONE) {
if(ev.type == KEYEV_UP)
if(ev.type == KEYEV_UP) {
if(ev.key == KEY_OPTN) {
game.damageTicks = -1;
continue;
}
continue;
}
if(getkey_global_shortcuts(ev))
continue;
if(ev.key == KEY_MENU)
runMainLoop = false;
if(ev.key == KEY_OPTN) {
if(game.world->canBreakBlock(game.cursorPos))
game.damageTicks = 0;
}
}
/* Clamp speed to 10 blocks/s */
if(tick % 2 == 0) {
if(tick % 2 == 0 && !game.isBreakingBlock()) {
if(keydown(KEY_LEFT) && !keydown(KEY_SHIFT))
game.movePlayerBy(WorldCoord::Left);
if(keydown(KEY_RIGHT) && !keydown(KEY_SHIFT))
@ -158,6 +177,8 @@ int main(void)
if(keydown(KEY_DOWN) && keydown(KEY_SHIFT))
game.moveCursorBy(WorldCoord::Down);
}
game.updateBlockBreaking();
}
timer_stop(t);

View File

@ -213,6 +213,20 @@ WorldCoord World::findSpawnPoint()
return WorldCoord(0, 0);
}
BlockInfo *World::blockInfoAt(WorldCoord p) const
{
if(!this->limits.contains(p))
return nullptr;
return Nooncraft::getBlockInfo(this->cellAt(p.x, p.y));
}
bool World::canBreakBlock(WorldCoord p) const
{
BlockInfo *info = blockInfoAt(p);
return info && info->breakability != Breakability::Fluid
&& info->breakability != Breakability::Unbreakable;
}
namespace Nooncraft {
World *mkWorld(int width, int height)

View File

@ -121,6 +121,10 @@ struct World
bool validSpawn(int x, int y) const;
WorldCoord findSpawnPoint();
BlockInfo *blockInfoAt(WorldCoord p) const;
bool canBreakBlock(WorldCoord p) const;
};
namespace Nooncraft {