gameplay: add block breaking
This commit is contained in:
parent
7f93d324d4
commit
1a6cea1e19
32
src/game.cpp
32
src/game.cpp
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
16
src/game.h
16
src/game.h
|
@ -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();
|
||||
};
|
||||
|
|
25
src/main.cpp
25
src/main.cpp
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue