mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2026-10-25 00:02:16 +00:00
214 lines
5.7 KiB
C
214 lines
5.7 KiB
C
/*
|
|
Large scrolling map demo for Game Boy.
|
|
Ported from GBDK's examples/cross-platform/large_map.
|
|
|
|
The map image is 1248x528 pixels = 156x66 tiles, far bigger than
|
|
the GB's 32x32 tile background map. Only the visible window plus the
|
|
next row/column is poked into VRAM with set_bkg_submap(), and the
|
|
whole thing is scrolled with move_bkg(). This is the standard GBDK
|
|
way to scroll a map larger than the hardware tile map.
|
|
|
|
Notes on the port:
|
|
- The original uses DEVICE_SCREEN_* macros from gbdk/platform.h;
|
|
on GB those are just the 20x18 visible area inside a 32x32 map.
|
|
- On a Game Boy Color the per-tile palette numbers come from a
|
|
second map, bigmap_map_attributes, which is poked into VRAM bank 1
|
|
alongside the tile indices. On a plain DMG the attributes are skipped.
|
|
- The map/tile data lives in bigmap.h (generated with png2asset
|
|
-use_map_attributes -noflip, so the attributes are palette-only and
|
|
the tiles still look right on DMG).
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include "gb/types.h"
|
|
#include "gb/hardware.h"
|
|
#include "gb/gb.h"
|
|
#include "gb/cgb.h"
|
|
#include "bigmap.h"
|
|
|
|
#define DEVICE_SCREEN_WIDTH 20
|
|
#define DEVICE_SCREEN_HEIGHT 18
|
|
#define DEVICE_SCREEN_BUFFER_WIDTH 32
|
|
#define DEVICE_SCREEN_BUFFER_HEIGHT 32
|
|
|
|
#define bigmap_mapWidth (bigmap_WIDTH/bigmap_TILE_W)
|
|
#define bigmap_mapHeight (bigmap_HEIGHT/bigmap_TILE_H)
|
|
|
|
#define camera_max_y ((bigmap_mapHeight - DEVICE_SCREEN_HEIGHT) * 8)
|
|
#define camera_max_x ((bigmap_mapWidth - DEVICE_SCREEN_WIDTH) * 8)
|
|
|
|
#define WRAP_SCROLL_Y(y) ((y) % (DEVICE_SCREEN_BUFFER_HEIGHT * 8))
|
|
|
|
#define MIN(A,B) ((A)<(B)?(A):(B))
|
|
|
|
uint8_t joy;
|
|
|
|
// current and old positions of the camera in pixels
|
|
uint16_t camera_x, camera_y, old_camera_x, old_camera_y;
|
|
// current and old position of the map in tiles
|
|
uint8_t map_pos_x, map_pos_y, old_map_pos_x, old_map_pos_y;
|
|
// redraw flag, indicates that camera position was changed
|
|
uint8_t redraw;
|
|
|
|
inline uint8_t update_column_left(uint8_t map_pos_x) {
|
|
return map_pos_x;
|
|
}
|
|
|
|
inline uint8_t update_column_right(uint8_t map_pos_x) {
|
|
return map_pos_x + DEVICE_SCREEN_WIDTH;
|
|
}
|
|
|
|
inline uint8_t update_row_top(uint8_t map_pos_y) {
|
|
return map_pos_y;
|
|
}
|
|
|
|
inline uint8_t update_row_bottom(uint8_t map_pos_y) {
|
|
return map_pos_y + DEVICE_SCREEN_HEIGHT;
|
|
}
|
|
|
|
// The map is a 2D [row][column] array (one flat 10296-byte initializer
|
|
// overflows the SDCC front-end); the rows are contiguous, so pass the
|
|
// first row as the base pointer.
|
|
void set_submap_rows(uint8_t x, uint8_t y, uint8_t w, uint8_t h) {
|
|
set_bkg_submap(x, y, w, h, bigmap_map[0], bigmap_mapWidth);
|
|
// attributes live in VRAM bank 1, which only exists on CGB
|
|
if (_cpu == CGB_TYPE) {
|
|
VBK_REG = 1;
|
|
set_bkg_submap(x, y, w, h, bigmap_map_attributes[0], bigmap_mapWidth);
|
|
VBK_REG = 0;
|
|
}
|
|
}
|
|
|
|
void set_camera(void)
|
|
{
|
|
// update hardware scroll position
|
|
move_bkg(camera_x, WRAP_SCROLL_Y(camera_y));
|
|
// up or down
|
|
map_pos_y = (uint8_t)(camera_y >> 3u);
|
|
if (map_pos_y != old_map_pos_y)
|
|
{
|
|
if (camera_y < old_camera_y)
|
|
{
|
|
set_submap_rows(
|
|
map_pos_x,
|
|
update_row_top(map_pos_y),
|
|
MIN(DEVICE_SCREEN_WIDTH + 1, bigmap_mapWidth-map_pos_x),
|
|
1);
|
|
}
|
|
else
|
|
{
|
|
if ((bigmap_mapHeight - DEVICE_SCREEN_HEIGHT) > map_pos_y)
|
|
{
|
|
set_submap_rows(
|
|
map_pos_x,
|
|
update_row_bottom(map_pos_y),
|
|
MIN(DEVICE_SCREEN_WIDTH + 1, bigmap_mapWidth-map_pos_x),
|
|
1);
|
|
}
|
|
}
|
|
old_map_pos_y = map_pos_y;
|
|
}
|
|
// left or right
|
|
map_pos_x = (uint8_t)(camera_x >> 3u);
|
|
if (map_pos_x != old_map_pos_x)
|
|
{
|
|
if (camera_x < old_camera_x)
|
|
{
|
|
set_submap_rows(
|
|
update_column_left(map_pos_x),
|
|
map_pos_y,
|
|
1,
|
|
MIN(DEVICE_SCREEN_HEIGHT + 1, bigmap_mapHeight - map_pos_y));
|
|
}
|
|
else
|
|
{
|
|
if ((bigmap_mapWidth - DEVICE_SCREEN_WIDTH) > map_pos_x)
|
|
{
|
|
set_submap_rows(
|
|
update_column_right(map_pos_x),
|
|
map_pos_y,
|
|
1,
|
|
MIN(DEVICE_SCREEN_HEIGHT + 1, bigmap_mapHeight - map_pos_y));
|
|
}
|
|
}
|
|
old_map_pos_x = map_pos_x;
|
|
}
|
|
// set old camera position to current camera position
|
|
old_camera_x = camera_x, old_camera_y = camera_y;
|
|
}
|
|
|
|
void init_camera(uint8_t x, uint8_t y) {
|
|
|
|
// Set up tile data
|
|
set_native_tile_data(0, bigmap_TILE_COUNT, bigmap_tiles);
|
|
|
|
// Set up color palettes on GBC
|
|
if (_cpu == CGB_TYPE) {
|
|
set_bkg_palette(0, bigmap_PALETTE_COUNT, bigmap_palettes);
|
|
}
|
|
|
|
// Initial camera position in pixels set here.
|
|
camera_x = x;
|
|
camera_y = y;
|
|
// Enforce map limits on initial camera position
|
|
if (camera_x > camera_max_x) camera_x = camera_max_x;
|
|
if (camera_y > camera_max_y) camera_y = camera_max_y;
|
|
old_camera_x = camera_x; old_camera_y = camera_y;
|
|
|
|
map_pos_x = camera_x >> 3;
|
|
map_pos_y = camera_y >> 3;
|
|
old_map_pos_x = old_map_pos_y = 255;
|
|
move_bkg(camera_x, WRAP_SCROLL_Y(camera_y));
|
|
|
|
// Draw the initial map view for the whole screen
|
|
set_submap_rows(
|
|
map_pos_x,
|
|
map_pos_y,
|
|
MIN(DEVICE_SCREEN_WIDTH + 1u, bigmap_mapWidth - map_pos_x),
|
|
MIN(DEVICE_SCREEN_HEIGHT + 1u, bigmap_mapHeight - map_pos_y));
|
|
|
|
redraw = 0;
|
|
|
|
move_bkg(camera_x, WRAP_SCROLL_Y(camera_y));
|
|
}
|
|
|
|
void main(void){
|
|
DISPLAY_OFF;
|
|
init_camera(0, 0);
|
|
|
|
SHOW_BKG;
|
|
DISPLAY_ON;
|
|
while (1) {
|
|
joy = joypad();
|
|
// up or down
|
|
if (joy & J_UP) {
|
|
if (camera_y) {
|
|
camera_y--;
|
|
redraw = 1;
|
|
}
|
|
} else if (joy & J_DOWN) {
|
|
if (camera_y < camera_max_y) {
|
|
camera_y++;
|
|
redraw = 1;
|
|
}
|
|
}
|
|
// left or right
|
|
if (joy & J_LEFT) {
|
|
if (camera_x) {
|
|
camera_x--;
|
|
redraw = 1;
|
|
}
|
|
} else if (joy & J_RIGHT) {
|
|
if (camera_x < camera_max_x) {
|
|
camera_x++;
|
|
redraw = 1;
|
|
}
|
|
}
|
|
if (redraw) {
|
|
wait_vbl_done();
|
|
set_camera();
|
|
redraw = 0;
|
|
} else wait_vbl_done();
|
|
}
|
|
}
|