#include #include #include #include "./vec.h" #include "./constants.h" #include "./flags.h" #include "./map.h" #define LYO 8 #define GET_TILE_INDEX_BY_COORD(x, y) ((((y) / PIXELS_PER_TILE) * 20) + ((x) / PIXELS_PER_TILE)) typedef struct Sprites { int gb_sprite_index; int frames_since_last_dash; int frames_since_last_jump; int bitmap_index_prev; int bitmap_index; int bitmap_indexes[8]; int bitmap_prop[8]; int has_diag_sprites; int has_joypad; char name[20]; int collision_offset[8][12]; UVec pos; Vec vel; Vec acc; } Sprite; void sprite_iter_frame(Sprite *sprite, Map *map, int joypad, unsigned int *fc); void sprite_draw_to_screen(Sprite *sprite); void sprite_update_bitmap(Sprite *sprite); // update a sprite for stuff that changes every frame void sprite_iter_frame(Sprite *sprite, Map *map, int joypad, unsigned int *fc) { unsigned int colx, coly; UVec original_position; // target displacement is sprite->vel but may collide, giving actual displacment if (sprite->frames_since_last_jump <= JUMP_TIMEOUT_FRAMES) sprite->frames_since_last_jump++; if (sprite->frames_since_last_dash <= DASH_TIMEOUT_FRAMES) sprite->frames_since_last_dash++; if (*fc % 2 == 0) { sprite->vel.y += GRAV_ACC; *fc = 0; } // player move left/right if ((joypad & J_RIGHT) && (sprite->vel.x < TERM_VELX)) sprite->acc.x = 1; else if ((joypad & J_LEFT) && (sprite->vel.x > -TERM_VELX)) sprite->acc.x = -1; else sprite->acc.x = -sprite->vel.x/abs(sprite->vel.x); sprite->vel.x += sprite->acc.x; // player dash if ((joypad & J_B) && (sprite->frames_since_last_dash > DASH_TIMEOUT_FRAMES)) { int frames_since_last_dash_copy = sprite->frames_since_last_dash; sprite->frames_since_last_dash = 0; if ((joypad & J_LEFT) && !(joypad & (J_UP | J_RIGHT | J_DOWN))) { sprite->vel.x = -DASH_VELL; } else if ((joypad & J_RIGHT) && !(joypad & (J_UP | J_LEFT | J_DOWN))) { sprite->vel.x = DASH_VELL; } else if ((joypad & J_UP) && !(joypad & (J_RIGHT | J_LEFT | J_DOWN))) { sprite->vel.y = -DASH_VELL; } else if ((joypad & J_DOWN) && !(joypad & (J_UP | J_LEFT | J_RIGHT))) { sprite->vel.y = DASH_VELL; } else if ((joypad & J_RIGHT) && (joypad & J_UP)) { sprite->vel.x = DASH_VELD; sprite->vel.y = -DASH_VELD; } else if ((joypad & J_LEFT) && (joypad & J_UP)) { sprite->vel.x = -DASH_VELD; sprite->vel.y = -DASH_VELD; } else if ((joypad & J_LEFT) && (joypad & J_DOWN)) { sprite->vel.x = -DASH_VELD; sprite->vel.y = DASH_VELD; } else if ((joypad & J_RIGHT) && (joypad & J_DOWN)) { sprite->vel.x = DASH_VELD; sprite->vel.y = DASH_VELD; } else { // if player doesn't hold the right buttons to dash, don't dash and set the // frames_since_last_dash counter back to what it was before sprite->frames_since_last_dash = frames_since_last_dash_copy; } } // slow down sprite in kind of realistic way // (in real life i think it's drag is proportional to sprite->vel square but not // sure if that is worth the compute yet cause everythign else is shit) if (sprite->vel.y > TERM_VELY) sprite->vel.y = TERM_VELY; if (sprite->vel.y < -TERM_VELY) sprite->vel.y += (abs(sprite->vel.y)-TERM_VELY)/TERM_VELY_DIVISOR; int *offsets = sprite->collision_offset[sprite->bitmap_index]; // jump if on platform if ((joypad & J_A) && (sprite->frames_since_last_jump > JUMP_TIMEOUT_FRAMES)) { coly = map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[0], sprite->pos.y - offsets[3]-LYO+1)]; if (!coly) coly += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[2], sprite->pos.y - offsets[3]-LYO+1)]; if(coly) { sprite->vel.y = -JUMP_VEL; sprite->frames_since_last_jump = 0; } } original_position.x = sprite->pos.x; original_position.y = sprite->pos.y; // check if following the path by the velocity will lead to a collision // if no velocity component, pretend sprite has already collided colx = sprite->vel.x == 0; coly = sprite->vel.y == 0; //for (int step = collision_check_steps; step >= 0; step--) { if(sprite->vel.y != 0){ sprite->pos.y = original_position.y + sprite->vel.y; if (sprite->vel.y < 0) { coly += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[0], sprite->pos.y - offsets[1]-LYO)]; if (!coly) coly += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[2], sprite->pos.y - offsets[1]-LYO)]; } else if (sprite->vel.y > 0) { coly += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[0], sprite->pos.y - offsets[3]-LYO)]; if (!coly) coly += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[2], sprite->pos.y - offsets[3]-LYO)]; } if (coly) sprite->pos.y = original_position.y; } if(sprite->vel.x != 0) { sprite->pos.x = original_position.x + sprite->vel.x; if (sprite->vel.x < 0) { colx += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[0], sprite->pos.y - offsets[1]-LYO)]; if(!colx) colx += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[0], sprite->pos.y - offsets[3]-LYO)]; } else if (sprite->vel.x > 0) { colx += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[2], sprite->pos.y - offsets[1]-LYO)]; if(!colx) colx += map->data[GET_TILE_INDEX_BY_COORD(sprite->pos.x - offsets[2], sprite->pos.y - offsets[3]-LYO)]; } if (colx) sprite->pos.x = original_position.x; } sprite_update_bitmap(sprite); sprite_draw_to_screen(sprite); } void sprite_update_bitmap(Sprite *sprite) { sprite->bitmap_index_prev = sprite->bitmap_index; if ((sprite->vel.y > 0) && (sprite->vel.x > 0)) sprite->bitmap_index = SI_DOWN_RIGHT; else if ((sprite->vel.y < 0) && (sprite->vel.x > 0)) sprite->bitmap_index = SI_UP_RIGHT; else if ((sprite->vel.y > 0) && (sprite->vel.x < 0)) sprite->bitmap_index = SI_DOWN_LEFT; else if ((sprite->vel.y < 0) && (sprite->vel.x < 0)) sprite->bitmap_index = SI_UP_LEFT; else if ( sprite->vel.y < 0) sprite->bitmap_index = SI_UP; else if ( sprite->vel.y > 0) sprite->bitmap_index = SI_DOWN; else if ( sprite->vel.x > 0) sprite->bitmap_index = SI_RIGHT; else if ( sprite->vel.x < 0) sprite->bitmap_index = SI_LEFT; } void sprite_draw_to_screen(Sprite *sprite) { int bmi = sprite->bitmap_index; if (sprite->bitmap_index_prev != bmi) { set_sprite_tile(sprite->gb_sprite_index, sprite->bitmap_indexes[bmi]); set_sprite_prop(sprite->gb_sprite_index, sprite->bitmap_prop[bmi]); } move_sprite(sprite->gb_sprite_index, sprite->pos.x, sprite->pos.y); }