diff --git a/data/collider/Makefile.am b/data/collider/Makefile.am index f36abb6..cb08656 100644 --- a/data/collider/Makefile.am +++ b/data/collider/Makefile.am @@ -10,7 +10,8 @@ nobase_dist_collidergamedata_DATA = \ penguin_7.col \ penguin_8.col \ penguin_9.col \ - penguin_10.col + penguin_10.col \ + bag_3.col noinst_PROGRAMS = penguin-generator collider-generator penguin_generator_SOURCES = generate-penguins.c \ @@ -54,3 +55,4 @@ colliders: collider-generator penguin-generator $(COLLIDER_GENERATOR) penguin_10.png penguin_10.col rm penguin_1.png penguin_2.png penguin_3.png penguin_4.png penguin_5.png penguin_6.png penguin_7.png penguin_8.png penguin_9.png penguin_10.png + $(COLLIDER_GENERATOR) $(top_srcdir)/data/images/bag_3.png bag_3.col diff --git a/data/collider/bag_3.col b/data/collider/bag_3.col new file mode 100755 index 0000000..a184c7d Binary files /dev/null and b/data/collider/bag_3.col differ diff --git a/src/Makefile.am b/src/Makefile.am index fea1939..d07f93e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,8 @@ bin_PROGRAMS = bean-counters-classic bean_counters_classic_SOURCES = beans.c \ gfx_blit_func.c gfx_blit_func.h \ path.c path.h \ + collider.c collider.h \ + sdl2_rect.c sdl2_rect.h \ gettext.h if MACOSX diff --git a/src/beans.c b/src/beans.c index 86024e3..1c98d3f 100644 --- a/src/beans.c +++ b/src/beans.c @@ -42,6 +42,7 @@ #include "path.h" #include "gfx_blit_func.h" +#include "collider.h" #define FPS (1000/24) #define RANDOM(x) ((int) (x ## .0 * rand () / (RAND_MAX + 1.0))) @@ -228,6 +229,38 @@ enum { NUM_PENGUIN_FRAMES }; +enum { + COLLIDER_BAG_3, + + COLLIDER_PENGUIN_1, + COLLIDER_PENGUIN_2, + COLLIDER_PENGUIN_3, + COLLIDER_PENGUIN_4, + COLLIDER_PENGUIN_5, + COLLIDER_PENGUIN_6, + COLLIDER_PENGUIN_7, + COLLIDER_PENGUIN_8, + COLLIDER_PENGUIN_9, + COLLIDER_PENGUIN_10, + + NUM_COLLIDERS +}; + +const char *collider_names[NUM_COLLIDERS] = { + "collider/bag_3.col", + + "collider/penguin_1.col", + "collider/penguin_2.col", + "collider/penguin_3.col", + "collider/penguin_4.col", + "collider/penguin_5.col", + "collider/penguin_6.col", + "collider/penguin_7.col", + "collider/penguin_8.col", + "collider/penguin_9.col", + "collider/penguin_10.col" +}; + const SDL_Color penguin_colors[18] = { {0, 51, 102}, {51, 51, 51}, @@ -262,24 +295,24 @@ const int bag_0_points[31][3] = { {1, 479, 27}, {1, 465, 27}, {1, 456, 28}, - {2, 427, 43}, - {2, 413, 46}, - {2, 400, 49}, - {2, 387, 51}, - {2, 371, 59}, - {2, 355, 66}, - {2, 338, 73}, - {2, 322, 88}, - {2, 305, 102}, - {2, 288, 117}, - {2, 274, 139}, - {2, 259, 161}, - {2, 245, 183}, - {2, 234, 211}, - {2, 223, 239}, - {2, 212, 268}, - {2, 204, 300}, - {2, 196, 333}, + {2, 427, 86}, + {2, 413, 89}, + {2, 401, 93}, + {2, 388, 97}, + {2, 371, 103}, + {2, 355, 110}, + {2, 340, 119}, + {2, 322, 131}, + {2, 305, 146}, + {2, 290, 161}, + {2, 273, 181}, + {2, 259, 203}, + {2, 246, 226}, + {2, 233, 254}, + {2, 223, 282}, + {2, 214, 311}, + {2, 205, 343}, + {2, 196, 375}, {3, 165, 408} }; @@ -390,6 +423,7 @@ SDL_Surface * screen; SDL_Surface * images[NUM_IMAGES]; SDL_Surface * penguin_images[NUM_PENGUIN_FRAMES]; int use_sound; +Collider *colliders[NUM_COLLIDERS]; int color_penguin = 0; @@ -535,7 +569,7 @@ int game_loop (void) { int bags = 0; int penguin_frame = 0; - int i, j; + int i, j, k; int level, activator; int bag_activity = 15; @@ -619,6 +653,12 @@ int game_loop (void) { } } + if (bags >= 0 && bags <= 6) { + k = COLLIDER_PENGUIN_1 + bags; + } else { + k = COLLIDER_PENGUIN_7; + } + /* Procesar las bolsas */ thisbag = first_bag; while (thisbag != NULL) { @@ -628,7 +668,23 @@ int game_loop (void) { j = thisbag->frame - thisbag->throw_length; - /* Calcular aquí la colisión contra el pingüino */ + if (j < 0) { + /* Calcular aquí la colisión contra el pingüino */ + i = collider_hittest (colliders[COLLIDER_BAG_3], thisbag->bag_points[thisbag->frame][1], thisbag->bag_points[thisbag->frame][2], colliders[k], penguinx - 120, 251); + + if (i == SDL_TRUE) { + bags++; + k = COLLIDER_PENGUIN_1 + bags; + + /* Reproducir el sonido de "Agarrar bolsa" */ + + /* Sumar score = score + (nivel * 2); */ + airbone--; + delete_bag (thisbag); + thisbag = nextbag; + continue; + } + } if (j == 0) { /* Eliminar del airbone */ @@ -736,6 +792,7 @@ void setup (void) { int g; char buffer_file[8192]; char *systemdata_path = get_systemdata_path (); + Collider *c; /* Inicializar el Video SDL */ if (SDL_Init(SDL_INIT_VIDEO) < 0) { @@ -807,6 +864,21 @@ void setup (void) { setup_and_color_penguin (); + /* Cargar los colliders de los pingüinos */ + for (g = 0; g < NUM_COLLIDERS; g++) { + sprintf (buffer_file, "%s%s", systemdata_path, collider_names[g]); + c = collider_new_from_file (buffer_file); + + if (c == NULL) { + fprintf (stderr, + _("Failed to load data file:\n" + "%s\n"), buffer_file); + SDL_Quit (); + exit (1); + } + colliders[g] = c; + } + if (use_sound) { /*for (g = 0; g < NUM_SOUNDS; g++) { sprintf (buffer_file, "%s%s", systemdata_path, sound_names[g]); diff --git a/src/collider.c b/src/collider.c new file mode 100644 index 0000000..9d09993 --- /dev/null +++ b/src/collider.c @@ -0,0 +1,192 @@ +/* + * collider.c + * This file is part of Bean Counters Classic + * + * Copyright (C) 2018 - Félix Arreola Rodríguez + * + * Bean Counters Classic is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Bean Counters Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Bean Counters Classic; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include + +#include + +#include +#include +#include + +#include "collider.h" +#include "sdl2_rect.h" + +struct _Collider { + Uint32 offset_x, offset_y; + Uint32 size_w, size_h; + + Uint32 pitch; + + Uint32 *pixels; +}; + +Uint32 collider_extract_block (Collider *c, int y, int x, int size) { + int bit_pos; + int align; + Uint32 res; + + bit_pos = c->pitch * y + (x / 32); + align = 32 - (x % 32); + + if (align == 32) { + res = c->pixels[bit_pos]; + } else { + res = c->pixels[bit_pos] << (32 - align); + res = res | (c->pixels[bit_pos + 1] >> align); + } + + if (size < 32) { + /* Quitar los bits sobrantes */ + res = res ^ (res & ((1 << (32 - size)) - 1)); + } + + return res; +} + +Collider * collider_new_from_file (const char *filename) { + int fd; + Collider *new; + Uint32 temp; + Uint32 four_int[4]; + int res, g, h; + int map_size; + + fd = open (filename, O_RDONLY); + + if (fd < 0) { + return NULL; + } + + new = (Collider *) malloc (sizeof (Collider)); + + if (new == NULL) goto bad_load; + + /* Empezar a leer los bytes iniciales para saber cuánto reservar en pixeles */ + res = read (fd, &temp, sizeof (temp)); + if (res < 0) goto bad_load_and_free; + + /* Versión incorrecta */ + if (temp != 1) goto bad_load_and_free; + + /* Consumir el byte extra de alineación de bytes */ + res = read (fd, &temp, sizeof (temp)); + if (res < 0) goto bad_load_and_free; + + res = read (fd, four_int, 4 * sizeof (Uint32)); + if (res < 4 * sizeof (Uint32)) goto bad_load_and_free; + + new->offset_x = four_int[0]; + new->offset_y = four_int[1]; + new->size_w = four_int[2]; + new->size_h = four_int[3]; + + if (new->size_w % 32 != 0) { + new->pitch = (new->size_w / 32) + 2; + } else { + new->pitch = (new->size_w / 32) + 1; + } + map_size = new->pitch * new->size_h; + + new->pixels = (Uint32 *) malloc (sizeof (Uint32) * map_size); + if (new->pixels == NULL) goto bad_load_and_free; + + memset (new->pixels, 0, sizeof (Uint32) * map_size); + + for (h = 0; h < new->size_h; h++) { + for (g = 0; g < new->pitch; g++) { + res = read (fd, &temp, sizeof (Uint32)); + if (res < 0) goto bad_load_and_free_pixels; + + new->pixels[(h * new->pitch) + g] = temp; + } + } + + close (fd); + + return new; + +bad_load_and_free_pixels: + free (new->pixels); +bad_load_and_free: + free (new); +bad_load: + close (fd); + + return NULL; +} + +int collider_hittest (Collider *a, int x1, int y1, Collider *b, int x2, int y2) { + SDL_Rect rect_left, rect_right, result; + int first = SDL_FALSE; + + int g, h; + int s, x; + int offset_a_x, offset_a_y; + int offset_b_x, offset_b_y; + + rect_left.x = x1 + a->offset_x; // Sumar los offsets del collider + rect_left.y = y1 + a->offset_y; + rect_left.w = a->size_w; + rect_left.h = a->size_h; + + rect_right.x = x2 + b->offset_x; + rect_right.y = y2 + b->offset_y; + rect_right.w = b->size_w; + rect_right.h = b->size_h; + + first = SDL_IntersectRect (&rect_left, &rect_right, &result); + + if (first == SDL_FALSE) { + /* Ni siquiera cercas */ + //printf ("Ni siquiera cercas de colision\n"); + return 0; + } + + offset_a_y = result.y - rect_left.y; + offset_a_x = result.x - rect_left.x; + offset_b_y = result.y - rect_right.y; + offset_b_x = result.x - rect_right.x; + + Uint32 block_a, block_b; + + for (h = result.h; h >= 0; h++) { + s = result.w; + x = 0; + while (s > 0) { + block_a = collider_extract_block (a, h + offset_a_y, x + offset_a_x, s); + block_b = collider_extract_block (b, h + offset_b_y, x + offset_b_x, s); + + block_a = block_a & block_b; + + if (block_a != 0) { + return 1; + } + + x = x + 32; + s = s - 32; + } + } + + return 0; +} + diff --git a/src/collider.h b/src/collider.h new file mode 100644 index 0000000..612fadc --- /dev/null +++ b/src/collider.h @@ -0,0 +1,31 @@ +/* + * collider.h + * This file is part of Bean Counters Classic + * + * Copyright (C) 2018 - Félix Arreola Rodríguez + * + * Bean Counters Classic is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Bean Counters Classic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Bean Counters Classic; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __COLLIDER_H__ +#define __COLLIDER_H__ + +typedef struct _Collider Collider; + +Collider * collider_new_from_file (const char *filename); +int collider_hittest (Collider *a, int x1, int y1, Collider *b, int x2, int y2); + +#endif diff --git a/src/sdl2_rect.c b/src/sdl2_rect.c new file mode 100644 index 0000000..f75c21a --- /dev/null +++ b/src/sdl2_rect.c @@ -0,0 +1,188 @@ +/* + * sdl2_rect.c + * This file is part of Find Four + * + * Copyright (C) 2017 - Félix Arreola Rodríguez + * + * Find Four is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Find Four is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Find Four; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include + +#include "sdl2_rect.h" + +/* Funciones */ +int SDL_RectEmpty(const SDL_Rect *r) { + return ((!r) || (r->w <= 0) || (r->h <= 0)) ? SDL_TRUE : SDL_FALSE; +} + +int SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B) { + int Amin, Amax, Bmin, Bmax; + + if (!A) { + return SDL_FALSE; + } + + if (!B) { + return SDL_FALSE; + } + + /* Special cases for empty rects */ + if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) { + return SDL_FALSE; + } + + /* Horizontal intersection */ + Amin = A->x; + Amax = Amin + A->w; + Bmin = B->x; + Bmax = Bmin + B->w; + if (Bmin > Amin) + Amin = Bmin; + if (Bmax < Amax) + Amax = Bmax; + if (Amax <= Amin) + return SDL_FALSE; + + /* Vertical intersection */ + Amin = A->y; + Amax = Amin + A->h; + Bmin = B->y; + Bmax = Bmin + B->h; + if (Bmin > Amin) + Amin = Bmin; + if (Bmax < Amax) + Amax = Bmax; + if (Amax <= Amin) + return SDL_FALSE; + + return SDL_TRUE; +} + +int SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result) { + int Amin, Amax, Bmin, Bmax; + + if (!A) { + return SDL_FALSE; + } + + if (!B) { + return SDL_FALSE; + } + + if (!result) { + return SDL_FALSE; + } + + /* Special cases for empty rects */ + if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) { + result->w = 0; + result->h = 0; + return SDL_FALSE; + } + + /* Horizontal intersection */ + Amin = A->x; + Amax = Amin + A->w; + Bmin = B->x; + Bmax = Bmin + B->w; + if (Bmin > Amin) + Amin = Bmin; + result->x = Amin; + if (Bmax < Amax) + Amax = Bmax; + if (Amax - Amin < 0) { + result->w = 0; + } else { + result->w = Amax - Amin; + } + + /* Vertical intersection */ + Amin = A->y; + Amax = Amin + A->h; + Bmin = B->y; + Bmax = Bmin + B->h; + if (Bmin > Amin) + Amin = Bmin; + result->y = Amin; + if (Bmax < Amax) + Amax = Bmax; + if (Amax - Amin < 0) { + result->h = 0; + } else { + result->h = Amax - Amin; + } + + return !SDL_RectEmpty(result); +} + +void SDL_UnionRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result) { + int Amin, Amax, Bmin, Bmax; + + if (!A) { + return; + } + + if (!B) { + return; + } + + if (!result) { + return; + } + + /* Special cases for empty Rects */ + if (SDL_RectEmpty(A)) { + if (SDL_RectEmpty(B)) { + /* A and B empty */ + return; + } else { + /* A empty, B not empty */ + *result = *B; + return; + } + } else { + if (SDL_RectEmpty(B)) { + /* A not empty, B empty */ + *result = *A; + return; + } + } + + /* Horizontal union */ + Amin = A->x; + Amax = Amin + A->w; + Bmin = B->x; + Bmax = Bmin + B->w; + if (Bmin < Amin) + Amin = Bmin; + result->x = Amin; + if (Bmax > Amax) + Amax = Bmax; + result->w = Amax - Amin; + + /* Vertical union */ + Amin = A->y; + Amax = Amin + A->h; + Bmin = B->y; + Bmax = Bmin + B->h; + if (Bmin < Amin) + Amin = Bmin; + result->y = Amin; + if (Bmax > Amax) + Amax = Bmax; + result->h = Amax - Amin; +} diff --git a/src/sdl2_rect.h b/src/sdl2_rect.h new file mode 100644 index 0000000..d6d1967 --- /dev/null +++ b/src/sdl2_rect.h @@ -0,0 +1,41 @@ +/* + * sdl2_rect.h + * This file is part of Find Four + * + * Copyright (C) 2017 - Félix Arreola Rodríguez + * + * Find Four is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Find Four is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Find Four; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __SDL2_RECT_H__ +#define __SDL2_RECT_H__ + +#include + +#ifndef SDL_FALSE +#define SDL_FALSE 0 +#endif + +#ifndef SDL_TRUE +#define SDL_TRUE -1 +#endif + +int SDL_RectEmpty(const SDL_Rect *r); +int SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B); +int SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result); +void SDL_UnionRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result); + +#endif /* __SDL2_RECT_H__ */