Monorepo for Aesthetic.Computer
aesthetic.computer
1; Sprite Example for the Nintendo Game Boy
2; by Dave VanEe 2022
3; Tested with RGBDS 1.0.0
4; License: CC0 (https://creativecommons.org/publicdomain/zero/1.0/)
5
6include "hardware.inc" ; Include hardware definitions so we can use nice names for things
7
8; Define a section that starts at the point the bootrom execution ends
9SECTION "Start", ROM0[$0100]
10 jp EntryPoint ; Jump past the header space to our actual code
11
12 ds $150-@, 0 ; Allocate space for RGBFIX to insert our ROM header by allocating
13 ; the number of bytes from our current location (@) to the end of the
14 ; header ($150)
15
16EntryPoint:
17 di ; Disable interrupts as we won't be using them
18 ld sp, $e000 ; Set the stack pointer to the end of WRAM
19
20 ; Turn off the LCD when it's safe to do so (during VBlank)
21.waitVBlank
22 ldh a, [rLY] ; Read the LY register to check the current scanline
23 cp SCREEN_HEIGHT_PX ; Compare the current scanline to the first scanline of VBlank
24 jr c, .waitVBlank ; Loop as long as the carry flag is set
25 ld a, 0 ; Once we exit the loop we're safely in VBlank
26 ldh [rLCDC], a ; Disable the LCD (must be done during VBlank to protect the LCD)
27
28 ; Copy our tile to VRAM
29 ld hl, TileData ; Load the source address of our tiles into HL
30 ld de, STARTOF(VRAM); Load the destination address in VRAM into DE
31 ld b, 16 ; Load the number of bytes to copy into B (16 bytes per tile)
32.copyLoop
33 ld a, [hl] ; Load a byte from the address HL points to into the register A
34 ld [de], a ; Load the byte in the A register to the address DE points to
35 inc hl ; Increment the source pointer in HL
36 inc de ; Increment the destination pointer in DE
37 dec b ; Decrement the loop counter in B
38 jr nz, .copyLoop ; If B isn't zero, continue looping
39
40 ; Setup the two object palettes
41 ld a, %11100100 ; Define a 4-shade palette from darkest (11) to lightest (00)
42 ldh [rOBP0], a ; Set the onject palette 0
43 ld a, %00011011 ; Define a 4-shade palette from lightest (00) to darkest (11)
44 ldh [rOBP1], a ; Set the onject palette 1
45
46 ; Set the attributes for a two sprites in OAMRAM
47 ld hl, STARTOF(OAM) ; Load the destination address in OAM into HL
48
49 ; The first sprite is in the top-left corner of the screen and uses the "normal" palette
50 ld a, 16 ; Load the value 16 into the A register
51 ld [hli], a ; Set the Y coordinate (plus 16) for the sprite in OAMRAM, increment HL
52 sub 8 ; Subtract 8 from the value stored in A and store the result in A
53 ld [hli], a ; Set the X coordinate (plus 8) for the sprite in OAMRAM, increment HL
54 ld a, 0 ; Load the tile index 0 into the A register
55 ld [hli], a ; Set the tile index for the sprite in OAMRAM, increment HL
56 ld [hli], a ; Set the attributes (flips and palette) for the sprite in OAMRAM, increment HL
57
58 ; The second sprite is shifted slightly and uses the "inverted" palette
59 ld a, 19 ; Load the value 19 into the A register
60 ld [hli], a ; Set the Y coordinate (plus 16) for the sprite in OAMRAM, increment HL
61 sub 6 ; Subtract 6 from the value stored in A and store the result in A
62 ld [hli], a ; Set the X coordinate (plus 8) for the sprite in OAMRAM, increment HL
63 ld a, 0 ; Load the tile index 0 into the A register
64 ld [hli], a ; Set the tile index for the sprite in OAMRAM, increment HL
65 ld a, OAM_YFLIP | OAM_PAL1 ; Load the flags to Y flip and use OBP1 for this sprite into A
66 ld [hli], a ; Set the attributes (flips and palette) for the sprite in OAMRAM, increment HL
67
68 ; Zero the Y coordinates of the remaining entries to avoid garbage sprites
69 xor a ; XOR A with itself, which sets A to zero (and affects the flags)
70 ; Note: This is 1 cycle faster and 1 byte smaller than `ld a, 0`
71 ld b, OAM_COUNT - 2 ; Load B with the number of loops, which is the total OAM count minus one
72.oamClearLoop
73 ld [hli], a ; Set the Y coordinate of this entry to zero, increment HL
74 inc l ; Increment L to advance HL (three times)
75 inc l ; Note: Since OAMRAM is from $FE00->$FE9F we can safely increment
76 inc l ; only the L register and HL will stay a valid pointer
77 dec b ; Decrement the loop counter in B
78 jr nz, .oamClearLoop; If B isn't zero, continue looping
79
80 ; Combine flag constants defined in hardware.inc into a single value with logical ORs and load it into A
81 ; Note that some of these constants (LCDC_BG_OFF, LCDC_OBJ_8, LCDC_WIN_OFF) are zero, but are included for clarity
82 ld a, LCDC_ON | LCDC_BG_OFF | LCDC_OBJ_8 | LCDC_OBJ_ON | LCDC_WIN_OFF
83 ldh [rLCDC], a ; Enable and configure the LCD to show the background
84
85LoopForever:
86 jr LoopForever ; Loop forever
87
88; Our tile data in 2bpp planar format (https://gbdev.io/pandocs/Tile_Data.html)
89TileData:
90.ball ; For the ball tile we'll use a more verbose syntax so you can see how the tile is built
91 ; low byte high byte
92 db %00111100, %00111100 ; single row of 8 pixels
93 db %01011110, %01000010
94 db %10001101, %10000011
95 db %11011101, %10000011
96 db %11111101, %10000011
97 db %10111001, %11000111
98 db %01000010, %01111110
99 db %00111100, %00111100
100