From e4d55eb9d92cb8930bda7dbaacc9074898a22bee Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Mon, 11 Jul 2022 17:26:26 -0400 Subject: [PATCH 01/19] Add getting-started to part 2 --- src/SUMMARY.md | 1 + src/part2/getting-started.md | 102 +++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 src/part2/getting-started.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 50ee7a08..0c670973 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -23,6 +23,7 @@ # Part Ⅱ — Our first game +- [Getting started](part2/getting-started.md) - [Work in progress](part2/wip.md) # Part Ⅲ — Our second game diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md new file mode 100644 index 00000000..9d5d5eca --- /dev/null +++ b/src/part2/getting-started.md @@ -0,0 +1,102 @@ +# Getting started + +In this lesson we will start a new project from scratch, an arkanoid clone called "Unbricked"! (Or any other name you like, as this is *your* project) + +Open a terminal and make new directory, like you did for "Hello, world!" (`mkdir unbricked`), and then enter it (`cd unbricked`). + +Start by creating a file called `main.asm`, and include hardware.inc in your code. + +``` +line 1 +``` + +Then create a header. Remember from part 1 that the header includes some information the Game Boy relies on, so you don't wanna accidentally leave it out. + +``` +lines 3-7 +``` + +The header jumps to `EntryPoint`, so let's write that now: + +``` +lines 9-18 +``` + +The next few lines wait until "VBlank". This basically means that the Game Boy's PPU has went to sleep for a short time, during which we can do things like turning off the screen. + +Turning off the screen is important because it puts the PPU to sleep until the screen is turned back on. You can only load new graphics while the PPU is sleeping, so this gives us time to load our tiles. + +Speaking of tiles, we're going to load some into VRAM next, using the following code: +``` +lines 20-31 +``` + +This loop might look familiar if you've read part 1. It copies `Tiles` to `$9000`, which is a part of VRAM where tiles are stored. To get the length of `Tiles`, we use another label at the end, called `TilesEnd`, and get the difference! + +Note that our code still doesn't have anything called `Tiles`. We'll get to that later! + +We're almost done now. Next, write another loop, this time for copying the tilemap, which will organize our tiles on the screen. + +``` +lines 33-44 +``` + +You might notice that while this code is exactly the same, the 3 values loaded into `de`, `hl`, and `bc` are different. These determine the source, destination, and size of the copy, respectively. + +Finally, we are going to turn the screen back on and initialize a background palette. hardware.inc provides the constants `LCDCF_ON` and `LCDCF_BGON`, which turn on the screen and the background respectively. We can "combine" these together using `|` (the or operator). + +``` +lines 46-55 +``` + +There's one last thing we need before we can build the rom, and that's our graphics. We're going to be drawing the following screen: + +![Layout of unbricked](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/tilemap.png?raw=true) + +In the "Hello, world!" lesson, you saw graphics which were wirtten out by hand in hexadecimal. This time, we're going to write our graphics in a more friendly way; by assigning a character to each shade! To do this, type `dw`, followed by a space, a backtick (\`) and a series of 8 characters; by default these are 0, 1, 2, and 3, from lightest to darkest. This defines a row of 8 pixels. + +```rgbasm,linenos +; For example: +Tiles: + dw `01230123 +``` + +(A note about OPT g could be added here?) + +We already have tiles made for this project, so you can copy [this premade file](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tileset.asm), and paste it at the end of your code. + +Then copy the tilemap from [this file](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tilemap.asm), and paste it after the `TilesEnd` label. + +You can try building the rom at this point, using the following commands in your terminal: + +```console +$ rgbasm -L -o unbricked.o unbricked.asm +$ rgblink -o unbricked.gb unbricked.o +$ rgbfix -v -p 0xFF unbricked.gb +``` + +If you run this in your emulator, you should see the following: + +(Screenshot pending :P) + +That white square seems to be missing! If you paid attention to your tiles earlier, you may have noticed this comment: + +``` +lines 135-140 +``` + +The logo tiles were left intentionally blank so that you could customize this project. If you feel up to it, you can try creating your own logo by hand, or you can copy one of the following logos into your code: + +## RGBDS Logo +[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/rgbds.asm) +![The RGBDS Logo](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/rgbds.png?raw=true) + +## Duck +[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/duck.asm) +![A pixel-art duck](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/duck.png?raw=true) + +## Tail +[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tail.asm) +![A silhouette of a tail](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/tail.png?raw=true) + +Build your game again and your logo of choice should appear in the bottom right! From 3f84b6aab46c39a4b721c717dde774e378bc5180 Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Mon, 11 Jul 2022 18:18:21 -0400 Subject: [PATCH 02/19] Apply suggestions from review --- src/part2/getting-started.md | 48 ++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 9d5d5eca..46ce7f60 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -1,10 +1,10 @@ # Getting started -In this lesson we will start a new project from scratch, an arkanoid clone called "Unbricked"! (Or any other name you like, as this is *your* project) +In this lesson we will start a new project from scratch, a [Breakout](https://en.wikipedia.org/wiki/Breakout_%28video_game%29) (also known as [Arkanoid](https://en.wikipedia.org/wiki/Arkanoid)) clone called "Unbricked"! (Or any other name you like, as this is *your* project) -Open a terminal and make new directory, like you did for "Hello, world!" (`mkdir unbricked`), and then enter it (`cd unbricked`). +Open a terminal and make a new directory (`mkdir unbricked`), and then enter it (`cd unbricked`), just like you did for "Hello, world!". -Start by creating a file called `main.asm`, and include hardware.inc in your code. +Start by creating a file called `main.asm`, and include `hardware.inc` in your code. ``` line 1 @@ -22,38 +22,52 @@ The header jumps to `EntryPoint`, so let's write that now: lines 9-18 ``` -The next few lines wait until "VBlank". This basically means that the Game Boy's PPU has went to sleep for a short time, during which we can do things like turning off the screen. +The next few lines wait until "VBlank". +VBlank basically means that the Game Boy's PPU has gone to sleep for a short time, during which we can do things like turning off the screen. -Turning off the screen is important because it puts the PPU to sleep until the screen is turned back on. You can only load new graphics while the PPU is sleeping, so this gives us time to load our tiles. +Turning off the screen is important because the PPU may wake back up at while we're still working. +By turning the screen off completely, we ensure that our code won't be interrupted. +You can only load new graphics while the PPU is sleeping, so this gives us as much time as we need to load our tiles. Speaking of tiles, we're going to load some into VRAM next, using the following code: ``` lines 20-31 ``` -This loop might look familiar if you've read part 1. It copies `Tiles` to `$9000`, which is a part of VRAM where tiles are stored. To get the length of `Tiles`, we use another label at the end, called `TilesEnd`, and get the difference! +This loop might look familiar if you've read part 1. +It copies `Tiles` to `$9000`, which is the part of VRAM where tiles are stored. +To get the length of `Tiles` we use another label at the end, called `TilesEnd`, and subtract the two to find the difference. -Note that our code still doesn't have anything called `Tiles`. We'll get to that later! +Note that our code still doesn't have a lable called `Tiles`. +We'll get to that later! -We're almost done now. Next, write another loop, this time for copying the tilemap, which will organize our tiles on the screen. +We're almost done now. +Next, write another loop, this time for copying the tilemap, which will organize our tiles on the screen. ``` lines 33-44 ``` -You might notice that while this code is exactly the same, the 3 values loaded into `de`, `hl`, and `bc` are different. These determine the source, destination, and size of the copy, respectively. +You might notice that while this code is exactly the same, the 3 values loaded into `de`, `hl`, and `bc` are different. +These determine the source, destination, and size of the copy, respectively. -Finally, we are going to turn the screen back on and initialize a background palette. hardware.inc provides the constants `LCDCF_ON` and `LCDCF_BGON`, which turn on the screen and the background respectively. We can "combine" these together using `|` (the or operator). +Finally, we are going to turn the screen back on and initialize a background palette. +hardware.inc provides the constants `LCDCF_ON` and `LCDCF_BGON`, which enable the screen and the background. +We must "combine" these together using `|` (the or operator). ``` lines 46-55 ``` -There's one last thing we need before we can build the rom, and that's our graphics. We're going to be drawing the following screen: +There's one last thing we need before we can build the rom, and that's our graphics. +We're going to be drawing the following screen: ![Layout of unbricked](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/tilemap.png?raw=true) -In the "Hello, world!" lesson, you saw graphics which were wirtten out by hand in hexadecimal. This time, we're going to write our graphics in a more friendly way; by assigning a character to each shade! To do this, type `dw`, followed by a space, a backtick (\`) and a series of 8 characters; by default these are 0, 1, 2, and 3, from lightest to darkest. This defines a row of 8 pixels. +In the "Hello, world!" lesson, you saw graphics which were written out by hand in hexadecimal. +This time, we're going to write our graphics in a more friendly way; by assigning a character to each shade. +To do this, type `dw`, followed by a space, a backtick (\`) and a series of 8 characters; by default these are 0, 1, 2, and 3, going from lightest to darkest. +This defines a row of 8 pixels. ```rgbasm,linenos ; For example: @@ -70,8 +84,8 @@ Then copy the tilemap from [this file](https://github.com/ISSOtm/gb-asm-tutorial You can try building the rom at this point, using the following commands in your terminal: ```console -$ rgbasm -L -o unbricked.o unbricked.asm -$ rgblink -o unbricked.gb unbricked.o +$ rgbasm -L -o main.o main.asm +$ rgblink -o unbricked.gb main.o $ rgbfix -v -p 0xFF unbricked.gb ``` @@ -79,13 +93,15 @@ If you run this in your emulator, you should see the following: (Screenshot pending :P) -That white square seems to be missing! If you paid attention to your tiles earlier, you may have noticed this comment: +That white square seems to be missing! +If you paid attention to your tiles earlier, you may have noticed this comment: ``` lines 135-140 ``` -The logo tiles were left intentionally blank so that you could customize this project. If you feel up to it, you can try creating your own logo by hand, or you can copy one of the following logos into your code: +The logo tiles were left intentionally blank so that you could customize this project. +If you feel up to it, you can try creating your own logo by hand, or you can copy one of the following logos into your code: ## RGBDS Logo [Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/rgbds.asm) From 7ad5c95b8af20a8f5aad24dfd2745551de688801 Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Mon, 11 Jul 2022 20:08:25 -0400 Subject: [PATCH 03/19] Apply suggestions from code review Co-authored-by: Eldred Habert --- src/part2/getting-started.md | 66 +++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 46ce7f60..51fe5532 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -1,8 +1,10 @@ # Getting started -In this lesson we will start a new project from scratch, a [Breakout](https://en.wikipedia.org/wiki/Breakout_%28video_game%29) (also known as [Arkanoid](https://en.wikipedia.org/wiki/Arkanoid)) clone called "Unbricked"! (Or any other name you like, as this is *your* project) +In this lesson, we will start a new project from scratch. +We will make a [Breakout](https://en.wikipedia.org/wiki/Breakout_%28video_game%29) / [Arkanoid](https://en.wikipedia.org/wiki/Arkanoid) clone, which we'll "Unbricked"! +(Though you are free to give it any other name you like, as it will be *your* project) -Open a terminal and make a new directory (`mkdir unbricked`), and then enter it (`cd unbricked`), just like you did for "Hello, world!". +Open a terminal and make a new directory (`mkdir unbricked`), and then enter it (`cd unbricked`), just like you did for ["Hello, world!"](../part1/hello-world). Start by creating a file called `main.asm`, and include `hardware.inc` in your code. @@ -10,7 +12,8 @@ Start by creating a file called `main.asm`, and include `hardware.inc` in your c line 1 ``` -Then create a header. Remember from part 1 that the header includes some information the Game Boy relies on, so you don't wanna accidentally leave it out. +Then, make room for the header. +[Remember from Part Ⅰ](../part1/header) that the header is where some information that the Game Boy relies on is stored, so you don't want to accidentally leave it out. ``` lines 3-7 @@ -30,49 +33,58 @@ By turning the screen off completely, we ensure that our code won't be interrupt You can only load new graphics while the PPU is sleeping, so this gives us as much time as we need to load our tiles. Speaking of tiles, we're going to load some into VRAM next, using the following code: + ``` lines 20-31 ``` -This loop might look familiar if you've read part 1. +This loop might be [reminiscent of part Ⅰ](../part1/jumps#conditional-jumps). It copies `Tiles` to `$9000`, which is the part of VRAM where tiles are stored. -To get the length of `Tiles` we use another label at the end, called `TilesEnd`, and subtract the two to find the difference. +To get how many bytes to copy, we will do just like in Part Ⅰ: using another label at the end, called `TilesEnd`, the difference between it (= the address after the last byte of tile data) and `Tiles` (= the address of the first byte) will be exactly that length. -Note that our code still doesn't have a lable called `Tiles`. +That said, we haven't written `Tiles` nor any of the related data yet. We'll get to that later! -We're almost done now. -Next, write another loop, this time for copying the tilemap, which will organize our tiles on the screen. +Almost done now—next, write another loop, this time for copying [the tilemap](../part1/tilemap). ``` lines 33-44 ``` -You might notice that while this code is exactly the same, the 3 values loaded into `de`, `hl`, and `bc` are different. +Note that while this loop's body is exactly the same as `CopyTiles`'s, the 3 values loaded into `de`, `hl`, and `bc` are different. These determine the source, destination, and size of the copy, respectively. -Finally, we are going to turn the screen back on and initialize a background palette. -hardware.inc provides the constants `LCDCF_ON` and `LCDCF_BGON`, which enable the screen and the background. -We must "combine" these together using `|` (the or operator). +::: tip DRY + +If you think that this is super redundant, you are not wrong, and we will see later how to write actual, reusable *functions*. +But there is more to them than meets the eye, so we will start tackling them much later. + +::: + +Finally, let's turn the screen back on, and set a [background palette](../part1/palettes). +Rather than writing the non-descript number `%10000001` (or $81 or 129, to taste), we make use of two constants graciously provided by `hardware.inc`: `LCDCF_ON` and `LCDCF_BGON`. +When written to [`rLCDC`](https://gbdev.io/pandocs/LCDC), the former causes the PPU and screen to turn back on, and the latter enables the background to be drawn. +(There are other elements that could be drawn, but we are not enabling them yet.) +Combining these constants must be done using `|`, the *binary "or"* operator; we'll see why later. ``` lines 46-55 ``` -There's one last thing we need before we can build the rom, and that's our graphics. -We're going to be drawing the following screen: +There's one last thing we need before we can build the ROM, and that's the graphics. +We will draw the following screen: ![Layout of unbricked](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/tilemap.png?raw=true) -In the "Hello, world!" lesson, you saw graphics which were written out by hand in hexadecimal. -This time, we're going to write our graphics in a more friendly way; by assigning a character to each shade. -To do this, type `dw`, followed by a space, a backtick (\`) and a series of 8 characters; by default these are 0, 1, 2, and 3, going from lightest to darkest. -This defines a row of 8 pixels. +In `hello-world.asm`, tile data had been written out by hand in hexadecimal; this was to let you see how the sausage is made at the lowest level, but *boy* is it impractical to write! +This time, we will employ a more friendly way, which will let us write each row of pixels more easily. +We will use `dw` instead of `db` (the difference between these two will be explained later); and for each row of pixels, instead of writing [the bitplanes](../part1/tiles#encoding) as raw numbers, we will use a backtick (\`) followed by 8 characters. +Each character defines a single pixel, intuitively from left to right; it must be one of 0, 1, 2, and 3, representing the corresponding color index in [the palette](../part1/palettes). + +For example: -```rgbasm,linenos -; For example: -Tiles: - dw `01230123 +```rgbasm + dw `01230123 ; This is equivalent to `db $55,$33` ``` (A note about OPT g could be added here?) @@ -81,7 +93,7 @@ We already have tiles made for this project, so you can copy [this premade file] Then copy the tilemap from [this file](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tilemap.asm), and paste it after the `TilesEnd` label. -You can try building the rom at this point, using the following commands in your terminal: +You can build the ROM now, by running the following commands in your terminal: ```console $ rgbasm -L -o main.o main.asm @@ -94,14 +106,14 @@ If you run this in your emulator, you should see the following: (Screenshot pending :P) That white square seems to be missing! -If you paid attention to your tiles earlier, you may have noticed this comment: +You may have noticed this comment earlier, somewhere in the tile data: ``` lines 135-140 ``` -The logo tiles were left intentionally blank so that you could customize this project. -If you feel up to it, you can try creating your own logo by hand, or you can copy one of the following logos into your code: +The logo tiles were left intentionally blank so that you can choose your own. +You can use one of the following pre-made logos, or try coming up with your own! ## RGBDS Logo [Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/rgbds.asm) @@ -115,4 +127,4 @@ If you feel up to it, you can try creating your own logo by hand, or you can cop [Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tail.asm) ![A silhouette of a tail](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/tail.png?raw=true) -Build your game again and your logo of choice should appear in the bottom right! +Replace the blank tiles with the new graphics, build the game again, and you should see your logo of choice in the bottom-right! From 3ab14c9212b1d7d07474b8b220992466daa6b026 Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Mon, 11 Jul 2022 20:33:35 -0400 Subject: [PATCH 04/19] Add suggestions from review --- src/assets/part2/img/tilemap.png | Bin 0 -> 708 bytes src/part2/getting-started.md | 26 +++++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 src/assets/part2/img/tilemap.png diff --git a/src/assets/part2/img/tilemap.png b/src/assets/part2/img/tilemap.png new file mode 100644 index 0000000000000000000000000000000000000000..6295c1ec11d84d58e78a34d162f65bdab2c904eb GIT binary patch literal 708 zcmV;#0z3VQP)0058z0{{R3^4o|L0004mX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9W`9PA+CkfC*IK~%(1t5Adrp;l;qmz@OiZxhH>NsGzSbbDicWQdq+b@wzAy);A z91EyHgWUFm|H1EWt>WZ_n-od{{V$I55d#9dK&#<6-^Y&AIsyF8z?I(h*P6i0C+Ur@ z7Ciz6w}Ff6uBPk(mpj1llOdaOTk_Ksibdf4jJ_!k4BZ03HMh6UK29HiEOnK>0S*p< zu@Yskd%Sy~x3_=Kbo%=NgkW;6SN$0p0000CP)t-s|NsAph=@EqJOBUyv$9X900009 za7bBm001r{001r{0eGc9b^rhX2XskIMF-{w3J)_7Gt^un0000PbVXQnLvL+uWo~o; zLvm$dbY)~9cWHEJAV*0}P*;Ht7XSbNmPtfGR9M69*f9!&KoEuD*XMFJ+nCGPVtA>sM0000 Date: Thu, 11 Aug 2022 11:58:50 -0400 Subject: [PATCH 05/19] Include code in part 2 --- src/assets/part2/img/screenshot.png | Bin 0 -> 1738 bytes src/assets/part2/unbricked.asm | 177 ++++++++++++++++++++++++++++ src/part2/getting-started.md | 39 +++--- 3 files changed, 198 insertions(+), 18 deletions(-) create mode 100644 src/assets/part2/img/screenshot.png create mode 100644 src/assets/part2/unbricked.asm diff --git a/src/assets/part2/img/screenshot.png b/src/assets/part2/img/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..8f347e057f235e3f637e6791f14513d7e449fd89 GIT binary patch literal 1738 zcmeAS@N?(olHy`uVBq!ia0y~yU~~Xt1r9c#$kCKlAAl4~v6E*A2N2Y7q;vrJk|nMY zCBgY=CFO}lsSN3P`MIgO#mPmfsd>d2`6cg}_uBy#>4FqF7o{eaWaj57gk7#SED0ohijW>$u#3XZ-Ct}Y>&Zn@123~b7tE{-7;bKc%nERv2CaR^M; zQt=Kc_AiNo-I97Ha0GtxP9URwwarPx7De~zpdsA4*8V5 zAZCBo)?4}a_S*k1V-xst{0%e13|EFm9Y&T-ECMHl928!^4fe0ORr_!5amMwx-abtG zruczFT491}gTpiirbs4^6i$T+U!N>L;JOZknmH(Bf8BjhCi~mpJ7@CGF9%sU_YB*P z8MS^#|9q>7LihmaM}&vxo+)kEy#9jue%twKAoFXP=hWJpf4==Wb2G&97dvMszh^Jk z`aapX{`Tko+W&f=*MHl+@aLISW|mE1)&N8kM3IrIKJ|H-@pC#+`j78w4X)AjT1&n-8QquCqIv6}gsAw7O!eqFVlFDQh5 zv4L&d{`@k?z&7&(7mLl0-{XH5@=iVd-?r!SzyHNPi+@}0{COtG`D@Gg3c$Xpe+G@i zf0`da4#>B&nGSRSFhwD(f^gPcT?Y)o);&L;9rnJ-(75IyFT@1-K2Uf8E!_S4@P*gu zb9Yzje&1|dpY!j<@9X9L+s^`R^Zh?tq5J0dVq<7rlp0AtNcv_e3W|)4z{r3kPejxK z!?V-~9GLfk5j+bNm|q~a0iz#m;C%-7_s7}52?s^nC5zCWM!&sW=h{*xnrzI-!(;$=`mnqB_> z{C?YSN0#4x?jB!I`19d(If0y;U;jP4Sij%)&Yx$>4=oV|3NQPIs{bDjSMvAU>e;5< z2IuPK2kNAQzTNrHZ^sJBd0!ds$>r7kx_$2Ry!x}}H|v6OW&MB5_9FN}E+_-sXS6PV)u7sWK>}FMFnGH9xvX literal 0 HcmV?d00001 diff --git a/src/assets/part2/unbricked.asm b/src/assets/part2/unbricked.asm new file mode 100644 index 00000000..70b26d97 --- /dev/null +++ b/src/assets/part2/unbricked.asm @@ -0,0 +1,177 @@ +; ANCHOR: dummy Lines beginning with `ANCHOR` and `ANCHOR_END` are used by mdBook +; ANCHOR_END: dummy Note that lines matching /^; ANCHOR/ are stripped from the online version +; ANCHOR: includes +INCLUDE "hardware.inc" +; ANCHOR_END: includes + +; ANCHOR: header +SECTION "Header", ROM0[$100] + + jp EntryPoint + + ds $150 - @, 0 ; Make room for the header +; ANCHOR_END: header + +; ANCHOR: entry +EntryPoint: + ; Do not turn the LCD off outside of VBlank +WaitVBlank: + ld a, [rLY] + cp 144 + jr c, WaitVBlank + + ; Turn the LCD off + ld a, 0 + ld [rLCDC], a +; ANCHOR_END: entry + +; ANCHOR: copy_tiles + ; Copy the tile data + ld de, Tiles + ld hl, $9000 + ld bc, TilesEnd - Tiles +CopyTiles: + ld a, [de] + ld [hli], a + inc de + dec bc + ld a, b + or a, c + jr nz, CopyTiles +; ANCHOR_END: copy_tiles + +; ANCHOR: copy_map + ; Copy the tilemap + ld de, Tilemap + ld hl, $9800 + ld bc, TilemapEnd - Tilemap +CopyTilemap: + ld a, [de] + ld [hli], a + inc de + dec bc + ld a, b + or a, c + jr nz, CopyTilemap +; ANCHOR_END: copy_map + +; ANCHOR: end + ; Turn the LCD on + ld a, LCDCF_ON | LCDCF_BGON + ld [rLCDC], a + + ; During the first (blank) frame, initialize display registers + ld a, %11100100 + ld [rBGP], a + +Done: + jr Done +; ANCHOR_END: end + +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 +; ANCHOR: custom_logo + dw `22322232 + dw `23232323 + dw `33333333 + ; Paste your logo here: + +TilesEnd: +; ANCHOR_END: custom_logo + +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: diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 8b877609..e7f428ba 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -8,8 +8,8 @@ Open a terminal and make a new directory (`mkdir unbricked`), and then enter it Start by creating a file called `main.asm`, and include `hardware.inc` in your code. -``` -line 1 +```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:includes}} +{{#include ../assets/part2/unbricked.asm:includes}} ``` `hardware.inc` is a file that provides constants which allow you to interface with the rest of the Game Boy. @@ -21,14 +21,14 @@ Numbers like this are difficult to memorize, and there are a *lot* to keep track Next, make room for the header. [Remember from Part Ⅰ](../part1/header) that the header is where some information that the Game Boy relies on is stored, so you don't want to accidentally leave it out. -``` -lines 3-7 +```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:header}} +{{#include ../assets/part2/unbricked.asm:header}} ``` The header jumps to `EntryPoint`, so let's write that now: -``` -lines 9-18 +```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:entry}} +{{#include ../assets/part2/unbricked.asm:entry}} ``` The next few lines wait until "VBlank", which is the only time you can safely turn off the screen (doing so at the wrong time could damage a real Game Boy, so this is very crucial). We'll talk more about VBlank later. @@ -37,8 +37,8 @@ Turning off the screen is important because loading new tiles while the screen i Speaking of tiles, we're going to load some into VRAM next, using the following code: -``` -lines 20-31 +```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:copy_tiles}} +{{#include ../assets/part2/unbricked.asm:copy_tiles}} ``` This loop might be [reminiscent of part Ⅰ](../part1/jumps#conditional-jumps). @@ -50,8 +50,8 @@ We'll get to that later! Almost done now—next, write another loop, this time for copying [the tilemap](../part1/tilemap). -``` -lines 33-44 +```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:copy_map}} +{{#include ../assets/part2/unbricked.asm:copy_map}} ``` Note that while this loop's body is exactly the same as `CopyTiles`'s, the 3 values loaded into `de`, `hl`, and `bc` are different. @@ -70,8 +70,8 @@ When written to [`rLCDC`](https://gbdev.io/pandocs/LCDC), the former causes the (There are other elements that could be drawn, but we are not enabling them yet.) Combining these constants must be done using `|`, the *binary "or"* operator; we'll see why later. -``` -lines 46-55 +```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:end}} +{{#include ../assets/part2/unbricked.asm:end}} ``` There's one last thing we need before we can build the ROM, and that's the graphics. @@ -111,28 +111,31 @@ $ rgbfix -v -p 0xFF unbricked.gb If you run this in your emulator, you should see the following: -(Screenshot pending :P) +![Screenshot of our game](../assets/part2/img/screenshot.png) That white square seems to be missing! You may have noticed this comment earlier, somewhere in the tile data: -``` -lines 135-140 +```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:custom_logo}} +{{#include ../assets/part2/unbricked.asm:custom_logo}} ``` The logo tiles were left intentionally blank so that you can choose your own. You can use one of the following pre-made logos, or try coming up with your own! ## RGBDS Logo -[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/rgbds.asm) ![The RGBDS Logo](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/rgbds.png?raw=true) +[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/rgbds.asm) + ## Duck -[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/duck.asm) ![A pixel-art duck](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/duck.png?raw=true) +[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/duck.asm) + ## Tail -[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tail.asm) ![A silhouette of a tail](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/tail.png?raw=true) +[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tail.asm) + Replace the blank tiles with the new graphics, build the game again, and you should see your logo of choice in the bottom-right! From 705fbe7db5adf5282407c584f6c1ff878e310f22 Mon Sep 17 00:00:00 2001 From: Evie M <14899090+eievui5@users.noreply.github.com> Date: Thu, 11 Aug 2022 11:59:55 -0400 Subject: [PATCH 06/19] Update src/part2/getting-started.md Co-authored-by: Antonio Vivace --- src/part2/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index e7f428ba..5268c80d 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -1,7 +1,7 @@ # Getting started In this lesson, we will start a new project from scratch. -We will make a [Breakout](https://en.wikipedia.org/wiki/Breakout_%28video_game%29) / [Arkanoid](https://en.wikipedia.org/wiki/Arkanoid) clone, which we'll "Unbricked"! +We will make a [Breakout](https://en.wikipedia.org/wiki/Breakout_%28video_game%29) / [Arkanoid](https://en.wikipedia.org/wiki/Arkanoid) clone, which we'll call "Unbricked"! (Though you are free to give it any other name you like, as it will be *your* project) Open a terminal and make a new directory (`mkdir unbricked`), and then enter it (`cd unbricked`), just like you did for ["Hello, world!"](../part1/hello-world). From 64de27671b2baabad0ca4989aa01fae1a4bbbd55 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Thu, 11 Aug 2022 23:15:05 +0200 Subject: [PATCH 07/19] Fix broken links --- src/part2/getting-started.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 5268c80d..2aab2781 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -4,7 +4,7 @@ In this lesson, we will start a new project from scratch. We will make a [Breakout](https://en.wikipedia.org/wiki/Breakout_%28video_game%29) / [Arkanoid](https://en.wikipedia.org/wiki/Arkanoid) clone, which we'll call "Unbricked"! (Though you are free to give it any other name you like, as it will be *your* project) -Open a terminal and make a new directory (`mkdir unbricked`), and then enter it (`cd unbricked`), just like you did for ["Hello, world!"](../part1/hello-world). +Open a terminal and make a new directory (`mkdir unbricked`), and then enter it (`cd unbricked`), just like you did for ["Hello, world!"](../part1/hello_world.md). Start by creating a file called `main.asm`, and include `hardware.inc` in your code. @@ -19,7 +19,7 @@ These are different from the CPU registers in that they live within the address Numbers like this are difficult to memorize, and there are a *lot* to keep track of, which is why we use `hardware.inc` to assign them more freidnly names, like `rLCDC`. Next, make room for the header. -[Remember from Part Ⅰ](../part1/header) that the header is where some information that the Game Boy relies on is stored, so you don't want to accidentally leave it out. +[Remember from Part Ⅰ](../part1/header.md) that the header is where some information that the Game Boy relies on is stored, so you don't want to accidentally leave it out. ```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:header}} {{#include ../assets/part2/unbricked.asm:header}} @@ -41,14 +41,14 @@ Speaking of tiles, we're going to load some into VRAM next, using the following {{#include ../assets/part2/unbricked.asm:copy_tiles}} ``` -This loop might be [reminiscent of part Ⅰ](../part1/jumps#conditional-jumps). +This loop might be [reminiscent of part Ⅰ](../part1/jumps.md#conditional-jumps). It copies `Tiles` to `$9000`, which is the part of VRAM where tiles are stored. To get how many bytes to copy, we will do just like in Part Ⅰ: using another label at the end, called `TilesEnd`, the difference between it (= the address after the last byte of tile data) and `Tiles` (= the address of the first byte) will be exactly that length. That said, we haven't written `Tiles` nor any of the related data yet. We'll get to that later! -Almost done now—next, write another loop, this time for copying [the tilemap](../part1/tilemap). +Almost done now—next, write another loop, this time for copying [the tilemap](../part1/tilemap.md). ```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:copy_map}} {{#include ../assets/part2/unbricked.asm:copy_map}} @@ -64,7 +64,7 @@ But there is more to them than meets the eye, so we will start tackling them muc ::: -Finally, let's turn the screen back on, and set a [background palette](../part1/palettes). +Finally, let's turn the screen back on, and set a [background palette](../part1/palettes.md). Rather than writing the non-descript number `%10000001` (or $81 or 129, to taste), we make use of two constants graciously provided by `hardware.inc`: `LCDCF_ON` and `LCDCF_BGON`. When written to [`rLCDC`](https://gbdev.io/pandocs/LCDC), the former causes the PPU and screen to turn back on, and the latter enables the background to be drawn. (There are other elements that could be drawn, but we are not enabling them yet.) @@ -77,12 +77,12 @@ Combining these constants must be done using `|`, the *binary "or"* operator; we There's one last thing we need before we can build the ROM, and that's the graphics. We will draw the following screen: -![Layout of unbricked](../assets/part2/tilemap.png) +![Layout of unbricked](../assets/part2/img/tilemap.png) In `hello-world.asm`, tile data had been written out by hand in hexadecimal; this was to let you see how the sausage is made at the lowest level, but *boy* is it impractical to write! This time, we will employ a more friendly way, which will let us write each row of pixels more easily. -We will use `dw` instead of `db` (the difference between these two will be explained later); and for each row of pixels, instead of writing [the bitplanes](../part1/tiles#encoding) as raw numbers, we will use a backtick (\`) followed by 8 characters. -Each character defines a single pixel, intuitively from left to right; it must be one of 0, 1, 2, and 3, representing the corresponding color index in [the palette](../part1/palettes). +We will use `dw` instead of `db` (the difference between these two will be explained later); and for each row of pixels, instead of writing [the bitplanes](../part1/tiles.md#encoding) as raw numbers, we will use a backtick (\`) followed by 8 characters. +Each character defines a single pixel, intuitively from left to right; it must be one of 0, 1, 2, and 3, representing the corresponding color index in [the palette](../part1/palettes.md). ::: tip From cc5464bffea4b543cf9e11dac50766b97aedbe1c Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Thu, 11 Aug 2022 23:26:43 +0200 Subject: [PATCH 08/19] Add link to explain what DRY is --- src/part2/getting-started.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 2aab2781..e120a37b 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -57,7 +57,7 @@ Almost done now—next, write another loop, this time for copying [the tilemap]( Note that while this loop's body is exactly the same as `CopyTiles`'s, the 3 values loaded into `de`, `hl`, and `bc` are different. These determine the source, destination, and size of the copy, respectively. -::: tip DRY +::: tip "[DRY](https://en.wikipedia.org/wiki/Don't_Repeat_Yourself)" If you think that this is super redundant, you are not wrong, and we will see later how to write actual, reusable *functions*. But there is more to them than meets the eye, so we will start tackling them much later. @@ -124,16 +124,19 @@ The logo tiles were left intentionally blank so that you can choose your own. You can use one of the following pre-made logos, or try coming up with your own! ## RGBDS Logo + ![The RGBDS Logo](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/rgbds.png?raw=true) [Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/rgbds.asm) ## Duck + ![A pixel-art duck](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/duck.png?raw=true) [Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/duck.asm) ## Tail + ![A silhouette of a tail](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/tail.png?raw=true) [Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tail.asm) From 1232301a2ddec620a5c393cc0ecdb11ff58e89de Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Thu, 11 Aug 2022 23:28:16 +0200 Subject: [PATCH 09/19] Make backtick character stand out more --- src/part2/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index e120a37b..64324977 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -81,7 +81,7 @@ We will draw the following screen: In `hello-world.asm`, tile data had been written out by hand in hexadecimal; this was to let you see how the sausage is made at the lowest level, but *boy* is it impractical to write! This time, we will employ a more friendly way, which will let us write each row of pixels more easily. -We will use `dw` instead of `db` (the difference between these two will be explained later); and for each row of pixels, instead of writing [the bitplanes](../part1/tiles.md#encoding) as raw numbers, we will use a backtick (\`) followed by 8 characters. +We will use `dw` instead of `db` (the difference between these two will be explained later); and for each row of pixels, instead of writing [the bitplanes](../part1/tiles.md#encoding) as raw numbers, we will use a backtick (`` ` ``) followed by 8 characters. Each character defines a single pixel, intuitively from left to right; it must be one of 0, 1, 2, and 3, representing the corresponding color index in [the palette](../part1/palettes.md). ::: tip From 5fdee28404d1f951ae82a9d1c0105395dbc709c1 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Fri, 12 Aug 2022 08:53:25 +0200 Subject: [PATCH 10/19] Move Unbricked source code to dedicated directory Place it outside of `src` so that it doesn't get served --- src/part2/getting-started.md | 28 +++++++++---------- .../getting-started/main.asm | 0 2 files changed, 14 insertions(+), 14 deletions(-) rename src/assets/part2/unbricked.asm => unbricked/getting-started/main.asm (100%) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 64324977..6f6fe8f3 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -8,8 +8,8 @@ Open a terminal and make a new directory (`mkdir unbricked`), and then enter it Start by creating a file called `main.asm`, and include `hardware.inc` in your code. -```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:includes}} -{{#include ../assets/part2/unbricked.asm:includes}} +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:includes}} +{{#include ../../unbricked/getting-started/main.asm:includes}} ``` `hardware.inc` is a file that provides constants which allow you to interface with the rest of the Game Boy. @@ -21,14 +21,14 @@ Numbers like this are difficult to memorize, and there are a *lot* to keep track Next, make room for the header. [Remember from Part Ⅰ](../part1/header.md) that the header is where some information that the Game Boy relies on is stored, so you don't want to accidentally leave it out. -```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:header}} -{{#include ../assets/part2/unbricked.asm:header}} +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:header}} +{{#include ../../unbricked/getting-started/main.asm:header}} ``` The header jumps to `EntryPoint`, so let's write that now: -```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:entry}} -{{#include ../assets/part2/unbricked.asm:entry}} +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:entry}} +{{#include ../../unbricked/getting-started/main.asm:entry}} ``` The next few lines wait until "VBlank", which is the only time you can safely turn off the screen (doing so at the wrong time could damage a real Game Boy, so this is very crucial). We'll talk more about VBlank later. @@ -37,8 +37,8 @@ Turning off the screen is important because loading new tiles while the screen i Speaking of tiles, we're going to load some into VRAM next, using the following code: -```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:copy_tiles}} -{{#include ../assets/part2/unbricked.asm:copy_tiles}} +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:copy_tiles}} +{{#include ../../unbricked/getting-started/main.asm:copy_tiles}} ``` This loop might be [reminiscent of part Ⅰ](../part1/jumps.md#conditional-jumps). @@ -50,8 +50,8 @@ We'll get to that later! Almost done now—next, write another loop, this time for copying [the tilemap](../part1/tilemap.md). -```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:copy_map}} -{{#include ../assets/part2/unbricked.asm:copy_map}} +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:copy_map}} +{{#include ../../unbricked/getting-started/main.asm:copy_map}} ``` Note that while this loop's body is exactly the same as `CopyTiles`'s, the 3 values loaded into `de`, `hl`, and `bc` are different. @@ -70,8 +70,8 @@ When written to [`rLCDC`](https://gbdev.io/pandocs/LCDC), the former causes the (There are other elements that could be drawn, but we are not enabling them yet.) Combining these constants must be done using `|`, the *binary "or"* operator; we'll see why later. -```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:end}} -{{#include ../assets/part2/unbricked.asm:end}} +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:end}} +{{#include ../../unbricked/getting-started/main.asm:end}} ``` There's one last thing we need before we can build the ROM, and that's the graphics. @@ -116,8 +116,8 @@ If you run this in your emulator, you should see the following: That white square seems to be missing! You may have noticed this comment earlier, somewhere in the tile data: -```rgbasm,linenos,start={{#line_no_of "" ../assets/part2/unbricked.asm:custom_logo}} -{{#include ../assets/part2/unbricked.asm:custom_logo}} +```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:custom_logo}} +{{#include ../../unbricked/getting-started/main.asm:custom_logo}} ``` The logo tiles were left intentionally blank so that you can choose your own. diff --git a/src/assets/part2/unbricked.asm b/unbricked/getting-started/main.asm similarity index 100% rename from src/assets/part2/unbricked.asm rename to unbricked/getting-started/main.asm From 55bc01f96611837f35e2b733e810e4edfde0c855 Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Fri, 12 Aug 2022 12:55:43 -0400 Subject: [PATCH 11/19] Add link to MMIO on wikipedia --- src/part2/getting-started.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index e7f428ba..58103844 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -18,6 +18,10 @@ To access other parts of the system, like the screen, buttons, or audio, you use These are different from the CPU registers in that they live within the address space, and are accessed through special numbers like `$FF40`. Numbers like this are difficult to memorize, and there are a *lot* to keep track of, which is why we use `hardware.inc` to assign them more freidnly names, like `rLCDC`. +::: tip + +This practice of accessing hardware through the address space is known as [Memory Mapped I/O (MMIO)](https://en.wikipedia.org/wiki/Memory-mapped_I/O) + Next, make room for the header. [Remember from Part Ⅰ](../part1/header) that the header is where some information that the Game Boy relies on is stored, so you don't want to accidentally leave it out. From 63ec34ebd431a299182be673455977645691098c Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Fri, 12 Aug 2022 12:58:35 -0400 Subject: [PATCH 12/19] Clarify the meaning of 000 --- src/part2/getting-started.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 58103844..7b587ea0 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -46,8 +46,9 @@ Speaking of tiles, we're going to load some into VRAM next, using the following ``` This loop might be [reminiscent of part Ⅰ](../part1/jumps#conditional-jumps). -It copies `Tiles` to `$9000`, which is the part of VRAM where tiles are stored. -To get how many bytes to copy, we will do just like in Part Ⅰ: using another label at the end, called `TilesEnd`, the difference between it (= the address after the last byte of tile data) and `Tiles` (= the address of the first byte) will be exactly that length. +It copies `Tiles` to `$9000`, which is the part of VRAM where our tiles are going to be stored. +`$9000` is the first background tile, so it's assigned an ID of 0, and every tile after it is just one ID higher. +To get the number of bytes to copy, we will do just like in Part Ⅰ: using another label at the end, called `TilesEnd`, the difference between it (= the address after the last byte of tile data) and `Tiles` (= the address of the first byte) will be exactly that length. That said, we haven't written `Tiles` nor any of the related data yet. We'll get to that later! From 188d2c3aab80e2496c62fb6fab47474836636298 Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Fri, 12 Aug 2022 13:02:02 -0400 Subject: [PATCH 13/19] Correct missing closing ::: --- src/part2/getting-started.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 8b3080c3..2a39e330 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -22,6 +22,8 @@ Numbers like this are difficult to memorize, and there are a *lot* to keep track This practice of accessing hardware through the address space is known as [Memory Mapped I/O (MMIO)](https://en.wikipedia.org/wiki/Memory-mapped_I/O) +::: + Next, make room for the header. [Remember from Part Ⅰ](../part1/header.md) that the header is where some information that the Game Boy relies on is stored, so you don't want to accidentally leave it out. From 32e4465f618e2b097d0d87daa56939f4a191df29 Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Fri, 12 Aug 2022 13:07:59 -0400 Subject: [PATCH 14/19] Add missing assets --- src/assets/part2/img/duck.png | Bin 0 -> 5195 bytes src/assets/part2/img/rgbds.png | Bin 0 -> 5220 bytes src/assets/part2/img/tail.png | Bin 0 -> 5258 bytes unbricked/2bpp2asm.c | 39 +++++++++ unbricked/getting-started/duck.asm | 128 ++++++++++++++++++++++++++++ unbricked/getting-started/rgbds.asm | 128 ++++++++++++++++++++++++++++ unbricked/getting-started/tail.asm | 128 ++++++++++++++++++++++++++++ unbricked/map2asm.c | 35 ++++++++ 8 files changed, 458 insertions(+) create mode 100644 src/assets/part2/img/duck.png create mode 100644 src/assets/part2/img/rgbds.png create mode 100644 src/assets/part2/img/tail.png create mode 100644 unbricked/2bpp2asm.c create mode 100644 unbricked/getting-started/duck.asm create mode 100644 unbricked/getting-started/rgbds.asm create mode 100644 unbricked/getting-started/tail.asm create mode 100644 unbricked/map2asm.c diff --git a/src/assets/part2/img/duck.png b/src/assets/part2/img/duck.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e3c8da0ef3dbc8a6fad82272d70b0bcf894a24 GIT binary patch literal 5195 zcmeHKXH-+!77jRwWDrMW6j33BQNS_DO(9K!V1N(>M7k)#O>zSvl_WrnZ!Ex!Aczz} zK*53qK|vG?7PRR8?Hj1{24he%xs)#uK`7-a8H9pV0zLwv z`s-N0a(T~O!{L^>d;`~R%dByxMST63w~FfW`O$5qdrE@E>#J`%vC^j$jSP!l=}((+ znHTJ3aW+JDC)~=~Pl+Q1_N5keX&bD|}jstvkZCibZ+txO1YpafbnbM5uSkhe{GC3h=Lj;a8EAS5MLC})0E+As&Ptjtx#u0O@=>jvc>KuvvV2{O&R2au9vbil_%|5-)#uvc zCYt6|e5fY_oWBfgk`Ky zA8@Tk1QNTGDT_mm&ZAP1vBo=(1~!IPQ!o7Lc;x37U9J_U&;MGJeCV-hM6CH$LwD+} z00d>J@x>#}mTP1Edc5S_2NjK{yKcE`J)?S*_r_tc!^9^w)b?Z-bAlPiZEnP$2U>O( zE%oWK3D3p8Gu?gO)F<}Z50?$3)*?4sMV9Dj!DGe6T&|~HpN}Z=+*Ysh`gH%5kjqHm zu$h1Gz1*S$ZhIq&i!1*qvTMGT8sSlR=RvM?mmmrA`ziEWx+|*EFS$K*$DDHh?v1|9{8}>3c%!_QhwE9(npvzTlvMQQ8BM=JrNoC|l~7|i0|_Y1xf>rmb} zxpcm;g|X)Hz6&~M7OVT4A`@Qvv70XM8yH}|=eh5wl$m#)A~T-NAFL}L(I1{<;BKP7 zR!}8{yF}uD7k)mfMY^7bW{j(5#5 zq%1hob=4v$7f4BQvI=U_&kS7hS`oeNQHMEaz|V0dP-}AAFa2gZ0-+NxU^2bfOyI*WML7A^FD>?pNAB_u|Ffp&CNBJD>YkHSWQm^s zf~mzu*v3=zlgQXE{e*&yjNM6F2CMd6N1u0o7~W0RPev1nt( z`yx}73&JUWGRvKxg|}u4R4Jva2M5(#yOwqIewYa!3&mGk8($;Tl_ydX_EW@h{SJ}w znNa57cB7#30__-J-^#-*NZYZmdqjcq!G7PT-svG0KMdyKNdR0 zwY`oTsd*+j)ZG)m&18}8FfOHk@;Keoj>UJWoflG?=sNGORcCe#wB%M_vF_VcGL@k_ z{>1vEMujB0{XD~Rn|%4pCX62Y@Q^W~aDkgz4*94(eYt8Om&QXca6sCt=rDj7 zQi3RzSR_%5s8%g<&ZV54y9I8>MlN?aV-H z?9+Ktu7F3^KH@E)N3n96V%a_XQMNqELboE~J5i z!Lb4uhfARGX*?c)A@T8442jAkV`u~pfZ-A$J_n-M@yUGB7Z6M20=Ozc(U)Fnpm;D8 zNFb7U6p)Vr$Yc(N1b`5RN+a_zTpFKDp%D2*fJ4(l@wjwXsay=g=@f{;FbF4;glQ)< zgwvh8*bFoQ3w$2&5`juStiV9K3nWph&lA1^G328JHEiO^b`%nshNn^i5{*b3HKfJ! zhvW*l5;d53081Rj)ue?E2LlreYU&gQ(89v8(3x@wR7&N(QmKf6)%n%eS4*^eg0 zO`w1!R%t4Jtmb{7$kDgaB_I-Lr%)(u+0sGos1XGi4e_*wV7<{PZa63jgW&Z&R!|?u z1^)dNPVBV; zU$g;OZ*&Z9FL1ZQeQH-@oM~wM7e8aU_!lj}(BF-G6Tjc-`cBt3G4M^o->d68UEjpO zHwk~QuKycd$j=8JNCN*0ih++a^%JD=@KMM>=C(|MK>RpGbLk**x0}L)`bxHki~a+B z9@#_`XH}hMLjdyz6EY3@f zt4nWd(D5*7SY36`WV)xC)fwD6Zp%uvmG#3m)P`pDy4McYy|XD-&GCs-wukJ@;FYIc w-;>$U$=x`(aJlf1{@=KSQu?*-AG*~#`HqZLWsWZJ5fFi3yLdX6EDVkPFT|VkZ2$lO literal 0 HcmV?d00001 diff --git a/src/assets/part2/img/rgbds.png b/src/assets/part2/img/rgbds.png new file mode 100644 index 0000000000000000000000000000000000000000..349d362ebb458c0426d007c3e73254145524bc0c GIT binary patch literal 5220 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 literal 0 HcmV?d00001 diff --git a/src/assets/part2/img/tail.png b/src/assets/part2/img/tail.png new file mode 100644 index 0000000000000000000000000000000000000000..fc36eaba7e2981313675f7365d0d2f567a9e82cb GIT binary patch literal 5258 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 +#include +#include + +int main(int argc, char ** argv) { + if (argc != 4) { + fprintf(stderr, "Expected 4 arguments\nUsage: %s ", argv[0]); + exit(1); + } + + FILE * infile = fopen(argv[2], "rb"); + FILE * outfile = fopen(argv[3], "w"); + + if (!infile) { + perror("infile"); + exit(1); + } + + if (!outfile) { + perror("outfile"); + exit(1); + } + + char * pixels = argv[1]; + + while (1) { + uint8_t light_row = fgetc(infile); + uint8_t dark_row = fgetc(infile); + if (feof(infile)) break; + fputs("\tdw `", outfile); + for (int i = 0; i < 8; i++) { + uint8_t shade = (light_row & 0x80) >> 7 | (dark_row & 0x80) >> 6; + fputc(pixels[shade], outfile); + light_row <<= 1; + dark_row <<= 1; + } + fputc('\n', outfile); + } +} \ No newline at end of file diff --git a/unbricked/getting-started/duck.asm b/unbricked/getting-started/duck.asm new file mode 100644 index 00000000..b34d1c30 --- /dev/null +++ b/unbricked/getting-started/duck.asm @@ -0,0 +1,128 @@ + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222211 + dw `22222211 + dw `22222211 + dw `22222222 + dw `22222222 + dw `22222222 + dw `11111111 + dw `11111111 + dw `11221111 + dw `11221111 + dw `11000011 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `11222222 + dw `11222222 + dw `11222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222211 + dw `22222200 + dw `22222200 + dw `22000000 + dw `22000000 + dw `22222222 + dw `22222222 + dw `22222222 + dw `11000011 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11000022 + dw `11222222 + dw `11222222 + dw `11222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222200 + dw `22222200 + dw `22222211 + dw `22222211 + dw `22221111 + dw `22221111 + dw `22221111 + dw `11000022 + dw `00112222 + dw `00112222 + dw `11112200 + dw `11112200 + dw `11220000 + dw `11220000 + dw `11220000 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22000000 + dw `22000000 + dw `00000000 + dw `00000000 + dw `00000000 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `22222222 + dw `11110022 + dw `11110022 + dw `11110022 + dw `22221111 + dw `22221111 + dw `22221111 + dw `22221111 + dw `22221111 + dw `22222211 + dw `22222211 + dw `22222222 + dw `11220000 + dw `11110000 + dw `11110000 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `22222222 + dw `00000000 + dw `00111111 + dw `00111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `22222222 + dw `11110022 + dw `11000022 + dw `11000022 + dw `00002222 + dw `00002222 + dw `00222222 + dw `00222222 + dw `22222222 diff --git a/unbricked/getting-started/rgbds.asm b/unbricked/getting-started/rgbds.asm new file mode 100644 index 00000000..4039921f --- /dev/null +++ b/unbricked/getting-started/rgbds.asm @@ -0,0 +1,128 @@ + dw `33000000 + dw `33000000 + dw `33000000 + dw `33000000 + dw `33111100 + dw `33111100 + dw `33111111 + dw `33111111 + dw `33331111 + dw `00331111 + dw `00331111 + dw `00331111 + dw `00331111 + dw `00331111 + dw `11331111 + dw `11331111 + dw `11333300 + dw `11113300 + dw `11113300 + dw `11113300 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `00003333 + dw `00000033 + dw `00000033 + dw `00000033 + dw `11000033 + dw `11000033 + dw `11111133 + dw `11111133 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11113311 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `33111111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11331111 + dw `11330000 + dw `11330000 + dw `11330000 + dw `33330000 + dw `11113311 + dw `11113311 + dw `00003311 + dw `00003311 + dw `00003311 + dw `00003311 + dw `00003311 + dw `00333311 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11111133 + dw `11113333 diff --git a/unbricked/getting-started/tail.asm b/unbricked/getting-started/tail.asm new file mode 100644 index 00000000..286fc332 --- /dev/null +++ b/unbricked/getting-started/tail.asm @@ -0,0 +1,128 @@ + 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 diff --git a/unbricked/map2asm.c b/unbricked/map2asm.c new file mode 100644 index 00000000..b887180f --- /dev/null +++ b/unbricked/map2asm.c @@ -0,0 +1,35 @@ +#include +#include +#include + +int main(int argc, char ** argv) { + if (argc != 4) { + fprintf(stderr, "Expected 4 arguments\nUsage: %s ", argv[0]); + exit(1); + } + + FILE * infile = fopen(argv[1], "rb"); + FILE * outfile = fopen(argv[2], "w"); + + if (!infile) { + perror("infile"); + exit(1); + } + + if (!outfile) { + perror("outfile"); + exit(1); + } + + char * pixels = argv[1]; + + while (1) { + fputs("\tdb ", outfile); + for (int i = 0; i < 20; i++) { + int byte = fgetc(infile); + if (byte == EOF) exit(0); + fprintf(outfile, "$%X, ", byte); + } + fputs("0,0,0,0,0,0,0,0,0,0,0,0\n", outfile); + } +} From 05985ca0c0a9f1de4e954eb89af9add7b63f8568 Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Fri, 12 Aug 2022 13:10:33 -0400 Subject: [PATCH 15/19] Update references to local assets --- src/part2/getting-started.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 2a39e330..e3850ac8 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -132,20 +132,20 @@ You can use one of the following pre-made logos, or try coming up with your own! ## RGBDS Logo -![The RGBDS Logo](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/rgbds.png?raw=true) +![The RGBDS Logo](../assets/part2/rgbds.png) -[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/rgbds.asm) +[Source](../../unbricked/getting-started/rgbds.asm) ## Duck -![A pixel-art duck](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/duck.png?raw=true) +![A pixel-art duck](../assets/part2/duck.png) -[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/duck.asm) +[Source](../../unbricked/getting-started/duck.asm) ## Tail -![A silhouette of a tail](https://github.com/ISSOtm/gb-asm-tutorial-part2/blob/main/tail.png?raw=true) +![A silhouette of a tail](../assets/part2/tail.png) -[Source](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tail.asm) +[Source](../../unbricked/getting-started/tail.asm) Replace the blank tiles with the new graphics, build the game again, and you should see your logo of choice in the bottom-right! From e5050ae5eabdd4efdaf9b04c29b48ff2a0b2a1b8 Mon Sep 17 00:00:00 2001 From: Eievui <14899090+eievui5@users.noreply.github.com> Date: Fri, 12 Aug 2022 13:17:43 -0400 Subject: [PATCH 16/19] Add tileset.asm and tilemap.asm --- src/part2/getting-started.md | 4 +- unbricked/getting-started/tilemap.asm | 20 +++++++ unbricked/getting-started/tileset.asm | 84 +++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 unbricked/getting-started/tilemap.asm create mode 100644 unbricked/getting-started/tileset.asm diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index e3850ac8..053b07ee 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -104,9 +104,9 @@ For example: dw `01230123 ; This is equivalent to `db $55,$33` ``` -We already have tiles made for this project, so you can copy [this premade file](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tileset.asm), and paste it at the end of your code. +We already have tiles made for this project, so you can copy [this premade file](../../unbricked/getting-started/tileset.asm), and paste it at the end of your code. -Then copy the tilemap from [this file](https://github.com/ISSOtm/gb-asm-tutorial-part2/raw/main/tilemap.asm), and paste it after the `TilesEnd` label. +Then copy the tilemap from [this file](../../unbricked/getting-started/tilemap.asm), and paste it after the `TilesEnd` label. You can build the ROM now, by running the following commands in your terminal: diff --git a/unbricked/getting-started/tilemap.asm b/unbricked/getting-started/tilemap.asm new file mode 100644 index 00000000..42afef99 --- /dev/null +++ b/unbricked/getting-started/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, $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: diff --git a/unbricked/getting-started/tileset.asm b/unbricked/getting-started/tileset.asm new file mode 100644 index 00000000..98d7ee9d --- /dev/null +++ b/unbricked/getting-started/tileset.asm @@ -0,0 +1,84 @@ +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 + ; Paste your logo here: + +TilesEnd: From 537c308bab6bb84e83c4841c329a4c00209512d4 Mon Sep 17 00:00:00 2001 From: Evie M <14899090+eievui5@users.noreply.github.com> Date: Fri, 12 Aug 2022 14:43:26 -0400 Subject: [PATCH 17/19] Apply suggestions from code review Co-authored-by: Eldred Habert --- src/part2/getting-started.md | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 053b07ee..e6a9f296 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -2,7 +2,7 @@ In this lesson, we will start a new project from scratch. We will make a [Breakout](https://en.wikipedia.org/wiki/Breakout_%28video_game%29) / [Arkanoid](https://en.wikipedia.org/wiki/Arkanoid) clone, which we'll call "Unbricked"! -(Though you are free to give it any other name you like, as it will be *your* project) +(Though you are free to give it any other name you like, as it will be *your* project.) Open a terminal and make a new directory (`mkdir unbricked`), and then enter it (`cd unbricked`), just like you did for ["Hello, world!"](../part1/hello_world.md). @@ -37,7 +37,8 @@ The header jumps to `EntryPoint`, so let's write that now: {{#include ../../unbricked/getting-started/main.asm:entry}} ``` -The next few lines wait until "VBlank", which is the only time you can safely turn off the screen (doing so at the wrong time could damage a real Game Boy, so this is very crucial). We'll talk more about VBlank later. +The next few lines wait until "VBlank", which is the only time you can safely turn off the screen (doing so at the wrong time could damage a real Game Boy, so this is very crucial). +We'll explain what VBlank is and talk about it more later in the tutorial. Turning off the screen is important because loading new tiles while the screen is on is tricky—we'll touch on how to do that in Part 3. @@ -48,7 +49,7 @@ Speaking of tiles, we're going to load some into VRAM next, using the following ``` This loop might be [reminiscent of part Ⅰ](../part1/jumps#conditional-jumps). -It copies `Tiles` to `$9000`, which is the part of VRAM where our tiles are going to be stored. +It copies starting at `Tiles` to `$9000` onwards, which is the part of VRAM where our [tiles](../part1/tiles.md) are going to be stored. `$9000` is the first background tile, so it's assigned an ID of 0, and every tile after it is just one ID higher. To get the number of bytes to copy, we will do just like in Part Ⅰ: using another label at the end, called `TilesEnd`, the difference between it (= the address after the last byte of tile data) and `Tiles` (= the address of the first byte) will be exactly that length. @@ -88,13 +89,13 @@ We will draw the following screen: In `hello-world.asm`, tile data had been written out by hand in hexadecimal; this was to let you see how the sausage is made at the lowest level, but *boy* is it impractical to write! This time, we will employ a more friendly way, which will let us write each row of pixels more easily. -We will use `dw` instead of `db` (the difference between these two will be explained later); and for each row of pixels, instead of writing [the bitplanes](../part1/tiles.md#encoding) as raw numbers, we will use a backtick (`` ` ``) followed by 8 characters. +For each row of pixels, instead of writing [the bitplanes](../part1/tiles.md#encoding) directly, we will use a backtick (`` ` ``) followed by 8 characters. Each character defines a single pixel, intuitively from left to right; it must be one of 0, 1, 2, and 3, representing the corresponding color index in [the palette](../part1/palettes.md). ::: tip -0, 1, 2, and 3 aren't the only options for writing graphics. -You can use [`OPT g`](https://rgbds.gbdev.io/docs/v0.5.2/rgbasm.5/#Changing_options_while_assembling) to modify these characters to your liking. +If the character selection isn't to your liking, you can use [RGBASM's `-g` option](https://rgbds.gbdev.io/docs/v0.5.2/rgbasm.1#g) or [`OPT g`](https://rgbds.gbdev.io/docs/v0.5.2/rgbasm.5/#Changing_options_while_assembling) to pick others. +For example, `rgbasm -g '.xXO' (...)` or `OPT g.xXO` would swap the four characters to `.`, `x`, `X`, and `O` respectively. ::: @@ -104,6 +105,7 @@ For example: dw `01230123 ; This is equivalent to `db $55,$33` ``` +You may have noticed that we are using `dw` instead of `db`; the difference between these two will be explained later. We already have tiles made for this project, so you can copy [this premade file](../../unbricked/getting-started/tileset.asm), and paste it at the end of your code. Then copy the tilemap from [this file](../../unbricked/getting-started/tilemap.asm), and paste it after the `TilesEnd` label. @@ -130,22 +132,22 @@ You may have noticed this comment earlier, somewhere in the tile data: The logo tiles were left intentionally blank so that you can choose your own. You can use one of the following pre-made logos, or try coming up with your own! -## RGBDS Logo +- **RGBDS Logo** -![The RGBDS Logo](../assets/part2/rgbds.png) + ![The RGBDS Logo](../assets/part2/rgbds.png) -[Source](../../unbricked/getting-started/rgbds.asm) + [Source](../../unbricked/getting-started/rgbds.asm) -## Duck +- **Duck** -![A pixel-art duck](../assets/part2/duck.png) + ![A pixel-art duck](../assets/part2/duck.png) -[Source](../../unbricked/getting-started/duck.asm) + [Source](../../unbricked/getting-started/duck.asm) -## Tail +- **Tail** -![A silhouette of a tail](../assets/part2/tail.png) + ![A silhouette of a tail](../assets/part2/tail.png) -[Source](../../unbricked/getting-started/tail.asm) + [Source](../../unbricked/getting-started/tail.asm) Replace the blank tiles with the new graphics, build the game again, and you should see your logo of choice in the bottom-right! From 3cc665a182032e0c71201762c2465312d32db887 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Sat, 13 Aug 2022 09:37:09 +0200 Subject: [PATCH 18/19] Apply suggestions from code review --- src/part2/getting-started.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index e6a9f296..4ea7b2d3 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -11,16 +11,21 @@ Start by creating a file called `main.asm`, and include `hardware.inc` in your c ```rgbasm,linenos,start={{#line_no_of "" ../../unbricked/getting-started/main.asm:includes}} {{#include ../../unbricked/getting-started/main.asm:includes}} ``` +You may be wondering what purpose `hardware.inc` serves. +Well, the code we write only really affects the CPU, but does not do anything with the rest of the console (not directly, anyway). +To interact with other components (like the graphics system, say), [Memory-Mapped I/O](https://en.wikipedia.org/wiki/Memory-mapped_I/O) (MMIO) is used: basically, [memory](../part1/memory.md) in a certain range (addresses $FF00–FF7F) does special things when accessed. -`hardware.inc` is a file that provides constants which allow you to interface with the rest of the Game Boy. -When you write code, your instructions are only read by the CPU. -To access other parts of the system, like the screen, buttons, or audio, you use special registers known as "I/O" registers. -These are different from the CPU registers in that they live within the address space, and are accessed through special numbers like `$FF40`. -Numbers like this are difficult to memorize, and there are a *lot* to keep track of, which is why we use `hardware.inc` to assign them more freidnly names, like `rLCDC`. +These bytes of memory being interfaces to the hardware, they are called *hardware registers* (not to be mistaken with [the CPU registers](../part1/registers.md)). +For example, the "PPU status" register is located at address $FF41. +Reading from that address reports various bits of info regarding the graphics system, and writing to it allows changing some parameters. +But, having to remember all the numbers ([non-exhaustive list](https://gbdev.io/pandocs/Power_Up_Sequence.html#hardware-registers)) would be very tedious—and this is where `hardware.inc` comes into play! +`hardware.inc` defines one constant for each of these registers (for example, `rSTAT` for the aforementioned "PPU status" register), plus some additional constants for values read from or written to these registers. ::: tip -This practice of accessing hardware through the address space is known as [Memory Mapped I/O (MMIO)](https://en.wikipedia.org/wiki/Memory-mapped_I/O) +Don't worry if this flew over your head, we'll see an example below with `rLCDC` and `LCDCF_ON`. + +By the way, the `r` stands for "register", and the `F` in `LCDCF` stands for "flag". ::: @@ -50,7 +55,7 @@ Speaking of tiles, we're going to load some into VRAM next, using the following This loop might be [reminiscent of part Ⅰ](../part1/jumps#conditional-jumps). It copies starting at `Tiles` to `$9000` onwards, which is the part of VRAM where our [tiles](../part1/tiles.md) are going to be stored. -`$9000` is the first background tile, so it's assigned an ID of 0, and every tile after it is just one ID higher. +Recall that `$9000` is where the data of background tile $00 lies, and the data of subsequent tiles follows right after. To get the number of bytes to copy, we will do just like in Part Ⅰ: using another label at the end, called `TilesEnd`, the difference between it (= the address after the last byte of tile data) and `Tiles` (= the address of the first byte) will be exactly that length. That said, we haven't written `Tiles` nor any of the related data yet. From d3ca446ecb8c560d6e6cb49420d9b4bcbc9d87a4 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Sat, 13 Aug 2022 09:47:15 +0200 Subject: [PATCH 19/19] Fix broken links --- book.toml | 2 +- src/part2/getting-started.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/book.toml b/book.toml index 7f28386c..352546f3 100644 --- a/book.toml +++ b/book.toml @@ -35,5 +35,5 @@ edit-url-template = "https://github.com/ISSOtm/gb-asm-tutorial/edit/master/{path site-url = "/gb-asm-tutorial/" [output.linkcheck] -traverse-parent-directories = false +traverse-parent-directories = true # We intentionally read some files outside of `src/` optional = true diff --git a/src/part2/getting-started.md b/src/part2/getting-started.md index 4ea7b2d3..c59a7f94 100644 --- a/src/part2/getting-started.md +++ b/src/part2/getting-started.md @@ -53,7 +53,7 @@ Speaking of tiles, we're going to load some into VRAM next, using the following {{#include ../../unbricked/getting-started/main.asm:copy_tiles}} ``` -This loop might be [reminiscent of part Ⅰ](../part1/jumps#conditional-jumps). +This loop might be [reminiscent of part Ⅰ](../part1/jumps.md#conditional-jumps). It copies starting at `Tiles` to `$9000` onwards, which is the part of VRAM where our [tiles](../part1/tiles.md) are going to be stored. Recall that `$9000` is where the data of background tile $00 lies, and the data of subsequent tiles follows right after. To get the number of bytes to copy, we will do just like in Part Ⅰ: using another label at the end, called `TilesEnd`, the difference between it (= the address after the last byte of tile data) and `Tiles` (= the address of the first byte) will be exactly that length. @@ -139,19 +139,19 @@ You can use one of the following pre-made logos, or try coming up with your own! - **RGBDS Logo** - ![The RGBDS Logo](../assets/part2/rgbds.png) + ![The RGBDS Logo](../assets/part2/img/rgbds.png) [Source](../../unbricked/getting-started/rgbds.asm) - **Duck** - ![A pixel-art duck](../assets/part2/duck.png) + ![A pixel-art duck](../assets/part2/img/duck.png) [Source](../../unbricked/getting-started/duck.asm) - **Tail** - ![A silhouette of a tail](../assets/part2/tail.png) + ![A silhouette of a tail](../assets/part2/img/tail.png) [Source](../../unbricked/getting-started/tail.asm)