summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2018-07-09 02:43:50 +0300
committerOxore <oxore@protonmail.com>2018-07-09 02:43:50 +0300
commita9e7132e6a430e86e8a69d1301252e38daf6e593 (patch)
tree08e7865c55883e40db966a9851b546b95bc4524b
parent67186f876e17696858495a2a7a699344b0f94178 (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.md2
-rw-r--r--include/field.h16
-rw-r--r--src/engine.c60
-rw-r--r--src/field.c63
-rw-r--r--src/main.c5
-rw-r--r--src/painter.c15
6 files changed, 108 insertions, 53 deletions
diff --git a/README.md b/README.md
index d0cf87e..d213330 100644
--- a/README.md
+++ b/README.md
@@ -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);
-}
diff --git a/src/main.c b/src/main.c
index 6eafc6e..df98a0b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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)