Skip to content

Commit

Permalink
updating backgrounds
Browse files Browse the repository at this point in the history
finishing object pools
removing sprites ad metasprites from gameplay
starting on player
adding object pool labels
  • Loading branch information
LaroldsJubilantJunkyard committed Dec 10, 2023
1 parent 2287d1f commit 3d72f44
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 52 deletions.
3 changes: 3 additions & 0 deletions galactic-armada/src/main/includes/constants.inc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ DEF MAX_OBJECT_COUNT EQU 16

DEF ENEMY_SPAWN_DELAY_MAX EQU 70

;ANCHOR: object-bytes

; from https://rgbds.gbdev.io/docs/v0.6.1/rgbasm.5#EXPRESSIONS
; The RS group of commands is a handy way of defining structure offsets:
RSRESET
Expand All @@ -21,6 +23,7 @@ DEF object_updateLowByte RB 1
DEF object_updateHighByte RB 1
DEF object_damageByte RB 1
DEF PER_OBJECT_BYTES_COUNT RB 0
;ANCHOR_END: object-bytes

RSRESET
DEF PLAYER_START RB PER_OBJECT_BYTES_COUNT
Expand Down
5 changes: 4 additions & 1 deletion galactic-armada/src/main/states/gameplay/objects/bullets.asm
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ FireNextBullet::
; if the zero flag is set, stop early
call GetNextAvailableObject_InHL
ret z
; ANCHOR_END: fire-bullets

; ANCHOR: fire-bullets2
ld a, 1
ld [hli], a

Expand Down Expand Up @@ -83,4 +85,5 @@ FireNextBullet::
ld [hli], a


ret
ret
; ANCHOR_END: fire-bullets2
50 changes: 31 additions & 19 deletions galactic-armada/src/main/states/gameplay/objects/object-pool.asm
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

; ANCHOR: bullets-top
; ANCHOR: objects-pool-top
include "src/main/includes/hardware.inc"
include "src/main/includes/constants.inc"

Expand All @@ -11,6 +10,9 @@ wObjectsFlash:: db

SECTION "Objects", ROM0

; ANCHOR_END: objects-pool-top

; ANCHOR: initialize-objects
InitializeObjectPool::

; The active byte will awlays be 0 or 1
Expand Down Expand Up @@ -40,16 +42,20 @@ InitializeObjectPool_Loop:

ld b, a
jp InitializeObjectPool_Loop
; ANCHOR_END: initialize-objects

; ANCHOR: update-objects-1
UpdateObjectPool::

; Increase our flash
ld a, [wObjectsFlash]
add a,25
ld [wObjectsFlash], a
; ANCHOR_END: update-objects-1

ld hl, wObjects
; ANCHOR: update-objects-2

ld hl, wObjects

UpdateObjectPool_Loop:

Expand All @@ -61,8 +67,11 @@ UpdateObjectPool_Loop:

; Check if the object is active
and a
jp z, UpdateObjectPool_InActiveObject
jp z, UpdateObjectPool_GoToNextObject

; ANCHOR_END: update-objects-2

; ANCHOR: update-objects-3
.UpdateObject
push hl
Expand All @@ -87,8 +96,10 @@ UpdateObjectPool_Loop:
; Check if we're inactive after updating
ld a, [hl]
and a
jp z , UpdateObjectPool_InActiveObject
jp z , UpdateObjectPool_GoToNextObject
; ANCHOR_END: update-objects-3

; ANCHOR: update-objects-4
.CheckIsDamaged

push hl
Expand All @@ -103,11 +114,6 @@ UpdateObjectPool_Loop:
jp z, NotDamaged
jp Damaged

NotDamaged:

pop hl
jp z, GetXAndY

Damaged:

; decrease our damage byte
Expand All @@ -120,8 +126,15 @@ Damaged:
ld a, [wObjectsFlash]
cp a, 128

jp c, UpdateObjectPool_InActiveObject
jp c, UpdateObjectPool_GoToNextObject

NotDamaged:

pop hl
jp z, GetXAndY
; ANCHOR_END: update-objects-4

; ANCHOR: update-objects-5
GetXAndY:

push hl
Expand Down Expand Up @@ -151,19 +164,18 @@ GetXAndY:

pop hl

jp UpdateObjectPool_InActiveObject

UpdateObjectPool_DeactivateObject:



UpdateObjectPool_InActiveObject:
jp UpdateObjectPool_GoToNextObject
; ANCHOR_END: update-objects-5
; ANCHOR: update-objects-6
UpdateObjectPool_GoToNextObject:

ld de, PER_OBJECT_BYTES_COUNT
add hl, de

jp UpdateObjectPool_Loop
; ANCHOR_END: update-objects-6

; ANCHOR: get-next-available-object
; parameters
; hl = start of array bytes
; b = number of objects to check
Expand Down Expand Up @@ -201,4 +213,4 @@ GetNextAvailableObject_End:
ld a, 0
and a
ret;
; ANCHOR_END: fire-bullets
; ANCHOR_END: get-next-available-object
8 changes: 1 addition & 7 deletions galactic-armada/src/main/states/gameplay/objects/player.asm
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,9 @@
include "src/main/includes/hardware.inc"
include "src/main/includes/constants.inc"

SECTION "PlayerVariables", WRAM0

mPlayerFlash: dw
; ANCHOR_END: player-start
; ANCHOR: player-data
SECTION "Player", ROM0

; ANCHOR_END: player-data

; ANCHOR_END: player-start
; ANCHOR: player-initialize
InitializePlayer::

Expand Down
1 change: 0 additions & 1 deletion src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
- [Story Screen](part3/story-screen.md)
- [Gameplay](part3/gameplay.md)
- [Object Pools](part3/object-pools.md)
- [Sprites & Metasprites](part3/sprites-metasprites.md)
- [Scrolling Background](part3/scrolling-background.md)
- [Heads-Up Interface](part3/heads-up-interface.md)
- [The Player](part3/the-player.md)
Expand Down
132 changes: 109 additions & 23 deletions src/part3/object-pools.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,128 @@
# Object Pools

Galactic Armada will use "object pools" for bullets and enemies. A fixed amount of bytes representing a specific maximum amount of objects. Each pool is just a collection of bytes. The number of bytes per “pool” is the maximum number of objects in the pool, times the number of bytes needed for data for each object.
Galactic Armada will use a single "object pool" for all obejcts (the player, enemies, and bullets). This pool repsents an array of objects, but is realy just a collection of bytes. Each object has the same number of bytes allocated for it.

Constants are also created for the size of each object, and what each byte is. These constants are in the “src/main/utils/constants.inc” file and utilize RGBDS offset constants (a really cool feature)
- Active (1 byte)
- Y Position (2 bytes)
- X Position (2 bytes)
- Metasprite address (2 bytes)
- Health (1 byte)
- Update function address (2 bytes)
- Damage Timer (1 byte)

We've pre-defined that in the starter.

The two object types that we need to loop through are Enemies and Bullets.
*inside of our `constants.inc` include file:*

**Bytes for an Enemy:**
```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/includes/constants.inc:object-bytes}}
{{#include ../../galactic-armada/src/main/includes/constants.inc:object-bytes}}
```

1. Active - Are they active
2. X - Position: horizontal coordinate
3. Y (low) - The lower byte of their 16-bit (scaled) y position
4. Y (high) - The higher byte of their 16-bit (scaled) y position
5. Speed - How fast they move
6. Health - How many bullets they can take
We need to next setup and implement variables that use that structure.

**Create a file called `object-pool.asm`, add the following code to it:**

![EnemyBytesVisualized.png](../assets/part3/img/EnemyBytesVisualized.png)
```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:objects-pool-top}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:objects-pool-top}}
```

**Bytes for a Bullet:**
We'll explain each variable soon, but notice how we allocated space in WRAM for `wObjects`. Rather than using a literal number for how many objects our game can handle, we use the constant `MAX_OBJECT_COUNT`. This constant is declared in `constants.inc`, and prevents any sort of inconsistincies if we change our minds.

1. Active - Are they active
2. X - Position: horizontal coordinate
3. Y (low) - The lower byte of their 16-bit (scaled) y position
4. Y (high) - The higher byte of their 16-bit (scaled) y position
## Initializing the object pool

When we initialize the object pool, we need to do 2 primary things:
- Set all bytes in the pool to 0
- Set our `wObjectsEnd` variable to 255

![BulletBytesVisualized.png](../assets/part3/img/BulletBytesVisualized.png)
Our `wObjectsEnd` variable is used to simplify looping through all objects. More on that later.

> ⚠️ **NOTE:** Scaled integers are used for only the y positions of bullets and enemies. Scaled Integers are a way to provide smooth “sub-pixel” movement. They only move vertically, so the x position can be 8-bit.
**Add the following code to the bottom of your `object-pool.asm` file:**

When looping through an object pool, we’ll check if an object is active. If it’s active, we’ll run the logic for that object. Otherwise, we’ll skip to the start of the next object’s bytes.
```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:initialize-objects}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:initialize-objects}}
```

Both bullets and enemies do similar things. They move vertically until they are off the screen. In addition, enemies will check against bullets when updating. If they are found to be colliding, the bullet is destroyed and so is the enemy.
The above code is just going to loop through each object, and set all of it's bytes to 0.

# “Activating” a pooled object
## Updating objects in our object pool

To Activate a pooled object, we simply loop through each object. If the first byte, which tells us if it’s active or not, is 0: then we’ll add the new item at that location and set that byte to be 1. If we loop through all possible objects and nothing is inactive, nothing happens.
We've created a variable called `wObjectsFlash`. This will be used as a counter. We'll increase it each frame. Because it's a a unsigned 8-bit integer, it's values will be between 0 and 255. Later, When it's value is larger than 128, any object that is damaged will not be shown. This overall creates a "blinking" damaged effect.

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-1}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-1}}
```

We're going to loop through each object in our object pool. Our `wObjectsEnd` variable is used to simplify looping through all objects. When iterating through our `wObjects`, the first byte for an object is the active byte (aka `object_activeByte` in constants.inc). The valid values of this byte are 0 and 1. If the code reads a 255 (from `wObjectsEnd`), then we know we've reached the end of the bytes associated with our object pool.

If we haven't read 255 yet, then we need to check if the current object is active. We can use `and a` (where the value in the 'a' register comes from the previous 'ld' instruction). If the zero flag is set, then that object is inactive and we'll jump to the next object.

The Code will proceed on, if the object is active.

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-2}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-2}}
```

The first thing we'll do for an active object is call it's update function. We'll copy the address of that function into it 'hl' and call it. Before such, we need to push hl onto the stack. When we're done calling our object's update function, we'll pop it off the stack.

> **Note:** Before we change 'hl', we'll copy it's value into 'bc'. For each object's update function, 'bc' will have the address of that object's first byte.
After updating, we want to draw the object. Before so, we need to check if the object is inactive. If so, we'll avoid drawing and jump to the next object.

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-3}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-3}}
```

AFter updating, if our object is still active, we'll conditionally draw the object. Now we're going to put into use the previously mentioned `wObjectsFlash` variable.

Each object has a damage byte (aka `object_damageByte` in constants.inc). If this byte is non-zero, the associated object has been damaged and we want it to blink. We'll skip drawing the object if the damage byte is non-zero and the `wObjectsFlash` variable is greater than 128.


```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-4}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-4}}
```

For drawing our object, we'll use the `RenderMetasprite` function from Evieue's Sprite Object library. This function requires the following parameters:
- the Q12.4 Fixed-point y position in bc
- The Q12.4 fixed-point X position in de
- The Pointer to current metasprite in hl

To prepare for that function, we'll copy bytes from our object to the proper registers.

> **Note:** After copying our x position to de, our 'hl' registers are not exactly what we need for `RenderMetasprite`. At that point in time, 'hl' doesn't contain the address of our metasprite. It contains a pointer to that address.
After rendering our metasprite, we'll pop the start of our metasprite off the stack. This makes going to the next object simple. With 'hl' pointing to our object's first byte, we simply need to increment 'hl'

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-5}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-5}}
```

When 'hl' points to the first byte of an object ,we can easily move on to the next object. This is done by adding to it: the dynamic constant `PER_OBJECT_BYTES_COUNT` (from constants.inc). From there, we'll go back to our `UpdateObjectPool_Loop` label and repeat until we read 255.

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-6}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:update-objects-6}}
```

## Getting an inactive object

When firing bullets and/or when spawning enemies, we'll need to find an object in our pool that is inactive. For this, we'll create a function called `GetNextAvailableObject_InHL`

This function takes two parameters
- the starting byte in hl
- how many objects to check in b

When this function is done, if the zero flag is not set: an inactive object has been found. At that point in time, 'hl' will point to the first byte of that object.

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:get-next-available-object}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/object-pool.asm:get-next-available-object}}
```

Later, when spawning bullets, we'll call that function like so:

*This code will be covered later*

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/objects/bullets.asm:fire-bullets}}
{{#include ../../galactic-armada/src/main/states/gameplay/objects/bullets.asm:fire-bullets}}
; ... More FireNextBullet logic
```

![Spawning Enemies.png](../assets/part3/img/Spawning_Enemies.png)
6 changes: 5 additions & 1 deletion src/part3/scrolling-background.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ Scrolling the background is an easy task. However, for a SMOOTH slow scrolling b

At the start of the gameplay game state we called the initialize background function. This function shows the star field background, and resets our background scroll variables:

> Just like with our title screen graphic, because our text font tiles are at the beginning of VRAM: we offset the tilemap values by 52
**Create a file called `backgrounds.asm` and add the following code:**

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/gameplay-background.asm:gameplay-background-initialize}}
{{#include ../../galactic-armada/src/main/states/gameplay/gameplay-background.asm:gameplay-background-initialize}}
```

To scroll the background in a gameboy game, we simply need to gradually change the `SCX` or `SCX` registers. Our code is a tiny bit more complicated because of scaled integer usage. Our background's scroll position is stored in a 16-bit integer called `mBackgroundScroll`. We'l increase that 16-bit integer by a set amount.

**Copy the `UpdateBackground` code below into your backgrounds.asm**

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/gameplay-background.asm:gameplay-background-update-start}}
{{#include ../../galactic-armada/src/main/states/gameplay/gameplay-background.asm:gameplay-background-update-start}}
```

We won't directly draw the background using this value. De-scaling a scaled integer simulates having a (more precise and useful for smooth movement) floating-point number. The value we draw our background at will be the de-scaled version of that 16-bit integer. To get that non-scaled version, we'll simply shift all of it's bit rightward 4 places. The final result will saved for when we update our background's y position.

**Copy the code below into your backgrounds.asm**

```rgbasm,linenos,start={{#line_no_of "" ../../galactic-armada/src/main/states/gameplay/gameplay-background.asm:gameplay-background-update-end}}
{{#include ../../galactic-armada/src/main/states/gameplay/gameplay-background.asm:gameplay-background-update-end}}
```
Expand Down

0 comments on commit 3d72f44

Please sign in to comment.