From 29cf895b6f38c7b1e11f5e005cd92519a6b63c5d Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 08:58:45 +0200 Subject: [PATCH 1/9] chore: ignore Jetbrains IDE files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0dbc3ac4..19817e05 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ /po/messages.pot /galactic-armada/src/generated /galactic-armada/dist/ -/galactic-armada/obj/ \ No newline at end of file +/galactic-armada/obj/ +.idea \ No newline at end of file From 2dc923a3a9d9f63b53e2485ee257924c0d6c5682 Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 09:05:05 +0200 Subject: [PATCH 2/9] feat: decimal numbers introduction --- src/SUMMARY.md | 1 + src/part2/bcd.md | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 src/part2/bcd.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 80d15ab1..9d4aaeef 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -29,6 +29,7 @@ - [Input](part2/input.md) - [Collision](part2/collision.md) - [Bricks](part2/bricks.md) +- [Decimal Numbers](part2/bcd.md) - [Work in progress](part2/wip.md) # Part III — Our second game diff --git a/src/part2/bcd.md b/src/part2/bcd.md new file mode 100644 index 00000000..227fe20a --- /dev/null +++ b/src/part2/bcd.md @@ -0,0 +1,5 @@ +# Decimal Numbers + +Now that we can make the bricks disappear on impact, we should probably get some reward, like points! +We'll start off with a score of 0 and then increase the score by 1 point each time a brick gets destroyed. +Then we can display the score on a scoreboard. From 4f76dbc2a1754e52e70cdcd4d40edde56b014b52 Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 09:11:46 +0200 Subject: [PATCH 3/9] feat: BCD introduction --- src/part2/bcd.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/part2/bcd.md b/src/part2/bcd.md index 227fe20a..4c54a44e 100644 --- a/src/part2/bcd.md +++ b/src/part2/bcd.md @@ -3,3 +3,15 @@ Now that we can make the bricks disappear on impact, we should probably get some reward, like points! We'll start off with a score of 0 and then increase the score by 1 point each time a brick gets destroyed. Then we can display the score on a scoreboard. + +## BCD + +As we're stingy when it comes to memory use, we will only use one byte. There are different ways of saving and retrieving numbers as decimals, but this time we will choose something called "Packed Binary Coded Decimal" or packed BCD for short. + +BCD is a way of storing decimal numbers in bytes, not using A-F, so $A would be 10 which consists of the digits 1 and 0. + +Remember how bits, nibbles and bytes work? Go and have a look at the [Hexadeciamal](../part1/bin_and_hex.md) section if you need a reminder. + +The "packed" part means that we pack 2 digits into one byte. A byte contains 8 bits and inside 4 bits we can already store numbers between `$0` (`%0000`) and `$F` (`%1111`), which is more than sufficent to store a number between 0 and 9. + +For example the number 35 (my favorite Pokémon) contains the number 3 `%0011` and 5 `%0101` and as a packed BCD this is `%00110101` From caa7741182697873984878e39aa4504e98ea00c3 Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 09:27:00 +0200 Subject: [PATCH 4/9] feat: score variable introduction --- src/part2/bcd.md | 14 + unbricked/bcd/main.asm | 631 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 645 insertions(+) create mode 100644 unbricked/bcd/main.asm diff --git a/src/part2/bcd.md b/src/part2/bcd.md index 4c54a44e..5cfbcf58 100644 --- a/src/part2/bcd.md +++ b/src/part2/bcd.md @@ -15,3 +15,17 @@ Remember how bits, nibbles and bytes work? Go and have a look at the [Hexadeciam The "packed" part means that we pack 2 digits into one byte. A byte contains 8 bits and inside 4 bits we can already store numbers between `$0` (`%0000`) and `$F` (`%1111`), which is more than sufficent to store a number between 0 and 9. For example the number 35 (my favorite Pokémon) contains the number 3 `%0011` and 5 `%0101` and as a packed BCD this is `%00110101` + +## Calculating the score + +Now let's start by defining a global variable (memory location) for the score: + +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:score-variable}} +{{#include ../../unbricked/bcd/main.asm:score-variable}} +``` + +And we'll set this to zero when initializing the other global variables. + +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:init-variables}} +{{#include ../../unbricked/bcd/main.asm:init-variables}} +``` diff --git a/unbricked/bcd/main.asm b/unbricked/bcd/main.asm new file mode 100644 index 00000000..c27c58b7 --- /dev/null +++ b/unbricked/bcd/main.asm @@ -0,0 +1,631 @@ +; ANCHOR: constants +INCLUDE "hardware.inc" + +DEF BRICK_LEFT EQU $05 +DEF BRICK_RIGHT EQU $06 +DEF BLANK_TILE EQU $08 +; ANCHOR_END: constants + +SECTION "Header", ROM0[$100] + + jp EntryPoint + + ds $150 - @, 0 ; Make room for the header + +EntryPoint: + ; Do not turn the LCD off outside of VBlank +WaitVBlank: + ld a, [rLY] + cp 144 + jp c, WaitVBlank + + ; Turn the LCD off + ld a, 0 + ld [rLCDC], a + + ; Copy the tile data + ld de, Tiles + ld hl, $9000 + ld bc, TilesEnd - Tiles + call Memcopy + + ; Copy the tilemap + ld de, Tilemap + ld hl, $9800 + ld bc, TilemapEnd - Tilemap + call Memcopy + + ; Copy the paddle tile + ld de, Paddle + ld hl, $8000 + ld bc, PaddleEnd - Paddle + call Memcopy + + ; Copy the ball tile + ld de, Ball + ld hl, $8010 + ld bc, BallEnd - Ball + call Memcopy + + xor a, a + ld b, 160 + ld hl, _OAMRAM +ClearOam: + ld [hli], a + dec b + jp nz, ClearOam + + ; Initialize the paddle sprite in OAM + ld hl, _OAMRAM + ld a, 128 + 16 + ld [hli], a + ld a, 16 + 8 + ld [hli], a + ld a, 0 + ld [hli], a + ld [hli], a + ; Now initialize the ball sprite + ld a, 100 + 16 + ld [hli], a + ld a, 32 + 8 + ld [hli], a + ld a, 1 + ld [hli], a + ld a, 0 + ld [hli], a + + ; The ball starts out going up and to the right + ld a, 1 + ld [wBallMomentumX], a + ld a, -1 + ld [wBallMomentumY], a + + ; Turn the LCD on + ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON + ld [rLCDC], a + + ; During the first (blank) frame, initialize display registers + ld a, %11100100 + ld [rBGP], a + ld a, %11100100 + ld [rOBP0], a + ; ANCHOR: init-variables + ; Initialize global variables + ld a, 0 + ld [wFrameCounter], a + ld [wCurKeys], a + ld [wNewKeys], a + ld [wScore], a + ; ANCHOR_END: init-variables + +Main: + ld a, [rLY] + cp 144 + jp nc, Main +WaitVBlank2: + ld a, [rLY] + cp 144 + jp c, WaitVBlank2 + + ; Add the ball's momentum to its position in OAM. + ld a, [wBallMomentumX] + ld b, a + ld a, [_OAMRAM + 5] + add a, b + ld [_OAMRAM + 5], a + + ld a, [wBallMomentumY] + ld b, a + ld a, [_OAMRAM + 4] + add a, b + ld [_OAMRAM + 4], a + +; ANCHOR: updated-bounce +BounceOnTop: + ; Remember to offset the OAM position! + ; (8, 16) in OAM coordinates is (0, 0) on the screen. + ld a, [_OAMRAM + 4] + sub a, 16 + 1 + ld c, a + ld a, [_OAMRAM + 5] + sub a, 8 + ld b, a + call GetTileByPixel ; Returns tile address in hl + ld a, [hl] + call IsWallTile + jp nz, BounceOnRight + call CheckAndHandleBrick + ld a, 1 + ld [wBallMomentumY], a + +BounceOnRight: + ld a, [_OAMRAM + 4] + sub a, 16 + ld c, a + ld a, [_OAMRAM + 5] + sub a, 8 - 1 + ld b, a + call GetTileByPixel + ld a, [hl] + call IsWallTile + jp nz, BounceOnLeft + call CheckAndHandleBrick + ld a, -1 + ld [wBallMomentumX], a + +BounceOnLeft: + ld a, [_OAMRAM + 4] + sub a, 16 + ld c, a + ld a, [_OAMRAM + 5] + sub a, 8 + 1 + ld b, a + call GetTileByPixel + ld a, [hl] + call IsWallTile + jp nz, BounceOnBottom + call CheckAndHandleBrick + ld a, 1 + ld [wBallMomentumX], a + +BounceOnBottom: + ld a, [_OAMRAM + 4] + sub a, 16 - 1 + ld c, a + ld a, [_OAMRAM + 5] + sub a, 8 + ld b, a + call GetTileByPixel + ld a, [hl] + call IsWallTile + jp nz, BounceDone + call CheckAndHandleBrick + ld a, -1 + ld [wBallMomentumY], a +BounceDone: +; ANCHOR_END: updated-bounce + + ; First, check if the ball is low enough to bounce off the paddle. + ld a, [_OAMRAM] + ld b, a + ld a, [_OAMRAM + 4] + cp a, b + jp nz, PaddleBounceDone + ; Now let's compare the X positions of the objects to see if they're touching. + ld a, [_OAMRAM + 1] + ld b, a + ld a, [_OAMRAM + 5] + add a, 16 + cp a, b + jp c, PaddleBounceDone + sub a, 16 + 8 + cp a, b + jp nc, PaddleBounceDone + + ld a, -1 + ld [wBallMomentumY], a + +PaddleBounceDone: + + ; Check the current keys every frame and move left or right. + call Input + + ; First, check if the left button is pressed. +CheckLeft: + ld a, [wCurKeys] + and a, PADF_LEFT + jp z, CheckRight +Left: + ; Move the paddle one pixel to the left. + ld a, [_OAMRAM + 1] + dec a + ; If we've already hit the edge of the playfield, don't move. + cp a, 15 + jp z, Main + ld [_OAMRAM + 1], a + jp Main + +; Then check the right button. +CheckRight: + ld a, [wCurKeys] + and a, PADF_RIGHT + jp z, Main +Right: + ; Move the paddle one pixel to the right. + ld a, [_OAMRAM + 1] + inc a + ; If we've already hit the edge of the playfield, don't move. + cp a, 105 + jp z, Main + ld [_OAMRAM + 1], a + jp Main + +; Convert a pixel position to a tilemap address +; hl = $9800 + X + Y * 32 +; @param b: X +; @param c: Y +; @return hl: tile address +GetTileByPixel: + ; First, we need to divide by 8 to convert a pixel position to a tile position. + ; After this we want to multiply the Y position by 32. + ; These operations effectively cancel out so we only need to mask the Y value. + ld a, c + and a, %11111000 + ld l, a + ld h, 0 + ; Now we have the position * 8 in hl + add hl, hl ; position * 16 + add hl, hl ; position * 32 + ; Just add the X position and offset to the tilemap, and we're done. + ld a, b + srl a ; a / 2 + srl a ; a / 4 + srl a ; a / 8 + add a, l + ld l, a + adc a, h + sub a, l + ld h, a + ld bc, $9800 + add hl, bc + ret + +; @param a: tile ID +; @return z: set if a is a wall. +IsWallTile: + cp a, $00 + ret z + cp a, $01 + ret z + cp a, $02 + ret z + cp a, $04 + ret z + cp a, $05 + ret z + cp a, $06 + ret z + cp a, $07 + ret + +; ANCHOR: check-for-brick +; Checks if a brick was collided with and breaks it if possible. +; @param hl: address of tile. +CheckAndHandleBrick: + ld a, [hl] + cp a, BRICK_LEFT + jr nz, CheckAndHandleBrickRight + ; Break a brick from the left side. + ld [hl], BLANK_TILE + inc hl + ld [hl], BLANK_TILE +CheckAndHandleBrickRight: + cp a, BRICK_RIGHT + ret nz + ; Break a brick from the right side. + ld [hl], BLANK_TILE + dec hl + ld [hl], BLANK_TILE + ret +; ANCHOR_END: check-for-brick + +Input: + ; Poll half the controller + ld a, P1F_GET_BTN + call .onenibble + ld b, a ; B7-4 = 1; B3-0 = unpressed buttons + + ; Poll the other half + ld a, P1F_GET_DPAD + call .onenibble + swap a ; A3-0 = unpressed directions; A7-4 = 1 + xor a, b ; A = pressed buttons + directions + ld b, a ; B = pressed buttons + directions + + ; And release the controller + ld a, P1F_GET_NONE + ldh [rP1], a + + ; Combine with previous wCurKeys to make wNewKeys + ld a, [wCurKeys] + xor a, b ; A = keys that changed state + and a, b ; A = keys that changed to pressed + ld [wNewKeys], a + ld a, b + ld [wCurKeys], a + ret + +.onenibble + ldh [rP1], a ; switch the key matrix + call .knownret ; burn 10 cycles calling a known ret + ldh a, [rP1] ; ignore value while waiting for the key matrix to settle + ldh a, [rP1] + ldh a, [rP1] ; this read counts + or a, $F0 ; A7-4 = 1; A3-0 = unpressed keys +.knownret + ret + +; Copy bytes from one area to another. +; @param de: Source +; @param hl: Destination +; @param bc: Length +Memcopy: + ld a, [de] + ld [hli], a + inc de + dec bc + ld a, b + or a, c + jp nz, Memcopy + ret + +Tiles: + dw `33333333 + dw `33333333 + dw `33333333 + dw `33322222 + dw `33322222 + dw `33322222 + dw `33322211 + dw `33322211 + dw `33333333 + dw `33333333 + dw `33333333 + dw `22222222 + dw `22222222 + dw `22222222 + dw `11111111 + dw `11111111 + dw `33333333 + dw `33333333 + dw `33333333 + dw `22222333 + dw `22222333 + dw `22222333 + dw `11222333 + dw `11222333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33322211 + dw `33322211 + dw `33322211 + dw `33322211 + dw `33322211 + dw `33322211 + dw `33322211 + dw `33322211 + dw `22222222 + dw `20000000 + dw `20111111 + dw `20111111 + dw `20111111 + dw `20111111 + dw `22222222 + dw `33333333 + dw `22222223 + dw `00000023 + dw `11111123 + dw `11111123 + dw `11111123 + dw `11111123 + dw `22222223 + dw `33333333 + dw `11222333 + dw `11222333 + dw `11222333 + dw `11222333 + dw `11222333 + dw `11222333 + dw `11222333 + dw `11222333 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `11001100 + dw `11111111 + dw `11111111 + dw `21212121 + dw `22222222 + dw `22322232 + dw `23232323 + dw `33333333 + ; My custom logo (tail) + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33302333 + dw `33333133 + dw `33300313 + dw `33300303 + dw `33013330 + dw `30333333 + dw `03333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `03333333 + dw `30333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333330 + dw `33333320 + dw `33333013 + dw `33330333 + dw `33100333 + dw `31001333 + dw `20001333 + dw `00000333 + dw `00000033 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33330333 + dw `33300333 + dw `33333333 + dw `33033333 + dw `33133333 + dw `33303333 + dw `33303333 + dw `33303333 + dw `33332333 + dw `33332333 + dw `33333330 + dw `33333300 + dw `33333300 + dw `33333100 + dw `33333000 + dw `33333000 + dw `33333100 + dw `33333300 + dw `00000001 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `10000333 + dw `00000033 + dw `00000003 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `33332333 + dw `33302333 + dw `32003333 + dw `00003333 + dw `00003333 + dw `00013333 + dw `00033333 + dw `00033333 + dw `33333300 + dw `33333310 + dw `33333330 + dw `33333332 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `30000000 + dw `33000000 + dw `33333000 + dw `33333333 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000003 + dw `00000033 + dw `00003333 + dw `02333333 + dw `33333333 + dw `00333333 + dw `03333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 + dw `33333333 +TilesEnd: + +Tilemap: + db $00, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $02, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $0A, $0B, $0C, $0D, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $0E, $0F, $10, $11, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $12, $13, $14, $15, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $16, $17, $18, $19, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 +TilemapEnd: + +Paddle: + dw `33333333 + dw `32222223 + dw `33333333 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `00000000 +PaddleEnd: + +Ball: + dw `00330000 + dw `03223000 + dw `32222300 + dw `32222300 + dw `03223000 + dw `00330000 + dw `00000000 + dw `00000000 +BallEnd: + +SECTION "Counter", WRAM0 +wFrameCounter: db + +SECTION "Input Variables", WRAM0 +wCurKeys: db +wNewKeys: db + +SECTION "Ball Data", WRAM0 +wBallMomentumX: db +wBallMomentumY: db + +; ANCHOR: score-variable +SECTION "Score", WRAM0 +wScore: db +; ANCHOR_END: score-variable \ No newline at end of file From 6287bb91874bebc67128f2bf56e431a90be289e5 Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 09:32:30 +0200 Subject: [PATCH 5/9] feat: DDA explanation and score increase --- src/part2/bcd.md | 20 ++++++++++++++++++++ unbricked/bcd/main.asm | 14 ++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/part2/bcd.md b/src/part2/bcd.md index 5cfbcf58..77f7886f 100644 --- a/src/part2/bcd.md +++ b/src/part2/bcd.md @@ -29,3 +29,23 @@ And we'll set this to zero when initializing the other global variables. ```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:init-variables}} {{#include ../../unbricked/bcd/main.asm:init-variables}} ``` + +Now we'll write a function to increase the score, right behind the `IsWallTile` function. +Don't worry about the call to `UpdateScoreBoard`, we'll get into that in a bit. + +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:increase-score}} +{{#include ../../unbricked/bcd/main.asm:increase-score}} +``` + +Let's have a look at what's going on there: +We set A to 1 and clear the carry flag +We add the score variable (contents of memory location `wScore`) to a, so now A has our increased score. + +So far so good, but what if the score was 9 and we add 1? The processor thinks in binary only and will do the following math: + +`%00001001` + `%00000001` = `%00001010` = `$A` + +That's a hexadecimal representation of 10, and we need to adjust it to become decimal. `DAA` or "Decimal Adjust after Addition," does just that. +After executing `DAA` our accumulator will be adjusted from `%00001010` to `%00010000`; a 1 in the left nibble and a 0 in the right one. A more detailed article about `DAA` on the Game Boy can be found [here](https://blog.ollien.com/posts/gb-daa/). + +Then we store the score back into `wScore` and finally, we call a function that will update the score board, which we will implement next. diff --git a/unbricked/bcd/main.asm b/unbricked/bcd/main.asm index c27c58b7..df5361ac 100644 --- a/unbricked/bcd/main.asm +++ b/unbricked/bcd/main.asm @@ -288,6 +288,20 @@ IsWallTile: cp a, $07 ret +; ANCHOR: increase-score +; Increase score by 1 and store it as a 1 byte packed BCD number +; changes A and HL +IncreaseScorePackedBCD: + xor a ; clear carry flag and a + inc a ; a = 1 + ld hl, wScore ; load score + adc [hl] ; add 1 + daa ; convert to BCD + ld [hl], a ; store score + call UpdateScoreBoard + ret +; ANCHOR_END: increase-score + ; ANCHOR: check-for-brick ; Checks if a brick was collided with and breaks it if possible. ; @param hl: address of tile. From ca0eeea9c8185025eae0665bf0527075d5d959ec Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 09:38:01 +0200 Subject: [PATCH 6/9] feat: score increase on brick collision --- src/part2/bcd.md | 6 ++++++ unbricked/bcd/main.asm | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/part2/bcd.md b/src/part2/bcd.md index 77f7886f..a9ab7497 100644 --- a/src/part2/bcd.md +++ b/src/part2/bcd.md @@ -49,3 +49,9 @@ That's a hexadecimal representation of 10, and we need to adjust it to become de After executing `DAA` our accumulator will be adjusted from `%00001010` to `%00010000`; a 1 in the left nibble and a 0 in the right one. A more detailed article about `DAA` on the Game Boy can be found [here](https://blog.ollien.com/posts/gb-daa/). Then we store the score back into `wScore` and finally, we call a function that will update the score board, which we will implement next. + +Of course, we still need to call it on impact. To do this, we add a call to `IncreaseScorePackedBCD` after each collision handler (we had a left and a right collision) in `CheckAndHandleBrick` + +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:check-for-brick}} +{{#include ../../unbricked/bcd/main.asm:check-for-brick}} +``` \ No newline at end of file diff --git a/unbricked/bcd/main.asm b/unbricked/bcd/main.asm index df5361ac..c6942656 100644 --- a/unbricked/bcd/main.asm +++ b/unbricked/bcd/main.asm @@ -313,6 +313,7 @@ CheckAndHandleBrick: ld [hl], BLANK_TILE inc hl ld [hl], BLANK_TILE + call IncreaseScorePackedBCD CheckAndHandleBrickRight: cp a, BRICK_RIGHT ret nz @@ -320,6 +321,7 @@ CheckAndHandleBrickRight: ld [hl], BLANK_TILE dec hl ld [hl], BLANK_TILE + call IncreaseScorePackedBCD ret ; ANCHOR_END: check-for-brick From 713257ee9c8a0f9583c156100eb85c584d87c281 Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 09:39:20 +0200 Subject: [PATCH 7/9] chore: remove superfluous anchors from previous lesson --- unbricked/bcd/main.asm | 4 ---- 1 file changed, 4 deletions(-) diff --git a/unbricked/bcd/main.asm b/unbricked/bcd/main.asm index c6942656..20792cb3 100644 --- a/unbricked/bcd/main.asm +++ b/unbricked/bcd/main.asm @@ -1,10 +1,8 @@ -; ANCHOR: constants INCLUDE "hardware.inc" DEF BRICK_LEFT EQU $05 DEF BRICK_RIGHT EQU $06 DEF BLANK_TILE EQU $08 -; ANCHOR_END: constants SECTION "Header", ROM0[$100] @@ -120,7 +118,6 @@ WaitVBlank2: add a, b ld [_OAMRAM + 4], a -; ANCHOR: updated-bounce BounceOnTop: ; Remember to offset the OAM position! ; (8, 16) in OAM coordinates is (0, 0) on the screen. @@ -183,7 +180,6 @@ BounceOnBottom: ld a, -1 ld [wBallMomentumY], a BounceDone: -; ANCHOR_END: updated-bounce ; First, check if the ball is low enough to bounce off the paddle. ld a, [_OAMRAM] From cbca29befed474dcdbc667caa18bb6de6ccf35be Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 10:04:07 +0200 Subject: [PATCH 8/9] feat: digit tile set and score initialization --- src/assets/part2/img/bcd-tilemap.png | Bin 0 -> 27612 bytes src/assets/part2/img/bcd-tileset.png | Bin 0 -> 1810 bytes src/part2/bcd.md | 32 ++++++- unbricked/bcd/digit-tileset.asm | 91 ++++++++++++++++++ unbricked/bcd/main.asm | 136 +++++++++++++++++++++++---- unbricked/bcd/tilemap.asm | 20 ++++ 6 files changed, 259 insertions(+), 20 deletions(-) create mode 100644 src/assets/part2/img/bcd-tilemap.png create mode 100644 src/assets/part2/img/bcd-tileset.png create mode 100644 unbricked/bcd/digit-tileset.asm create mode 100644 unbricked/bcd/tilemap.asm diff --git a/src/assets/part2/img/bcd-tilemap.png b/src/assets/part2/img/bcd-tilemap.png new file mode 100644 index 0000000000000000000000000000000000000000..abc32824371aee31983fbbaed44a0910d7c3e6ba GIT binary patch literal 27612 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�R--mBX6rUGerU`HQfX4gsZT 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 MjxMLG?Y$HK1$nfc4gdfE literal 0 HcmV?d00001 diff --git a/src/assets/part2/img/bcd-tileset.png b/src/assets/part2/img/bcd-tileset.png new file mode 100644 index 0000000000000000000000000000000000000000..ba0b6fcf2f38dd405956f7e86df5664ba0e48b37 GIT binary patch literal 1810 zcmai#c~BEq9LJ-rTJfN$jH1O1f@ncSvV(wuq>6I198w`bj95YrWtB)MBp4E`t%4FR zZIloaZK;StVlk$IfUyGtfeqe)gi}#afgn;6WFd4FsjkCg;pDw)P+J$N>3qG>$Y2`v}b@21NSc~*)Yg>oh@4aHEeK(>f$Bbu{*EBkM zax!cf;DA!DH{MRF2!cl&J54XEJmEgP$!)}#VtVeHKN(X%hlwLS#)T%^{Q|Cs+6U}- zrsk({DY-Uq{YKmB8x9V_iEO*q)fK}##P4TE>K$NqUY4fvuE@#)ndoK6iSjK$|oa)4u`3Sfn`OnmlwtN6{pX&(mTYR>!mZMMFrLb8mUo1l}z4>})@{)Yz z<(y6|TUgv*@OT@8*3@+1j8MNTidKXBfVgh74Ape@aY5HOH)Fix&qfjzZMo(U5T6)Z z0e#hb}Dp-ICXPv-K>MACFohbgWwb6!pI&6xXA6UNGOkQr53`3T&vQo z6JOItv)L-1yQ@@Kwci?AT-zmwlu=q9$m@8nkVqH=5>vK zDajc&y1e4daf*MqA72*+_Ny7`EvXRHgS$x4i6DM%#FV3t0?8-7*dr}5i?ld= z=ky)~`s4Ai6`rllms}A+TZ))xFDU8JEZ(l8!V66CWh6KOQ(=I^#m5!OrSPTvV)Lzn za>mP62gpOvmwZ%c0Zt`ATld1hWTL7i>?w)+`6Y<^Xl#45Z?Zpc@9skTOS{!ljWoQXAy*ogOh8K$c<0e4 z185S6%gJhtm7Q_CA`(*dFR!K~23*~+bMZr25224xvYQHN+;GKNn$604<|=z2sOLsi z9o4nD(Ne31Ff6tXU*Rptvyx+kGC^N~PRq8hOK{W}-l@>4M`mtM1muvl#Bf^{e4bWY z;$MiItSE7lL>1S5Lh=6a(8!UH+~<IxHnZJ4y^W~NipM^oPmc5Y4& zjw<93gxEgq>;C1TF*Jo>zEIJSuZ~zDO(JuDe)x{{7Rkx`s8An4)tAtF<>1v_-H6rs zK$uph%B4cJw$TCaq%DoFT4qVRP8XERCF0w%yRjL4tQY_yQ7i1DPdl&3;=6nZOP+#l zz^&5Mk60j$q}B#zCRouZOcJ`Z@SWQ9^2ls6pk3ZT()!daFUOJ9fl{bNRl1>?@1NOc ztNCk6)!FuHe%eyI>iJrqV^#yr)2?}m=D;f4A}d-w4g>8~o}LbYoRe!Ylr#PPgcUzc zUc5C)H|-^Yx5sRLnDcOD3XO#8c83U7m_8xi93*aGL^~t@I+Wk` Lz-_Xv-yQiIw|dHF literal 0 HcmV?d00001 diff --git a/src/part2/bcd.md b/src/part2/bcd.md index a9ab7497..d709a5fb 100644 --- a/src/part2/bcd.md +++ b/src/part2/bcd.md @@ -54,4 +54,34 @@ Of course, we still need to call it on impact. To do this, we add a call to `Inc ```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:check-for-brick}} {{#include ../../unbricked/bcd/main.asm:check-for-brick}} -``` \ No newline at end of file +``` + +## Digit tiles + +Before we can display the score we'll need to add some graphics for the numbers 0-9. We already have some ready-made digits for this project, so you can copy [this premade file](https://github.com/gbdev/gb-asm-tutorial/raw/master/unbricked/bcd/digit-tileset.asm), and paste it at the end of your tile set, just before the `TilesEnd` label. Your tile set will look like this: + +![Screenshot of tile set with digits added at the end](../assets/part2/img/bcd-tileset.png) + +So we can easily remember where the digits start, let's add a constant called `DIGIT_OFFSET` to point us to where the digits are relative to the start of the tile set: `$1A` + +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:digit-offset}} +{{#include ../../unbricked/bcd/main.asm:digit-offset}} +``` + +Let's make an assumption, that we cannot get a score higher than 99 ([what could possibly go wrong](https://en.wikipedia.org/wiki/Year_2000_problem)) so two digits are enough. + +We can start with showing two zeroes (the tile at offset `$1A`) on our initial map. Let's put them on row 3, starting 4 tiles to the left. +You can copy-paste the tile set from [this file](https://github.com/gbdev/gb-asm-tutorial/raw/master/unbricked/bcd/tilemap.asm) + +This should make the tile set look like this on start up: + +![Screenshot of tile map with two zeroes added](../assets/part2/img/bcd-tilemap.png) + +> **Tip:** You can find the address in VRAM in your emulator's tile map viewer by selecting the tile and looking at the index. +> The screenshot above is from emulucious. + +Let's remember their positions by defining a constant for VRAM location of the 10s and the 1s at the top of our file, behind the other constants. + +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:score-tile-location}} +{{#include ../../unbricked/bcd/main.asm:score-tile-location}} +``` diff --git a/unbricked/bcd/digit-tileset.asm b/unbricked/bcd/digit-tileset.asm new file mode 100644 index 00000000..fbc51ae2 --- /dev/null +++ b/unbricked/bcd/digit-tileset.asm @@ -0,0 +1,91 @@ + ; digits + ; 0 + dw `33333333 + dw `33000033 + dw `30033003 + dw `30033003 + dw `30033003 + dw `30033003 + dw `33000033 + dw `33333333 + ; 1 + dw `33333333 + dw `33300333 + dw `33000333 + dw `33300333 + dw `33300333 + dw `33300333 + dw `33000033 + dw `33333333 + ; 2 + dw `33333333 + dw `33000033 + dw `30330003 + dw `33330003 + dw `33000333 + dw `30003333 + dw `30000003 + dw `33333333 + ; 3 + dw `33333333 + dw `30000033 + dw `33330003 + dw `33000033 + dw `33330003 + dw `33330003 + dw `30000033 + dw `33333333 + ; 4 + dw `33333333 + dw `33000033 + dw `30030033 + dw `30330033 + dw `30330033 + dw `30000003 + dw `33330033 + dw `33333333 + ; 5 + dw `33333333 + dw `30000033 + dw `30033333 + dw `30000033 + dw `33330003 + dw `30330003 + dw `33000033 + dw `33333333 + ; 6 + dw `33333333 + dw `33000033 + dw `30033333 + dw `30000033 + dw `30033003 + dw `30033003 + dw `33000033 + dw `33333333 + ; 7 + dw `33333333 + dw `30000003 + dw `33333003 + dw `33330033 + dw `33300333 + dw `33000333 + dw `33000333 + dw `33333333 + ; 8 + dw `33333333 + dw `33000033 + dw `30333003 + dw `33000033 + dw `30333003 + dw `30333003 + dw `33000033 + dw `33333333 + ; 9 + dw `33333333 + dw `33000033 + dw `30330003 + dw `30330003 + dw `33000003 + dw `33330003 + dw `33000033 + dw `33333333 \ No newline at end of file diff --git a/unbricked/bcd/main.asm b/unbricked/bcd/main.asm index 20792cb3..6acfbae9 100644 --- a/unbricked/bcd/main.asm +++ b/unbricked/bcd/main.asm @@ -1,8 +1,14 @@ INCLUDE "hardware.inc" - +; ANCHOR: digit-offset DEF BRICK_LEFT EQU $05 DEF BRICK_RIGHT EQU $06 DEF BLANK_TILE EQU $08 +DEF DIGIT_OFFSET EQU $1A +; ANCHOR_END: digit-offset +; ANCHOR: score-tile-location +DEF SCORE_TENS EQU $9870 +DEF SCORE_ONES EQU $9871 +; ANCHOR_END: score-tile-location SECTION "Header", ROM0[$100] @@ -581,27 +587,119 @@ Tiles: dw `33333333 dw `33333333 dw `33333333 + + ; digits + ; 0 + dw `33333333 + dw `33000033 + dw `30033003 + dw `30033003 + dw `30033003 + dw `30033003 + dw `33000033 + dw `33333333 + ; 1 + dw `33333333 + dw `33300333 + dw `33000333 + dw `33300333 + dw `33300333 + dw `33300333 + dw `33000033 + dw `33333333 + ; 2 + dw `33333333 + dw `33000033 + dw `30330003 + dw `33330003 + dw `33000333 + dw `30003333 + dw `30000003 + dw `33333333 + ; 3 + dw `33333333 + dw `30000033 + dw `33330003 + dw `33000033 + dw `33330003 + dw `33330003 + dw `30000033 + dw `33333333 + ; 4 + dw `33333333 + dw `33000033 + dw `30030033 + dw `30330033 + dw `30330033 + dw `30000003 + dw `33330033 + dw `33333333 + ; 5 + dw `33333333 + dw `30000033 + dw `30033333 + dw `30000033 + dw `33330003 + dw `30330003 + dw `33000033 + dw `33333333 + ; 6 + dw `33333333 + dw `33000033 + dw `30033333 + dw `30000033 + dw `30033003 + dw `30033003 + dw `33000033 + dw `33333333 + ; 7 + dw `33333333 + dw `30000003 + dw `33333003 + dw `33330033 + dw `33300333 + dw `33000333 + dw `33000333 + dw `33333333 + ; 8 + dw `33333333 + dw `33000033 + dw `30333003 + dw `33000033 + dw `30333003 + dw `30333003 + dw `33000033 + dw `33333333 + ; 9 + dw `33333333 + dw `33000033 + dw `30330003 + dw `30330003 + dw `33000003 + dw `33330003 + dw `33000033 + dw `33333333 TilesEnd: Tilemap: - db $00, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $02, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $0A, $0B, $0C, $0D, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $0E, $0F, $10, $11, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $12, $13, $14, $15, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $16, $17, $18, $19, $03, 0,0,0,0,0,0,0,0,0,0,0,0 - db $04, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $00, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $02, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $1A, $1A, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $0A, $0B, $0C, $0D, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $0E, $0F, $10, $11, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $12, $13, $14, $15, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $16, $17, $18, $19, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 TilemapEnd: Paddle: diff --git a/unbricked/bcd/tilemap.asm b/unbricked/bcd/tilemap.asm new file mode 100644 index 00000000..5214cdba --- /dev/null +++ b/unbricked/bcd/tilemap.asm @@ -0,0 +1,20 @@ +Tilemap: + db $00, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $01, $02, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $1A, $1A, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $05, $06, $05, $06, $05, $06, $05, $06, $05, $06, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $0A, $0B, $0C, $0D, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $0E, $0F, $10, $11, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $12, $13, $14, $15, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $08, $07, $03, $16, $17, $18, $19, $03, 0,0,0,0,0,0,0,0,0,0,0,0 + db $04, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $07, $03, $03, $03, $03, $03, $03, 0,0,0,0,0,0,0,0,0,0,0,0 +TilemapEnd: \ No newline at end of file From 88294efedf046ba32d1d66fce9c58717fdbff733 Mon Sep 17 00:00:00 2001 From: hollannikas Date: Thu, 26 Dec 2024 10:23:04 +0200 Subject: [PATCH 9/9] feat: updating the score board --- src/part2/bcd.md | 19 +++++++++++++++++++ unbricked/bcd/main.asm | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/part2/bcd.md b/src/part2/bcd.md index d709a5fb..9c0cdfd2 100644 --- a/src/part2/bcd.md +++ b/src/part2/bcd.md @@ -85,3 +85,22 @@ Let's remember their positions by defining a constant for VRAM location of the 1 ```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:score-tile-location}} {{#include ../../unbricked/bcd/main.asm:score-tile-location}} ``` +## Displaying the score + +Now we need to write the missing `UpdateScoreBoard` function that will update the score board: + +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/bcd/main.asm:update-score-board}} +{{#include ../../unbricked/bcd/main.asm:update-score-board}} +``` + +First we load the score (stored in the wScore memory location) into register A. Recall that the score is stored in packed BCD format, where the upper nibble contains the tens digit and the lower nibble contains the ones digit. + +The `and %11110000` operation masks the lower nibble (the ones digit) so that only the upper nibble (the tens digit) remains in `A`. + +The `rrca` instructions perform a rotate right operation on `A` four times. This effectively shifts the tens digit to the lower nibble, making it ready to map to a digit tile. + +We then add the `DIGIT_OFFSET` constant to the tens digit to calculate the tile address for the digit. This address is stored in the `SCORE_TENS` VRAM location, which updates the display to show the tens digit. + +Finally, we repeat the process for the ones digit: We mask the tens digit from `A` using `and %00001111`, no need to rotate this time. + +Now we can display the score on the screen! We'll need to call `UpdateScoreBoard` after each time the score is updated. We've already done this in the `IncreaseScorePackedBCD` function, so we're all set! \ No newline at end of file diff --git a/unbricked/bcd/main.asm b/unbricked/bcd/main.asm index 6acfbae9..ba623a32 100644 --- a/unbricked/bcd/main.asm +++ b/unbricked/bcd/main.asm @@ -304,6 +304,25 @@ IncreaseScorePackedBCD: ret ; ANCHOR_END: increase-score +; ANCHOR: update-score-board +; Read the packed BCD score from wScore and updates the score display +UpdateScoreBoard: + ld a, [wScore] ; Get the Packed score + and %11110000 ; Mask the lower nibble + rrca ; Move the upper nibble to the lower nibble (divide by 16) + rrca + rrca + rrca + add a, DIGIT_OFFSET ; Offset + add to get the digit tile + ld [SCORE_TENS], a ; Show the digit on screen + + ld a, [wScore] ; Get the packed score again + and %00001111 ; Mask the upper nibble + add a, DIGIT_OFFSET ; Offset + add to get the digit tile again + ld [SCORE_ONES], a ; Show the digit on screen + ret +; ANCHOR_END: update-score-board + ; ANCHOR: check-for-brick ; Checks if a brick was collided with and breaks it if possible. ; @param hl: address of tile.