diff --git a/assets/player-stand.png b/assets/player-stand.png new file mode 100644 index 0000000..fc16c4f Binary files /dev/null and b/assets/player-stand.png differ diff --git a/src/actor.c b/src/actor.c index 4e51cfa..8db4145 100644 --- a/src/actor.c +++ b/src/actor.c @@ -2,6 +2,7 @@ #include +#include "player.h" #include "sdk/oam.h" #include "util.h" @@ -10,6 +11,7 @@ #define NUM_OAM_ENTRIES 40 #define TILE_WIDTH 8 #define FRAMES_PER_ANIM_FRAME 20 +#define PLAYER_ACTOR_IDX 0 static actor_anim_state_t ANIM_TOTAL_FRAMES[] = {2}; @@ -20,6 +22,16 @@ static actor_t all_actors[MAX_ACTORS]; static uint8_t actor_load_mob_anim_data(uint8_t mob_id); +actor_t *PLAYER_ACTOR = &all_actors[PLAYER_ACTOR_IDX]; + +void actor_init(void) { + actor_reset(); + + PLAYER_ACTOR->active = 1; + PLAYER_ACTOR->x = PLAYER.x; + PLAYER_ACTOR->y = PLAYER.y; +} + void actor_reset(void) { for (uint8_t i = 0; i < ARRSIZE(mob_ids); ++i) { mob_ids[i] = 0xff; diff --git a/src/actor.h b/src/actor.h index e9f24f9..4d89446 100644 --- a/src/actor.h +++ b/src/actor.h @@ -5,6 +5,11 @@ #include "mob.h" +typedef enum { + DIR_LEFT, + DIR_RIGHT, +} actor_dir_t; + typedef enum { ANIM_STAND, ANIM_WALK, @@ -16,7 +21,6 @@ typedef enum { typedef struct { uint8_t active; - uint8_t dirty; uint8_t mob_anim_idx; actor_anim_state_t anim; uint8_t frame_idx; @@ -65,4 +69,6 @@ void actor_update(void); */ void actor_flush_oam(void); +extern actor_t *PLAYER_ACTOR; + #endif diff --git a/src/collision.c b/src/collision.c new file mode 100644 index 0000000..03dc1d8 --- /dev/null +++ b/src/collision.c @@ -0,0 +1,45 @@ +#include "game.h" +#include "map.h" +#include "player.h" + +typedef enum { + COLLF_WALK = (1 << 0), + COLLF_LADDER = (1 << 1), + COLLF_PORTAL = (1 << 2), +} coll_state_t; + +uint8_t can_move_to(uint8_t x, uint8_t y) { + const uint8_t coll = ((uint8_t*)MAP.collision_ptr)[y * MAP.map_width + x]; + return coll & COLLF_WALK; +} + +uint8_t get_tile_coord(uint8_t pixel_coord) { + uint8_t offset = 0; + if (pixel_coord & 0x7) { + offset = 8; + } + return (pixel_coord + offset) >> 3; +} + +uint8_t player_bg_collides(void) { + const int8_t map_x = PLAYER.x / 8 + MAP.camera_x; + if (map_x < 0 || map_x >= MAP.map_width) { + return 1; + } + + const int8_t map_y = PLAYER.y / 8 + MAP.camera_y; + if (map_y < 0 || map_y >= MAP.map_height) { + return 1; + } + + return !(can_move_to(map_x, map_y) && can_move_to(map_x + 1, map_y) && + can_move_to(map_x, map_y + 1) && + can_move_to(map_x + 1, map_y + 1)); +} + +uint8_t player_in_air(void) { + const uint8_t x = get_tile_coord(PLAYER.x) + MAP.camera_x; + const uint8_t y = get_tile_coord(PLAYER.y) + MAP.camera_y; + + return can_move_to(x, y + 2) && can_move_to(x + 1, y + 2); +} diff --git a/src/game.h b/src/game.h index 1e5d721..f159ba5 100644 --- a/src/game.h +++ b/src/game.h @@ -38,7 +38,9 @@ (ALLOC_SIZE_FONT + ALLOC_SIZE_PLAYER + ALLOC_SIZE_BACKGROUND + \ ALLOC_SIZE_ITEMS) -#define TILE_SIZE 16 //!< Size of 1 tile in bytes +#define TILE_WIDTH 8 //!< Width of 1 tile in pixels +#define TILE_HEIGHT 8 //!< Height of 1 tile in pixels +#define TILE_SIZE 16 //!< Size of 1 tile in bytes #define VRAM_TILE_PTR(idx) \ ((void*)(_VRAM + \ (idx)*TILE_SIZE)) //!< Compute VRAM pointer for tile section @@ -74,4 +76,8 @@ void interrupts_disable(void) __preserves_regs(a, b, c, d, e, h, l); #define lcd_disable() lcd_off() #define lcd_enable() rLCDC = LCDC_ON | LCDC_OBJON | LCDC_BGON | LCDC_BG8000 +uint8_t player_bg_collides(void); + +uint8_t player_in_air(void); + #endif diff --git a/src/level.c b/src/level.c index a3cfa08..9786cb1 100644 --- a/src/level.c +++ b/src/level.c @@ -1,6 +1,7 @@ #include "game.h" #include "intro.h" #include "map.h" +#include "player.h" #include "sdk/hardware.h" #include "sdk/joypad.h" #include "sdk/video.h" @@ -13,6 +14,8 @@ void level(void) { while (1) { joypad_update(); + player_update(); + actor_flush_oam(); HALT(); rIF = 0; diff --git a/src/player.c b/src/player.c index ad7746f..4769eb2 100644 --- a/src/player.c +++ b/src/player.c @@ -1,3 +1,55 @@ #include "player.h" +#include "actor.h" +#include "game.h" +#include "sdk/joypad.h" + +#define PLAYER_SPEED 2 +#define GRAVITY 0x002e //!< 0.18 +#define PLAYER_INIT_JUMP_VY 0x0399 //!< 3.6 +#define PLAYER_INIT_FALL_VY 0xff1a //!< -1.1015625 +#define MAX_VY 0xf900 //!< -7.0 + player_t PLAYER; + +void player_update(void) { + if ((joypad_pressed & PAD_UP) && PLAYER.state != PLAYER_STATE_JUMP) { + PLAYER.state = PLAYER_STATE_JUMP; + PLAYER.vy = PLAYER_INIT_JUMP_VY; + } + + if (PLAYER.state == PLAYER_STATE_JUMP) { + PLAYER.vy -= GRAVITY; + PLAYER.y -= PLAYER.vy; + + if (player_bg_collides()) { + PLAYER.y += PLAYER.vy; + if (PLAYER.vy & (1 << 15)) { + PLAYER.state = PLAYER_STATE_WALK; + } + PLAYER.vy = 0; + } + } + + if ((joypad_state & PAD_RIGHT) && PLAYER.x + TILE_WIDTH * 2 > SCRN_X) { + PLAYER.dir = DIR_RIGHT; + PLAYER.x += PLAYER_SPEED; + if (player_bg_collides()) { + PLAYER.x -= PLAYER_SPEED; + } + } else if ((joypad_state & PAD_LEFT) && PLAYER.x > 0) { + PLAYER.dir = DIR_LEFT; + PLAYER.x -= PLAYER_SPEED; + if (player_bg_collides()) { + PLAYER.x += PLAYER_SPEED; + } + } + + if (player_in_air() && PLAYER.state != PLAYER_STATE_JUMP) { + PLAYER.state = PLAYER_STATE_JUMP; + PLAYER.vy = PLAYER_INIT_FALL_VY; + } + + PLAYER_ACTOR->x = PLAYER.x; + PLAYER_ACTOR->y = PLAYER.y; +} diff --git a/src/player.h b/src/player.h index 76ba0bf..1a96e94 100644 --- a/src/player.h +++ b/src/player.h @@ -5,6 +5,12 @@ #define PLAYER_INV_SIZE 32 +typedef enum { + PLAYER_STATE_STAND, + PLAYER_STATE_WALK, + PLAYER_STATE_JUMP, +} player_state_t; + typedef struct { uint8_t x; uint16_t y; @@ -16,4 +22,6 @@ typedef struct { extern player_t PLAYER; +void player_update(void); + #endif