diff options
author | Oxore <oxore@protonmail.com> | 2018-07-09 02:43:50 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2018-07-09 02:43:50 +0300 |
commit | a9e7132e6a430e86e8a69d1301252e38daf6e593 (patch) | |
tree | 08e7865c55883e40db966a9851b546b95bc4524b | |
parent | 67186f876e17696858495a2a7a699344b0f94178 (diff) |
Introduce phantom shape, refactor field
Introduce phantom shape feature, yay!
Refactor field: rename attribute of invisible empty cells, remove
"color" member from struct shape, introduce shape movement functions
with embedded collision checking and success reporting,
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | include/field.h | 16 | ||||
-rw-r--r-- | src/engine.c | 60 | ||||
-rw-r--r-- | src/field.c | 63 | ||||
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/painter.c | 15 |
6 files changed, 108 insertions, 53 deletions
@@ -38,7 +38,7 @@ Look at the [repo releases](https://github.com/Oxore/tetris-csfml/releases)! Now - [x] Scoring system as in Tetris for NES which is described on [this page](https://tetris.wiki/Scoring) - [Wall kick](https://tetris.wiki/Wall_kick) - Hard drop -- Phantom shape +- [x] Phantom shape - Table of records - Settings menu with external `config.yml` file which allows - Change key bindings diff --git a/include/field.h b/include/field.h index 30ed56b..52b4de8 100644 --- a/include/field.h +++ b/include/field.h @@ -1,5 +1,7 @@ -#define FLD_ATTR_INVISIBLE (1 << 0) -#define FLD_ATTR_TRANSPARENT (1 << 1) +#define FLD_ATTR_INVISIBLE (1 << 0) +#define FLD_ATTR_HIDE_EMPTY_CELLS (1 << 1) + +#define SHP_ATTR_GHOST (1 << 0) struct cell { char a; // active/empty state of cell @@ -24,11 +26,10 @@ struct cell { */ struct shape { - int x; // x coord of shape's left side - int y; // y coord of shape's bottom + struct vector2i; // position int t; // shape type - unsigned int color; // shape color - char c[4][4]; // array of logic shape cells + unsigned int attr; + char c[4][4]; }; struct field { @@ -47,6 +48,9 @@ void field_deinit(struct field *fld); void field_fill_random(struct field *fld); void field_clear(struct field *fld); void field_rotate_shape(struct field *fld, unsigned int index); +int field_move_shape_down(struct field *fld, unsigned int index); +int field_move_shape_left(struct field *fld, unsigned int index); +int field_move_shape_right(struct field *fld, unsigned int index); void field_put_shape(struct field *fld, struct shape *shape); void field_reset_walking_shape(struct field *fld, unsigned int index); int field_rm_lines(struct field *fld); diff --git a/src/engine.c b/src/engine.c index c218105..72fdbfc 100644 --- a/src/engine.c +++ b/src/engine.c @@ -160,6 +160,7 @@ static void transition_game_over() painter_update_field(nxt.id, &nxt); fld.shape[0].y = fld.size.y; + fld.shape[1].y = fld.size.y; field_fill_random(&fld); painter_update_field(fld.id, &fld); @@ -169,14 +170,29 @@ static void transition_game_over() list_foreach(texts, update_game_text); } +static void project_ghost_shape(struct field *fld, unsigned int idreal, unsigned int idghost) +{ + fld->shape[idghost].t = fld->shape[idreal].t; + fld->shape[idghost].x = fld->shape[idreal].x; + fld->shape[idghost].y = fld->shape[idreal].y; + for (unsigned int j = 0; j < 4; j++) + for (unsigned int i = 0; i < 4; i++) + fld->shape[idghost].c[j][i] = fld->shape[idreal].c[j][i]; + do { + --fld->shape[idghost].y; + } while (!field_shape_collision(fld, &fld->shape[idghost])); + ++fld->shape[idghost].y; +} + static void transition_put_shape() { - field_put_shape(&fld, &fld.shape[0]); + field_put_shape(&fld, &fld.shape[1]); int removedLines = field_rm_lines(&fld); game.lines += removedLines; game.scoreCurrent += rmlines_score[removedLines] * game.level; - fld.shape[0].t = nxt.shape[0].t; - field_reset_walking_shape(&fld, 0); + fld.shape[1].t = nxt.shape[0].t; + field_reset_walking_shape(&fld, 1); + project_ghost_shape(&fld, 1, 0); for (unsigned int s = 0; s < nxt.shape_cnt - 1; ++s) { nxt.shape[s] = nxt.shape[s + 1]; nxt.shape[s].y = 4 - s * 3; @@ -188,13 +204,12 @@ static void transition_put_shape() static void game_tick() { sfClock_restart(game.gameTick); - fld.shape[0].y--; // try - if (field_shape_collision(&fld, &fld.shape[0])) - fld.shape[0].y++; // fallback - else + if (field_move_shape_down(&fld, 1)) { + project_ghost_shape(&fld, 1, 0); sfClock_restart(game.putTick); + } if (sfClock_getElapsedTime(game.putTick).microseconds >= PUT_LATENCY) { - if (field_shape_out_of_bounds(&fld, &fld.shape[0])) + if (field_shape_out_of_bounds(&fld, &fld.shape[1])) transition_game_over(); else transition_put_shape(); @@ -204,15 +219,14 @@ static void game_tick() static void signal_up() { - field_rotate_shape(&fld, 0); + field_rotate_shape(&fld, 1); + project_ghost_shape(&fld, 1, 0); } static void signal_down() { - fld.shape[0].y--; - if (field_shape_collision(&fld, &fld.shape[0])) { - fld.shape[0].y++; - } else { + if (field_move_shape_down(&fld, 1)) { + project_ghost_shape(&fld, 1, 0); sfClock_restart(game.gameTick); game.scoreCurrent++; } @@ -221,21 +235,19 @@ static void signal_down() static void signal_left() { - fld.shape[0].x--; - if (field_shape_collision(&fld, &fld.shape[0])) - fld.shape[0].x++; - else + if (field_move_shape_left(&fld, 1)) { + project_ghost_shape(&fld, 1, 0); sfClock_restart(game.putTick); + } sfClock_restart(game.repKeyLeft); } static void signal_right() { - fld.shape[0].x++; - if (field_shape_collision(&fld, &fld.shape[0])) - fld.shape[0].x--; - else + if (field_move_shape_right(&fld, 1)) { + project_ghost_shape(&fld, 1, 0); sfClock_restart(game.putTick); + } sfClock_restart(game.repKeyRight); } @@ -322,8 +334,10 @@ static void transition_game_start() { game.isStarted = 1; field_clear(&fld); - shape_gen_random(&fld.shape[0]); - field_reset_walking_shape(&fld, 0); + shape_gen_random(&fld.shape[1]); + field_reset_walking_shape(&fld, 1); + project_ghost_shape(&fld, 1, 0); + shape_load(&fld.shape[1]); for (unsigned int i = 0; i < nxt.shape_cnt; ++i) shape_gen_random(&nxt.shape[i]); nxt.attr &= ~FLD_ATTR_INVISIBLE; diff --git a/src/field.c b/src/field.c index 18b4fed..62b6455 100644 --- a/src/field.c +++ b/src/field.c @@ -29,6 +29,13 @@ void field_init(struct field *fld) fld->shape = calloc(fld->shape_cnt, sizeof(struct shape)); } +void field_deinit(struct field *fld) { + for (int j = 0; j < (int)fld->bound.y; j++) + free(fld->c[j]); + free(fld->c); + free(fld->shape); +} + void field_clear(struct field *fld) { for (unsigned int j = 0; j < fld->bound.y; j++) @@ -53,7 +60,7 @@ void field_put_shape(struct field *fld, struct shape *active) for (int i = 0; i < 4; i++) if (active->c[j][i]) { fld->c[j+active->y][i+active->x].a = active->c[j][i]; - fld->c[j+active->y][i+active->x].color = active->color; + fld->c[j+active->y][i+active->x].color = active->t; } } @@ -68,7 +75,6 @@ int field_shape_out_of_bounds(struct field *fld, struct shape *active) void shape_load(struct shape *shape) { - shape->color = shape->t; switch (shape->t) { // Copy cell active/inactive state case 1 : memcpy(&shape->c[0][0], &arrShapeL[0][0], sizeof(char)*4*4); @@ -96,15 +102,15 @@ void shape_load(struct shape *shape) void field_reset_walking_shape(struct field *fld, unsigned int index) { - struct shape *active = &fld->shape[index]; - shape_load(active); - active->x = 3; - if (active->t == 6) - active->y = 19; + struct shape *shape = &fld->shape[index]; + shape_load(shape); + shape->x = 3; + if (shape->t == 6) + shape->y = 19; else - active->y = 18; - while (field_shape_collision(fld, active)) - active->y++; + shape->y = 18; + while (field_shape_collision(fld, shape)) + shape->y++; } void shape_gen_random(struct shape *shape) @@ -181,6 +187,36 @@ void field_rotate_shape(struct field *fld, unsigned int index) rotate_shape_left(shape); } +int field_move_shape_down(struct field *fld, unsigned int index) +{ + fld->shape[index].y--; + if (field_shape_collision(fld, &fld->shape[index])) { + fld->shape[index].y++; + return 0; + } + return -1; +} + +int field_move_shape_left(struct field *fld, unsigned int index) +{ + fld->shape[index].x--; + if (field_shape_collision(fld, &fld->shape[index])) { + fld->shape[index].x++; + return 0; + } + return -1; +} + +int field_move_shape_right(struct field *fld, unsigned int index) +{ + fld->shape[index].x++; + if (field_shape_collision(fld, &fld->shape[index])) { + fld->shape[index].x--; + return 0; + } + return -1; +} + int field_rm_lines(struct field *fld) { unsigned int lines = 0; @@ -201,10 +237,3 @@ int field_rm_lines(struct field *fld) } return lines; } - -void field_deinit(struct field *fld) { - for (int j = 0; j < (int)fld->bound.y; j++) - free(fld->c[j]); - free(fld->c); - free(fld->shape); -} @@ -70,14 +70,15 @@ int main() fld.pos = FLD_POS; fld.size = (struct vector2ui){.x = FLD_SIZE_X, .y = FLD_SIZE_Y}; fld.bound = (struct vector2ui){.x = FLD_BOUND_X, .y = FLD_BOUND_Y}; - fld.shape_cnt = 1; + fld.shape_cnt = 2; field_init(&fld); + fld.shape[0].attr |= SHP_ATTR_GHOST; nxt.pos = NXT_POS; nxt.size = NXT_SIZE; nxt.bound = NXT_SIZE; nxt.shape_cnt = 3; - nxt.attr |= FLD_ATTR_TRANSPARENT | FLD_ATTR_INVISIBLE; + nxt.attr |= FLD_ATTR_HIDE_EMPTY_CELLS | FLD_ATTR_INVISIBLE; field_init(&nxt); nxt.shape[0].y = 4; nxt.shape[1].y = 1; diff --git a/src/painter.c b/src/painter.c index 9f6b911..c0e93ea 100644 --- a/src/painter.c +++ b/src/painter.c @@ -120,7 +120,7 @@ void painter_update_field(unsigned long id, struct field *fld) if (fld->c[j][i].a) { sfRectangleShape_setFillColor(f->p[j][i], shape_color_map[fld->c[j][i].color]); sfRectangleShape_setOutlineColor(f->p[j][i], (sfColor)UIFGACTIVECOLOR); - } else if (f->attr & FLD_ATTR_TRANSPARENT) { + } else if (f->attr & FLD_ATTR_HIDE_EMPTY_CELLS) { sfRectangleShape_setFillColor(f->p[j][i], (sfColor)UITRANSPARENT); sfRectangleShape_setOutlineColor(f->p[j][i], (sfColor)UITRANSPARENT); } else { @@ -129,17 +129,24 @@ void painter_update_field(unsigned long id, struct field *fld) } } } - for (unsigned int s = 0; s < fld->shape_cnt; ++s) + for (unsigned int s = 0; s < fld->shape_cnt; ++s) { + sfColor fill_color = shape_color_map[fld->shape[s].t]; + sfColor outline_color = (sfColor)UIFGACTIVECOLOR; + if (fld->shape[s].attr && SHP_ATTR_GHOST) { + fill_color.a = 100; + outline_color.a = 100; + } for (int j = 0; j < 4; j++) for (int i = 0; i < 4; i++) if (fld->shape[s].c[j][i] && j + fld->shape[s].y < (int)fld->size.y) { sfRectangleShape_setFillColor( f->p[j + fld->shape[s].y][i + fld->shape[s].x], - shape_color_map[fld->shape[s].color]); + fill_color); sfRectangleShape_setOutlineColor( f->p[j + fld->shape[s].y][i + fld->shape[s].x], - (sfColor)UIFGACTIVECOLOR); + outline_color); } + } } static void draw_field_drawable(struct drawable *d) |