INCLUDE "hardware.inc" INCLUDE "input.inc" INCLUDE "oam.inc" INCLUDE "util.inc" Section "Player Data", WRAM0 playerWorldX: dw playerWorldY: dw ; player data PLAYER_X:: db PLAYER_Y:: db PLAYER_DIR:: db PLAYER_JUMPING:: db PLAYER_VY:: dw PLAYER_OLD_Y: db Section "Player Code", ROM0 spriteData: INCBIN "png/sprite/player.2bpp" DEF SPRITE_OAM_IDX EQU 0 DEF SPRITE_IDX EQU 32 ; tile index, rename later DEF SPRITE_WIDTH EQU 2 DEF SPRITE_HEIGHT EQU 2 DEF GRAVITY EQU (0 << 8) | 8 DEF INIT_VY EQU (2 << 8) | 40 Player_Init:: ; Clear player data ld hl, PLAYER_X ld [hl], 0 inc hl ld [hl], 144-32 inc hl ld [hl], 0 inc hl ld [hl], 0 inc hl ld [hl], 0 inc hl ld [hl], 0 ; Copy sprite to VRAM ld bc, _VRAM8000 + SPRITE_IDX * 16 ld hl, spriteData ld d, 16 * (SPRITE_WIDTH * SPRITE_HEIGHT) call memcpy ; Initialize OAM entries with player state call update_oam ret Player_Update:: ld hl, keys ld b, [hl] ; check for jump ld a, b and BTN_UP jr z, .update_jump ; initialize jump state if not already jumping ld hl, PLAYER_JUMPING ld a, [hl] or a jr nz, .update_jump ld [hl], 1 ld hl, PLAYER_VY ld [hl], HIGH(INIT_VY) inc hl ld [hl], LOW(INIT_VY) .update_jump: ld hl, PLAYER_JUMPING ld a, [hl] or a jr z, .right ; load y velocity into bc ld hl, PLAYER_VY ld b, [hl] inc hl ld c, [hl] ; adjust velocity by gravity ld a, c sub LOW(GRAVITY) ld c, a ld a, b sbc HIGH(GRAVITY) ld b, a ld hl, PLAYER_VY STORE16 bc ; old_y = y ld hl, PLAYER_Y ld a, [hl] ld hl, PLAYER_OLD_Y ld [hl], a ; y -= floor(vy) ld hl, PLAYER_Y ld a, [hl] sub b ld [hl], a ; roll back jump if there was a collision call player_bg_collides jr nz, .update_jump_oam ld hl, PLAYER_OLD_Y ld a, [hl] ld hl, PLAYER_Y ld b, [hl] ld hl, PLAYER_VY ld [hl], 0 ; if colliding below, stop jump state cp b jr nc, .right ld hl, PLAYER_JUMPING ld [hl], 0 .update_jump_oam: call update_oam ; check for move right .right: ld hl, keys ld a, [hl] and BTN_RIGHT jr z, .left ; check for right boundary ld hl, PLAYER_X ld a, [hl] add 16 cp SCRN_X jr nc, .left inc [hl] inc [hl] call player_bg_collides jr z, .right_rollback ld hl, PLAYER_DIR ld [hl], 0 call update_oam ret .right_rollback: ld hl, PLAYER_X dec [hl] dec [hl] ret .left: ; check for left button ld hl, keys ld a, [hl] and BTN_LEFT ret z ; check for left boundary ld hl, PLAYER_X ld a, [hl] or a ret z dec [hl] dec [hl] call player_bg_collides jr z, .left_rollback ld hl, PLAYER_DIR ld [hl], $ff call update_oam ret .left_rollback: ld hl, PLAYER_X dec [hl] inc [hl] ret ; Update player metasprite with positional data update_oam: ld hl, PLAYER_DIR ld a, [hl-] ; dir (0 = right , $ff = left) and OAMF_XFLIP ld c, a ld a, [hl-] ; y add 16 ld d, a ld a, [hl] ; x add 8 ld b, a ld a, d ld_OAM_y hl, SPRITE_OAM_IDX ; top left sprite ld [hli], a ld [hl], b inc hl ld [hl], SPRITE_IDX inc hl ld [hl], c inc hl ; top right ld d, a ld a, b add 8 ld b, a ld a, d ld [hli], a ld [hl], b inc hl ld [hl], SPRITE_IDX + 1 inc hl ld [hl], c inc hl ; bottom left add 8 ld d, a ld a, b sub 8 ld b, a ld a, d ld [hli], a ld [hl], b inc hl ld [hl], SPRITE_IDX + 2 inc hl ld [hl], c inc hl ; bottom right ld d, a ld a, b add 8 ld b, a ld a, d ld [hli], a ld [hl], b inc hl ld [hl], SPRITE_IDX + 3 inc hl ld [hl], c ; flip tile indices if necessary ld a, c or c jr z, .done ld_OAM_tile hl, SPRITE_OAM_IDX ld [hl], SPRITE_IDX + 1 ld_OAM_tile hl, SPRITE_OAM_IDX + 1 ld [hl], SPRITE_IDX ld_OAM_tile hl, SPRITE_OAM_IDX + 2 ld [hl], SPRITE_IDX + 3 ld_OAM_tile hl, SPRITE_OAM_IDX + 3 ld [hl], SPRITE_IDX + 2 .done: ret