diff --git a/makefile b/makefile index f09c752..ad64f9c 100644 --- a/makefile +++ b/makefile @@ -17,7 +17,7 @@ tiles: @$(MAKE) -C src/tiles --no-print-directory SHELL = bash -IMAGE_NAMES = {pl,en}_{base,turret}_{0..8} +IMAGE_NAMES = {{pl,en}_{base,turret},shell}_{0..8} CONVIMG_INPUT = $(shell echo src/gfx/trimmed/$(IMAGE_NAMES).png) src/gfx/tileset.png CONVIMG_OUTPUT = $(shell echo src/gfx/$(IMAGE_NAMES).{c,h}) src/gfx/tileset.c src/gfx/tileset.h src/gfx/palette.c src/gfx/palette.h src/gfx/gfx.h BLENDER_OUTPUT = $(shell echo src/gfx/rendered/$(IMAGE_NAMES).png) @@ -38,7 +38,7 @@ src/gfx/trimmed/%.png src/gfx/offsets/%.h: src/gfx/rendered/%.png src/gfx/offsets/offsets.h: $(OFFSET_FILES) echo \#ifndef H_OFFSETS > src/gfx/offsets/offsets.h echo \#define H_OFFSETS >> src/gfx/offsets/offsets.h - for CURRENT_TYPE in {pl,en}_{base,turret}_{0..8}; do \ + for CURRENT_TYPE in $(IMAGE_NAMES); do \ echo \#include \"$$CURRENT_TYPE.h\" ; \ done >> src/gfx/offsets/offsets.h echo \#endif >> src/gfx/offsets/offsets.h diff --git a/src/collision.c b/src/collision.c index 05989bf..81f4318 100644 --- a/src/collision.c +++ b/src/collision.c @@ -17,11 +17,11 @@ #undef NDEBUG #include -uint24_t centerX(physicsBody_t* p) { +uint24_t centerX(const physicsBody_t *p) { return p->position_x + p->width / 2; } -uint24_t centerY(physicsBody_t* p) { +uint24_t centerY(const physicsBody_t *p) { return p->position_y + p->height / 2; } diff --git a/src/collision.h b/src/collision.h index eb34e41..127151c 100644 --- a/src/collision.h +++ b/src/collision.h @@ -46,8 +46,8 @@ typedef struct { uint32_t updateTime; } physicsBody_t; -uint24_t centerX(physicsBody_t* p); //Get the center coords of a AABB -uint24_t centerY(physicsBody_t* p); +uint24_t centerX(const physicsBody_t *p); //Get the center coords of a AABB +uint24_t centerY(const physicsBody_t *p); //Determine if two bounding boxes are intersecting bool detectCollision(physicsBody_t* p1, physicsBody_t* p2); diff --git a/src/dynamic_sprites.c b/src/dynamic_sprites.c index 63fe80b..f6d812c 100644 --- a/src/dynamic_sprites.c +++ b/src/dynamic_sprites.c @@ -22,7 +22,15 @@ gfx_UninitedSprite(pl_turret_13, pl_turret_3_width, pl_turret_3_height); gfx_UninitedSprite(pl_turret_14, pl_turret_2_width, pl_turret_2_height); gfx_UninitedSprite(pl_turret_15, pl_turret_1_width, pl_turret_1_height); -gfx_sprite_t *tank_bases[NUM_TANK_TYPES][16] = { +gfx_UninitedSprite(shell_9, shell_7_width, shell_7_height); +gfx_UninitedSprite(shell_10, shell_6_width, shell_6_height); +gfx_UninitedSprite(shell_11, shell_5_width, shell_5_height); +gfx_UninitedSprite(shell_12, shell_4_width, shell_4_height); +gfx_UninitedSprite(shell_13, shell_3_width, shell_3_height); +gfx_UninitedSprite(shell_14, shell_2_width, shell_2_height); +gfx_UninitedSprite(shell_15, shell_1_width, shell_1_height); + +gfx_sprite_t * const tank_bases[NUM_TANK_TYPES][16] = { { pl_base_0, pl_base_1, @@ -43,7 +51,7 @@ gfx_sprite_t *tank_bases[NUM_TANK_TYPES][16] = { } }; -gfx_sprite_t *tank_turrets[NUM_TANK_TYPES][16] = { +gfx_sprite_t * const tank_turrets[NUM_TANK_TYPES][16] = { { pl_turret_0, pl_turret_1, @@ -64,7 +72,26 @@ gfx_sprite_t *tank_turrets[NUM_TANK_TYPES][16] = { } }; -const uint8_t base_x_offsets[16] = { +gfx_sprite_t * const shell_sprites[16] = { + shell_0, + shell_1, + shell_2, + shell_3, + shell_4, + shell_5, + shell_6, + shell_7, + shell_8, + (gfx_sprite_t*)shell_9_data, + (gfx_sprite_t*)shell_10_data, + (gfx_sprite_t*)shell_11_data, + (gfx_sprite_t*)shell_12_data, + (gfx_sprite_t*)shell_13_data, + (gfx_sprite_t*)shell_14_data, + (gfx_sprite_t*)shell_15_data, +}; + +const uint8_t base_x_offsets[16] = { pl_base_0_offset_x, pl_base_1_offset_x, pl_base_2_offset_x, @@ -83,7 +110,7 @@ const uint8_t base_x_offsets[16] = { tank_sprite_total_width - pl_base_1_offset_x - pl_base_1_width, }; -const uint8_t base_y_offsets[16] = { +const uint8_t base_y_offsets[16] = { pl_base_0_offset_y, pl_base_1_offset_y, pl_base_2_offset_y, @@ -102,7 +129,7 @@ const uint8_t base_y_offsets[16] = { pl_base_1_offset_y, }; -const uint8_t turret_x_offsets[16] = { +const uint8_t turret_x_offsets[16] = { pl_turret_0_offset_x, pl_turret_1_offset_x, pl_turret_2_offset_x, @@ -121,7 +148,7 @@ const uint8_t turret_x_offsets[16] = { tank_sprite_total_width - pl_turret_1_offset_x - pl_turret_1_width, }; -const uint8_t turret_y_offsets[16] = { +const uint8_t turret_y_offsets[16] = { pl_turret_0_offset_y, pl_turret_1_offset_y, pl_turret_2_offset_y, @@ -139,3 +166,41 @@ const uint8_t turret_y_offsets[16] = { pl_turret_2_offset_y, pl_turret_1_offset_y, }; + +const uint8_t shell_x_offsets[16] = { + shell_0_offset_x, + shell_1_offset_x, + shell_2_offset_x, + shell_3_offset_x, + shell_4_offset_x, + shell_5_offset_x, + shell_6_offset_x, + shell_7_offset_x, + shell_8_offset_x, + tank_sprite_total_width - shell_7_offset_x - shell_7_width, + tank_sprite_total_width - shell_6_offset_x - shell_6_width, + tank_sprite_total_width - shell_5_offset_x - shell_5_width, + tank_sprite_total_width - shell_4_offset_x - shell_4_width, + tank_sprite_total_width - shell_3_offset_x - shell_3_width, + tank_sprite_total_width - shell_2_offset_x - shell_2_width, + tank_sprite_total_width - shell_1_offset_x - shell_1_width, +}; + +const uint8_t shell_y_offsets[16] = { + shell_0_offset_y, + shell_1_offset_y, + shell_2_offset_y, + shell_3_offset_y, + shell_4_offset_y, + shell_5_offset_y, + shell_6_offset_y, + shell_7_offset_y, + shell_8_offset_y, + shell_7_offset_y, + shell_6_offset_y, + shell_5_offset_y, + shell_4_offset_y, + shell_3_offset_y, + shell_2_offset_y, + shell_1_offset_y, +}; diff --git a/src/dynamic_sprites.h b/src/dynamic_sprites.h index 4dda8c4..78472a9 100644 --- a/src/dynamic_sprites.h +++ b/src/dynamic_sprites.h @@ -1,15 +1,20 @@ #ifndef TANKS_DYNAMIC_SPRITES_H #define TANKS_DYNAMIC_SPRITES_H -extern gfx_sprite_t *tank_bases[NUM_TANK_TYPES][16]; -extern gfx_sprite_t *tank_turrets[NUM_TANK_TYPES][16]; +extern gfx_sprite_t * tank_bases[NUM_TANK_TYPES][16]; +extern gfx_sprite_t * tank_turrets[NUM_TANK_TYPES][16]; -gfx_sprite_t * const enemy_bases_unconv[9]; -gfx_sprite_t * const enemy_turrets_unconv[9]; +extern gfx_sprite_t * shell_sprites[16]; + +extern gfx_sprite_t * const enemy_bases_unconv[9]; +extern gfx_sprite_t * const enemy_turrets_unconv[9]; extern const uint8_t base_x_offsets[16]; extern const uint8_t base_y_offsets[16]; extern const uint8_t turret_x_offsets[16]; extern const uint8_t turret_y_offsets[16]; +extern const uint8_t shell_x_offsets[16]; +extern const uint8_t shell_y_offsets[16]; + #endif //TANKS_DYNAMIC_SPRITES_H diff --git a/src/gfx/convimg.yaml b/src/gfx/convimg.yaml index abfaf64..43c8395 100644 --- a/src/gfx/convimg.yaml +++ b/src/gfx/convimg.yaml @@ -107,6 +107,7 @@ converts: - tileset.png images: - trimmed/pl_*.png + - trimmed/shell_*.png - name: enemy palette: enemy_palette images: diff --git a/src/graphics.c b/src/graphics.c index e3de12c..2cfb5e4 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -134,6 +134,7 @@ void initGraphics(void) { for(uint8_t i = 1; i < 8; i++) { gfx_FlipSpriteY(tank_bases[PLAYER][i], tank_bases[PLAYER][16 - i]); gfx_FlipSpriteY(tank_turrets[PLAYER][i], tank_turrets[PLAYER][16 - i]); + gfx_FlipSpriteY(shell_sprites[i], shell_sprites[16 - i]); } } @@ -319,45 +320,53 @@ void draw_aim_dots(void) { profiler_end(aim_indicator); } +void render_obscured_object(gfx_sprite_t **sprites, const uint8_t *offsets_x, const uint8_t *offsets_y, const physicsBody_t *phys, uint8_t rotation) { + uint24_t base_x = SCREEN_X(centerX(phys)) - SPRITE_OFFSET_X; + uint8_t base_y = SCREEN_Y(centerY(phys)) - SPRITE_OFFSET_Y; + uint8_t tile_x, tile_y; + uint8_t end_x = screen_to_tm_x(base_x + SPRITE_SIZE_X); + uint8_t end_y = screen_to_tm_y(base_y + SPRITE_SIZE_Y); + uint8_t tank_y = ptToYTile(phys->position_y + phys->height - 1); // -1 is to round down if exactly on the edge + + pdraw_TransparentSprite_NoClip(sprites[rotation], + base_x + offsets_x[rotation], + base_y + offsets_y[rotation]); + + // todo: make this next part use offsets + for(tile_x = screen_to_tm_x(base_x); tile_x <= end_x; tile_x++) { + for(tile_y = screen_to_tm_y(base_y); tile_y <= end_y; tile_y++) { + int8_t world_tile_y = depthmap[tile_y][tile_x]; + if(world_tile_y >= tank_y && tilemap[tile_y][tile_x] != TS_NONE) { + redraw_tile(tile_x, tile_y); + } + } + } +} + +void render_shell(shell_t *shell) { + if(shell->alive) { + uint8_t sprite = shell->direction; + render_obscured_object(shell_sprites, shell_x_offsets, shell_y_offsets, &shell->phys, sprite); + } +} + void render_tank(tank_t *tank) { int j; if(tank->alive) { - uint24_t base_x = SCREEN_X(tank->phys.position_x) - TANK_SPRITE_OFFSET_X; - uint8_t base_y = SCREEN_Y(tank->phys.position_y) - TANK_SPRITE_OFFSET_Y; uint8_t base_sprite = (((uint8_t)-((tank->tread_rot >> 16) - 64)) >> 3) & 0xF; uint8_t turret_sprite = ((uint8_t)-((tank->barrel_rot >> 16) - 64)) >> 4; - uint8_t tile_x, tile_y; - uint8_t end_x = screen_to_tm_x(base_x + TANK_SPRITE_SIZE_X); - uint8_t end_y = screen_to_tm_y(base_y + TANK_SPRITE_SIZE_Y); - uint8_t tank_y = ptToYTile(tank->phys.position_y + TANK_SIZE - 1); // -1 is to round down if exactly on the edge - - pdraw_TransparentSprite_NoClip(tank_bases[tank->type][base_sprite], - base_x + base_x_offsets[base_sprite], - base_y + base_y_offsets[base_sprite]); - pdraw_TransparentSprite_NoClip(tank_turrets[tank->type][turret_sprite], - base_x + turret_x_offsets[turret_sprite], - base_y + turret_y_offsets[turret_sprite]); - - // todo: make this next part use offsets - // todo: figure out why the turret is visible through blocks in some cases - for(tile_x = screen_to_tm_x(base_x); tile_x <= end_x; tile_x++) { - for(tile_y = screen_to_tm_y(base_y); tile_y <= end_y; tile_y++) { - int8_t world_tile_y = depthmap[tile_y][tile_x]; - if(world_tile_y >= tank_y && tilemap[tile_y][tile_x] != TS_NONE) { - redraw_tile(tile_x, tile_y); - } - } - } + render_obscured_object(tank_bases[tank->type], base_x_offsets, base_y_offsets, &tank->phys, base_sprite); + render_obscured_object(tank_turrets[tank->type], turret_x_offsets, turret_y_offsets, &tank->phys, turret_sprite); + + // todo: figure out why the turret is visible through blocks in some cases } //draw shell hitboxes until I can get sprites for(j = max_shells[tank->type] - 1; j >= 0; j--) { shell_t* shell = &tank->shells[j]; - if(!(shell->alive)) continue; - gfx_SetColor(COL_BLACK); - renderPhysicsBody(&shell->phys); + if(shell->alive) render_shell(shell); } //draw mine hitboxes for(j = max_mines[tank->type] - 1; j >= 0; j--) { diff --git a/src/graphics.h b/src/graphics.h index 0ca085b..7ab9d0a 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -115,10 +115,10 @@ typedef struct { #define SCREEN_X(x) (SCREEN_DELTA_X(x) + MAP_OFFSET_X) #define SCREEN_Y(y) (SCREEN_DELTA_Y(y) + MAP_OFFSET_Y) -#define TANK_SPRITE_OFFSET_X 11 -#define TANK_SPRITE_OFFSET_Y 16 -#define TANK_SPRITE_SIZE_X 40 -#define TANK_SPRITE_SIZE_Y 30 +#define SPRITE_OFFSET_X 20 +#define SPRITE_OFFSET_Y 22 +#define SPRITE_SIZE_X 40 +#define SPRITE_SIZE_Y 30 // todo: get an actual value? #define AIM_INDICATOR_DOT_DISTANCE (2 * TILE_SIZE) diff --git a/src/shell.c b/src/shell.c index d12f5a9..b266274 100644 --- a/src/shell.c +++ b/src/shell.c @@ -62,12 +62,19 @@ bool shellRicochet(shell_t* shell, direction_t dir) { //shell_t is still alive if(dir & UP || dir & DOWN) { shell->phys.velocity_y *= -1; + updateShellDirection(shell); shell->bounces--; } if(dir & LEFT || dir & RIGHT) { shell->phys.velocity_x *= -1; + updateShellDirection(shell); shell->bounces--; } return true; } + +void updateShellDirection(shell_t* shell) { + angle_t angle = fast_atan2(shell->phys.velocity_y, shell->phys.velocity_x); + shell->direction = angleToShellDirection(angle); +} diff --git a/src/shell.h b/src/shell.h index bcd05e4..34daae5 100644 --- a/src/shell.h +++ b/src/shell.h @@ -27,10 +27,16 @@ typedef struct { physicsBody_t phys; uint8_t bounces; //Number of times the shell can bounce off a wall without exploding bool left_tank_hitbox; //Whether the shell has exited the tank hitbox yet. Used to stop shells from blowing up the tank that fired them. + uint8_t direction; } shell_t; //Bounce a shell off a wall //Returns whether or not the shell is still alive bool shellRicochet(shell_t* shell, direction_t dir); +uint8_t inline angleToShellDirection(angle_t angle) { + return ((uint8_t)-((angle >> 16) - 64)) >> 4; +} +void updateShellDirection(shell_t* shell); + #endif //TANKS_SHELL_H diff --git a/src/tank.c b/src/tank.c index 6c1b2e3..a842d18 100644 --- a/src/tank.c +++ b/src/tank.c @@ -79,6 +79,7 @@ bool fireShell(tank_t* tank) { shell->phys.velocity_x = SHELL_SPEED_STANDARD * vector_x / TRIG_SCALE; shell->phys.velocity_y = SHELL_SPEED_STANDARD * vector_y / TRIG_SCALE; } + shell->direction = angleToShellDirection(tank->barrel_rot); return true; } return false; diff --git a/tank.blend b/tank.blend index 6c1a376..2b9902d 100644 Binary files a/tank.blend and b/tank.blend differ