diff --git a/png/map/intro_coll.png b/png/map/intro_coll.png index 6fac243..fdb70c8 100644 Binary files a/png/map/intro_coll.png and b/png/map/intro_coll.png differ diff --git a/scripts/generate_map.py b/scripts/generate_map.py index 29f8799..94f0b6f 100644 --- a/scripts/generate_map.py +++ b/scripts/generate_map.py @@ -16,7 +16,9 @@ def abort(msg: str) -> NoReturn: sys.exit(1) -def generate_coll_map(in_path: pathlib.Path, width: int, height: int) -> str: +def generate_coll_map( + in_path: pathlib.Path, width: int, height: int, compress: bool = False +) -> str: png = Image.open(in_path).convert("RGB") if png.width % 8 != 0 or png.height % 8 != 0: abort(f"file '{in_path}' has invalid dimensions (should be multiple of 8)") @@ -33,37 +35,35 @@ def generate_coll_map(in_path: pathlib.Path, width: int, height: int) -> str: bit = None if pixel == RED: - bit = 1 - elif pixel == GREEN: bit = 0 + elif pixel == GREEN: + bit = 1 else: abort(f"unsupported pixel in collision map: {pixel}") - bits.append(bit) - if len(bits) == 8: - byte = sum([bit << i for i, bit in enumerate(bits)]) - out_bytes.append(byte) - bits = [] + if compress: + bits.append(bit) + if len(bits) == 8: + byte = sum([bit << i for i, bit in enumerate(bits)]) + out_bytes.append(byte) + bits = [] + else: + out_bytes.append(bit) png.close() - - lines = [] - for line_no in range(0, len(out_bytes), 16): - line = out_bytes[line_no : line_no + 16] - lines.append(" DB " + ", ".join(["$%02X" % b for b in line])) - - return "\n".join(lines) + return format_bytes(out_bytes, width=width) -def format_bytes(data: bytes) -> str: +def format_bytes(data: bytes, width: int = 16) -> str: + print(f"formatting with width={width}") lines = [] - for line_no in range(0, len(data), 16): - line = data[line_no : line_no + 16] + for line_no in range(0, len(data), width): + line = data[line_no : line_no + width] lines.append(" DB " + ", ".join(["$%02X" % b for b in line])) return "\n".join(lines) -def generate_map(pngfile: str) -> None: +def generate_map(pngfile: str, compress: bool = False) -> None: pngpath = pathlib.Path(pngfile).resolve() incpath = pngpath.parent / pngpath.name.replace(".png", ".inc") spath = pngpath.parent / pngpath.name.replace(".png", ".s") @@ -90,13 +90,13 @@ def generate_map(pngfile: str) -> None: ] ) - map_data = format_bytes(tilef.read()) + map_data = format_bytes(tilef.read(), width=width) tile_data = format_bytes(mapf.read()) section = pngpath.name.replace(".png", "") collpath = pngpath.parent / pngpath.name.replace(".png", "_coll.png") - coll_map = generate_coll_map(collpath, width, height) + coll_map = generate_coll_map(collpath, width, height, compress=compress) with open(incpath, "w") as outf: outf.write( @@ -131,9 +131,10 @@ ASSERT {section}_MAP_SIZE == {section}_WIDTH * {section}_HEIGHT def main() -> None: parser = argparse.ArgumentParser("generate_map") + parser.add_argument("-c", "--compress", default=False) parser.add_argument("png") args = parser.parse_args() - generate_map(args.png) + generate_map(args.png, compress=(not not args.compress)) if __name__ == "__main__": diff --git a/src/bg.s b/src/bg.s index 7ee1323..0a4d878 100644 --- a/src/bg.s +++ b/src/bg.s @@ -1,7 +1,23 @@ INCLUDE "hardware.inc" INCLUDE "png/map/intro.inc" -SECTION "BG0", ROM0 +SECTION "BG Data", WRAM0 + +BG_COLLISION_DATA:: dw +BG_MAP_WIDTH:: db + +SECTION "BG Code", ROM0 + +MACRO update_map_info + ld hl, BG_COLLISION_DATA + ld a, HIGH(\1) + ld [hli], a + ld a, LOW(\1) + ld [hli], a + + ld a, \2 + ld [hli], a +ENDM BG_Init:: ; copy map @@ -31,4 +47,6 @@ BG_Init:: ld d, intro_NUM_TILES call memcpy + update_map_info intro_COLLISION, intro_WIDTH + ret diff --git a/src/collision.s b/src/collision.s new file mode 100644 index 0000000..9057ddf --- /dev/null +++ b/src/collision.s @@ -0,0 +1,133 @@ +INCLUDE "oam.inc" + +SECTION "Collision", ROMX + +; Check whether a 16x16 metasprite collides with the background +; @param a The index of the first (top left) OAM entry of the sprite +; @destroy hl +; note: doesn't work atm (use srl, not sra?) +sprite16x16_bg_collides:: + ; compute oam entry address (_OAM + a * 4) + ; a is guaranteed not to overflow since l = $00 and a < 40 + ld hl, _OAM + sla a + sla a + add l + ld l, a + + ; top left (x,y) + ld a, [hl+] + sra a + sra a + sra a + ld c, [hl] + sra c + sra c + sra c + call can_move_to + ret nz + + ; other three sprites + REPT 3 + ld a, [hl+] + sra a + sra a + sra a + ld c, [hl] + sra c + sra c + sra c + call can_move_to + ret nz + ENDR + + ret + +player_bg_collides:: + ; c = x/8 + ld hl, PLAYER_X + ld a, [hl] + ld c, a + and %111 + jr z, .skip_inc_c + ld a, c + add 8 + ld c, a +.skip_inc_c: + srl c + srl c + srl c + + ; b = y/8 + inc hl + ld a, [hl] + ld b, a + and %111 + jr z, .skip_inc_b + ld a, b + add 8 + ld b, a +.skip_inc_b: + srl b + srl b + srl b + + ; top left + call can_move_to + ret z + + ; top right + inc c + call can_move_to + ret z + + ; bottom left + dec c + inc b + call can_move_to + ret z + + ; bottom right + inc c + call can_move_to + + ret + +; Check whether the location can be moved to or not +; @param b y-coordinate +; @param c x-coordinate +; @destroy a, d, e +; @note Z = false, NZ = true +can_move_to: + ; todo: should be aware of scx/scy + push bc + push hl + + ; hl = bg_collision_data + ld hl, BG_COLLISION_DATA + ld d, [hl] + inc hl + ld e, [hl] + push de + + ; de = map width + ld hl, BG_MAP_WIDTH + ld d, 0 + ld e, [hl] + pop hl + + ; compute map index (HL + B * (BG_MAP_WIDTH + 1) + C) +.mul_y_width: + add hl, de + dec b + jr nz, .mul_y_width + add hl, bc + + ; check [hl] = 1 + ld a, [hl] + cp 0 + + pop hl + pop bc + + ret diff --git a/src/player.s b/src/player.s index b8d3578..1aafa71 100644 --- a/src/player.s +++ b/src/player.s @@ -7,6 +7,11 @@ Section "Player Data", WRAM0 playerWorldX: dw playerWorldY: dw +; player data +PLAYER_X:: db +PLAYER_Y:: db +PLAYER_DIR:: db + Section "Player Code", ROM0 spriteData: @@ -18,6 +23,14 @@ DEF SPRITE_WIDTH EQU 2 DEF SPRITE_HEIGHT EQU 2 Player_Init:: + ; clear player data + ld hl, PLAYER_X + ld [hl], 0 + inc hl + ld [hl], 144-32 + inc hl + ld [hl], 0 + ld a, 8 ld hl, _OAM + 1 ld [hl], a @@ -56,13 +69,27 @@ Player_Update:: jr z, .left ; check for right boundary - ld_OAM_x hl, SPRITE_OAM_IDX + 1 + ld hl, PLAYER_X ld a, [hl] + add 16 cp SCRN_X jr nc, .left - ; TODO: check collision - call move_right + 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] + ret .left: ; check for left button @@ -71,90 +98,97 @@ Player_Update:: ret z ; check for left boundary - ld_OAM_x hl, SPRITE_OAM_IDX + ld hl, PLAYER_X ld a, [hl] - cp 9 - ret c + or a + ret z - ; TODO: check collision - call move_left + dec [hl] - ret + call player_bg_collides + jr z, .left_rollback -move_right: - ld_OAM_x hl, SPRITE_OAM_IDX + ld hl, PLAYER_DIR + ld [hl], $ff - ; update top left sprite - inc [hl] - inc hl - ld [hl], SPRITE_IDX - inc hl - res OAMB_XFLIP, [hl] + call update_oam + ret - ; update top right sprite - inc hl - inc hl - inc [hl] - inc hl - ld [hl], SPRITE_IDX + 1 - inc hl - res OAMB_XFLIP, [hl] +.left_rollback: + ld hl, PLAYER_X + dec [hl] + ret - ; update bottom left sprite - inc hl - inc hl - inc [hl] - inc hl - ld [hl], SPRITE_IDX + 2 - inc hl - res OAMB_XFLIP, [hl] +; Update sprite OAM entries with current position and direction +update_oam: + ld hl, PLAYER_DIR + ld a, [hl-] ; dir (0 = right , $ff = left) + and OAMF_XFLIP + ld c, a - ; update bottom right sprite - inc hl - inc hl - inc [hl] - inc hl - ld [hl], SPRITE_IDX + 3 - inc hl - res OAMB_XFLIP, [hl] + ld a, [hl-] ; y + add 16 - ret + ld d, a + ld a, [hl] ; x + add 8 + ld b, a + ld a, d -move_left: - ld_OAM_x hl, SPRITE_OAM_IDX + ld_OAM_y hl, SPRITE_OAM_IDX - ; top left - dec [hl] + ; top left sprite + ld [hli], a + ld [hl], b inc hl - ld [hl], SPRITE_IDX + 1 + ld [hl], SPRITE_IDX + inc hl + ld [hl], c inc hl - set OAMB_XFLIP, [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 - dec [hl] - inc hl - ld [hl], SPRITE_IDX + ld [hl], c inc hl - set OAMB_XFLIP, [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 - dec [hl] - inc hl - ld [hl], SPRITE_IDX + 3 + ld [hl], c inc hl - set OAMB_XFLIP, [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 - dec [hl] - inc hl - ld [hl], SPRITE_IDX + 2 - inc hl - set OAMB_XFLIP, [hl] + ld [hl], c ret