Browse Source

Add title screen

master
Forest Belton 3 years ago
parent
commit
6d72ee2c2e
8 changed files with 145 additions and 58 deletions
  1. BIN
      assets/bg/title.png
  2. BIN
      assets/tiles.png
  3. +23
    -1
      src/actor.c
  4. +6
    -0
      src/actor.h
  5. +47
    -0
      src/game.h
  6. +14
    -0
      src/helpers.asm
  7. +11
    -57
      src/main.c
  8. +44
    -0
      src/title.c

BIN
assets/bg/title.png View File

Before After
Width: 160  |  Height: 144  |  Size: 2.8 KiB

BIN
assets/tiles.png View File

Before After
Width: 32  |  Height: 32  |  Size: 245 B

+ 23
- 1
src/actor.c View File

@ -9,6 +9,9 @@
#define MAX_ACTORS 5 #define MAX_ACTORS 5
#define NUM_OAM_ENTRIES 40 #define NUM_OAM_ENTRIES 40
#define TILE_WIDTH 8 #define TILE_WIDTH 8
#define FRAMES_PER_ANIM_FRAME 20
static actor_anim_state_t ANIM_TOTAL_FRAMES[] = {2};
static uint8_t mob_ids[MAX_UNIQUE_MOBS]; static uint8_t mob_ids[MAX_UNIQUE_MOBS];
static sprite16_mob mob_anim_data[MAX_UNIQUE_MOBS]; static sprite16_mob mob_anim_data[MAX_UNIQUE_MOBS];
@ -54,12 +57,31 @@ actor_t *actor_create_mob(uint8_t id) {
void actor_remove(actor_t *a) { a->active = 0; } void actor_remove(actor_t *a) { a->active = 0; }
void actor_update(void) {
actor_t *a = &all_actors[0];
for (uint8_t i = 0; i < ARRSIZE(all_actors); ++i) {
if (!a->active) {
continue;
}
a->frame_counter++;
if (a->frame_counter == FRAMES_PER_ANIM_FRAME) {
a->frame_counter = 0;
a->frame_idx = (a->frame_idx + 1) % ANIM_TOTAL_FRAMES[a->anim];
}
a++;
}
}
void actor_flush_oam(void) { void actor_flush_oam(void) {
struct oam_entry *oam_ptr = &shadow_oam[0]; struct oam_entry *oam_ptr = &shadow_oam[0];
actor_t *a = &all_actors[0]; actor_t *a = &all_actors[0];
for (uint8_t i = 0; i < ARRSIZE(all_actors); ++i) { for (uint8_t i = 0; i < ARRSIZE(all_actors); ++i) {
if (!a->active) { if (!a->active) {
a++;
continue; continue;
} }
@ -116,4 +138,4 @@ static uint8_t actor_load_mob_anim_data(uint8_t mob_id) {
} }
return mob_anim_idx; return mob_anim_idx;
}
}

+ 6
- 0
src/actor.h View File

@ -16,6 +16,7 @@ typedef enum {
typedef struct { typedef struct {
uint8_t active; uint8_t active;
uint8_t dirty;
uint8_t mob_anim_idx; uint8_t mob_anim_idx;
actor_anim_state_t anim; actor_anim_state_t anim;
uint8_t frame_idx; uint8_t frame_idx;
@ -54,6 +55,11 @@ actor_t *actor_create_mob(mob_id_t id);
*/ */
void actor_remove(actor_t *a); void actor_remove(actor_t *a);
/**
* @brief Update the internal state of each actor.
*/
void actor_update(void);
/** /**
* @brief Flush actor sprite data to OAM. * @brief Flush actor sprite data to OAM.
*/ */

+ 47
- 0
src/game.h View File

@ -0,0 +1,47 @@
#ifndef IS_GAME_H_
#define IS_GAME_H_
#define _VRAM 0x8000
#define _VRAM8000 _VRAM
#define _VRAM8800 (_VRAM + 0x800)
#define _VRAM9000 (_VRAM + 0x1000)
#define _SCRN0 0x9800
#define _SCRN1 0x9c00
#define SCRN_X 160
#define SCRN_Y 144
#define SCRN_X_B 20
#define SCRN_Y_B 18
#define SCRN_VX 256
#define SCRN_VY 256
#define SCRN_VX_B 32
#define SCRN_VX_Y 32
#define SCREEN_HEIGHT_TILES 18
#define SCREEN_WIDTH_TILES 20
typedef enum {
GAME_STATE_TITLE,
GAME_STATE_LEVEL,
GAME_STATE_MENU,
} game_state_t;
extern game_state_t game_state;
/**
* @brief Render the title screen.
*/
void title(void);
/**
* @brief Enable interrupts.
*/
void interrupts_enable(void) __preserves_regs(a, b, c, d, e, h, l);
/**
* @brief Disable interrupts.
*/
void interrupts_disable(void) __preserves_regs(a, b, c, d, e, h, l);
#endif

+ 14
- 0
src/helpers.asm View File

@ -0,0 +1,14 @@
SECTION "vblank", ROM0[$40]
handle_vblank:
reti
SECTION "interrupt routines", ROM0
_interrupts_disable::
di
ret
_interrupts_enable::
ei
ret

+ 11
- 57
src/main.c View File

@ -1,80 +1,34 @@
#include <string.h> #include <string.h>
#include "actor.h" #include "actor.h"
#include "sdk/assets.h"
#include "game.h"
#include "sdk/hardware.h" #include "sdk/hardware.h"
#include "sdk/joypad.h"
#include "sdk/oam.h" #include "sdk/oam.h"
#include "sdk/video.h"
ASSET(tiles, "tiles.2bpp");
uint8_t cursor_x = 0;
uint8_t cursor_y = 0;
game_state_t game_state;
void main() { void main() {
// Load our initial vram (this is slow, but always works, even outside of
// vblank)
vram_memcpy(0x8000, tiles, tiles_end - tiles);
vram_memcpy(0x9000, tiles, tiles_end - tiles);
game_state = GAME_STATE_TITLE;
// Setup the OAM for sprite drawing // Setup the OAM for sprite drawing
oam_init(); oam_init();
// Set some default DMG palette data
// Set up background & sprites
rBGP = 0b11100100; rBGP = 0b11100100;
rOBP0 = 0b11100100; rOBP0 = 0b11100100;
rOBP1 = 0b11100100; rOBP1 = 0b11100100;
// Put some sprites on the screen
shadow_oam[0].y = 0x20;
shadow_oam[0].x = 0x20;
shadow_oam[0].tile = 0x04;
shadow_oam[0].attr = 0x00;
shadow_oam[1].y = 0x24;
shadow_oam[1].x = 0x24;
shadow_oam[1].tile = 0x02;
shadow_oam[1].attr = 0x00;
// Make sure sprites and the background are drawn
rLCDC = LCDC_ON | LCDC_OBJON | LCDC_BGON;
rLCDC = LCDC_OBJON | LCDC_BGON | LCDC_BG8000;
// Setup the VBLANK interrupt, but we don't actually enable interrupt // Setup the VBLANK interrupt, but we don't actually enable interrupt
// handling.
// We only do this, so HALT waits for VBLANK.
// handling. We only do this so HALT waits for VBLANK.
rIF = 0; rIF = 0;
rIE = IE_VBLANK; rIE = IE_VBLANK;
vram_memset(0x9800, 0x05, 32 * 18);
for (uint8_t x = 0; x < 20; x++) {
vram_set(0x9800 + x, 0x07);
vram_set(0x9A20 + x, 0x07);
}
for (uint8_t y = 1; y < 18; y++) {
vram_set(0x9800 + y * 0x20, 0x07);
vram_set(0x9800 + 19 + y * 0x20, 0x07);
}
vram_set(0x9800 + 3 + 3 * 0x20, 0x01);
while (1) { while (1) {
joypad_update();
if (joypad_state & PAD_LEFT) cursor_x--;
if (joypad_state & PAD_RIGHT) cursor_x++;
if (joypad_state & PAD_UP) cursor_y--;
if (joypad_state & PAD_DOWN) cursor_y++;
if (joypad_state & (PAD_A | PAD_B)) {
vram_set(0x9800 + cursor_x / 8 + cursor_y / 8 * 0x20, 0x03);
switch (game_state) {
case GAME_STATE_TITLE:
title();
break;
} }
// Screen to OAM coordinates
shadow_oam[0].y = cursor_y + 16;
shadow_oam[0].x = cursor_x + 8;
// Wait for VBLANK
HALT();
rIF = 0; // As global interrupts are not enabled, we need to clear the
// interrupt flag.
// Copy the sprites into OAM memory
oam_dma_copy();
} }
} }

+ 44
- 0
src/title.c View File

@ -0,0 +1,44 @@
#include <string.h>
#include "game.h"
#include "sdk/assets.h"
#include "sdk/hardware.h"
#include "sdk/joypad.h"
#include "sdk/oam.h"
#include "sdk/video.h"
ASSET(bg_tiles, "bg/title.2bpp");
ASSET(bg_map, "bg/title.map");
void title(void) {
// NOTE: Replace with lcdc_off() if necessary
rLCDC &= ~LCDC_ON;
// Copy title screen to VRAM
memcpy((uint8_t *)_VRAM, &bg_tiles[0], bg_tiles_end - bg_tiles);
// vram_memcpy(_VRAM, &bg_tiles[0], bg_tiles_end - bg_tiles);
uint8_t *vram_ptr = (uint8_t *)_SCRN0;
const uint8_t *map_ptr = &bg_map[0];
for (uint8_t y = 0; y < SCRN_Y_B; ++y) {
memcpy(vram_ptr, map_ptr, SCRN_X_B);
vram_ptr += SCRN_VX_B;
map_ptr += SCRN_X_B;
}
rLCDC |= LCDC_ON;
interrupts_enable();
while (1) {
joypad_update();
if (joypad_state & PAD_START) {
game_state = GAME_STATE_LEVEL;
break;
}
// Wait for VBLANK. Clear IF since global interrupts are disabled.
HALT();
rIF = 0;
}
}

Loading…
Cancel
Save