basic main menu with transitions
This commit is contained in:
parent
3c3883b076
commit
aced4c28be
|
@ -22,6 +22,7 @@ set(SOURCES
|
|||
src/geometry.c
|
||||
src/main.c
|
||||
src/map.c
|
||||
src/menu.c
|
||||
src/pathfinding.c
|
||||
src/player.c
|
||||
src/render.c
|
||||
|
@ -44,6 +45,9 @@ set(ASSETS
|
|||
assets-cg/levels/lv1.txt
|
||||
assets-cg/levels/lv2.tmx
|
||||
assets-cg/levels/lv2.txt
|
||||
# Menu
|
||||
assets-cg/menu_title.png
|
||||
assets-cg/menu_arrows.png
|
||||
# HUD
|
||||
assets-cg/hud.png
|
||||
assets-cg/hud_life.png
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
*.png:
|
||||
type: bopti-image
|
||||
name_regex: (.*)\.png img_\1
|
||||
profile: p8
|
||||
|
||||
hud*.png:
|
||||
profile: p4
|
||||
|
||||
hud_xp.ase:
|
||||
custom-type: aseprite-anim
|
||||
name: frames_hud_xp
|
||||
profile: p4
|
||||
center: 6, 8
|
||||
next: Idle=Idle, Shine=Idle, Explode=Idle
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
23
src/main.c
23
src/main.c
|
@ -12,6 +12,7 @@
|
|||
#include "geometry.h"
|
||||
#include "level.h"
|
||||
#include "map.h"
|
||||
#include "menu.h"
|
||||
#include "pathfinding.h"
|
||||
#include "player.h"
|
||||
#include "render.h"
|
||||
|
@ -33,22 +34,6 @@
|
|||
|
||||
#include <libprof.h>
|
||||
|
||||
int main_menu(void)
|
||||
{
|
||||
while(1) {
|
||||
dclear(C_BLACK);
|
||||
dprint(1, 1, C_WHITE, "Rogue Life");
|
||||
dprint(1, 15, C_WHITE, "[1] Cavern");
|
||||
dprint(1, 29, C_WHITE, "[2] Lab");
|
||||
dupdate();
|
||||
|
||||
int key = getkey().key;
|
||||
if(key == KEY_EXIT) return -1;
|
||||
if(key == KEY_1) return 1;
|
||||
if(key == KEY_2) return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* Enable %f etc. in printf()-like functions */
|
||||
|
@ -63,12 +48,12 @@ int main(void)
|
|||
usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL };
|
||||
usb_open(interfaces, GINT_CALL_NULL);
|
||||
|
||||
int lv = main_menu();
|
||||
int lv = menu_level_select(0);
|
||||
level_t const *level = NULL;
|
||||
if(lv == -1) return 1;
|
||||
|
||||
if(lv == 1) level = &level_lv1;
|
||||
if(lv == 2) level = &level_lv2;
|
||||
if(lv == 0) level = &level_lv1;
|
||||
if(lv == 1) level = &level_lv2;
|
||||
|
||||
game_t game = { 0 };
|
||||
camera_t *c = &game.camera;
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
#include "map.h"
|
||||
#include "level.h"
|
||||
#include "render.h"
|
||||
#include <gint/timer.h>
|
||||
#include <gint/cpu.h>
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/defs/util.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
/* Same mechanism as in game_t */
|
||||
map_t const *map;
|
||||
uint16_t *map_anim;
|
||||
camera_t camera;
|
||||
|
||||
} menu_game_t;
|
||||
|
||||
static menu_game_t *menu_load_game(level_t const *level)
|
||||
{
|
||||
menu_game_t *mg = malloc(sizeof *mg);
|
||||
mg->map = level->map;
|
||||
mg->map_anim = malloc(mg->map->width * mg->map->height *
|
||||
sizeof *mg->map_anim);
|
||||
|
||||
for(int i = 0; i < mg->map->width * mg->map->height; i++)
|
||||
mg->map_anim[i] = rand() & 4095;
|
||||
|
||||
camera_init(&mg->camera, mg->map);
|
||||
|
||||
return mg;
|
||||
}
|
||||
|
||||
static void menu_destroy_game(menu_game_t *mg)
|
||||
{
|
||||
free(mg->map_anim);
|
||||
free(mg);
|
||||
}
|
||||
|
||||
static void menu_render_game(menu_game_t *mg)
|
||||
{
|
||||
render_map_layer(mg->map, &mg->camera, 0, 0, HORIZONTAL, mg->map_anim,
|
||||
DIMAGE_NONE);
|
||||
render_map_layer(mg->map, &mg->camera, 0, 0, VERTICAL, mg->map_anim,
|
||||
DIMAGE_NONE);
|
||||
render_map_layer(mg->map, &mg->camera, 0, 0, CEILING, mg->map_anim,
|
||||
DIMAGE_NONE);
|
||||
}
|
||||
|
||||
static void menu_update_animations(menu_game_t *mg, fixed_t dt)
|
||||
{
|
||||
for(int i = 0; i < mg->map->width * mg->map->height; i++)
|
||||
mg->map_anim[i] += fround(dt * 1000);
|
||||
}
|
||||
|
||||
int menu_level_select(int start)
|
||||
{
|
||||
extern bopti_image_t img_menu_title, img_menu_arrows;
|
||||
|
||||
menu_game_t *options[2];
|
||||
#define OPTION_COUNT ((int)(sizeof options / sizeof options[0]))
|
||||
|
||||
options[0] = menu_load_game(&level_lv1);
|
||||
options[1] = menu_load_game(&level_lv2);
|
||||
|
||||
int selection = (start >= 0 && start < OPTION_COUNT) ? start : 0;
|
||||
int target_x=0, x=0;
|
||||
|
||||
int volatile frame_tick = 1;
|
||||
int t = timer_configure(TIMER_ANY, 1000000 / FRAME_RATE,
|
||||
GINT_CALL_SET(&frame_tick));
|
||||
timer_start(t);
|
||||
|
||||
while(1) {
|
||||
while(!frame_tick)
|
||||
sleep();
|
||||
fixed_t dt = fix(1) / FRAME_RATE;
|
||||
|
||||
if(x != target_x) {
|
||||
int dx = (target_x - x) / 6;
|
||||
if(x < target_x && dx < 6)
|
||||
dx = min(target_x-x, 6);
|
||||
if(x > target_x && dx > -6)
|
||||
dx = max(target_x-x, -6);
|
||||
x += dx;
|
||||
}
|
||||
|
||||
dclear(C_BLACK);
|
||||
|
||||
for(int i = 0; i < OPTION_COUNT; i++) {
|
||||
if(-x <= (i-1)*DWIDTH)
|
||||
continue;
|
||||
if(-x >= (i+1)*DWIDTH)
|
||||
continue;
|
||||
|
||||
int local_offset = x + i*DWIDTH;
|
||||
fixed_t map_center = fix(options[i]->map->width) / 2;
|
||||
options[i]->camera.x = map_center - fix(local_offset) / TILE_WIDTH;
|
||||
menu_render_game(options[i]);
|
||||
}
|
||||
|
||||
dimage(148, 9, &img_menu_title);
|
||||
if(selection > 0)
|
||||
dsubimage(16, 93, &img_menu_arrows, 0, 0, 35, 42, DIMAGE_NOCLIP);
|
||||
if(selection < OPTION_COUNT - 1)
|
||||
dsubimage(345, 93, &img_menu_arrows, 35, 0, 35, 42, DIMAGE_NOCLIP);
|
||||
|
||||
dupdate();
|
||||
|
||||
for(int i = 0; i < OPTION_COUNT; i++)
|
||||
menu_update_animations(options[i], dt);
|
||||
|
||||
int key = getkey_opt(GETKEY_MENU, &frame_tick).key;
|
||||
if(key == KEY_LEFT && selection > 0) {
|
||||
selection--;
|
||||
target_x += DWIDTH;
|
||||
}
|
||||
if(key == KEY_RIGHT && selection < OPTION_COUNT - 1) {
|
||||
selection++;
|
||||
target_x -= DWIDTH;
|
||||
}
|
||||
if(key == KEY_EXE || key == KEY_SHIFT)
|
||||
return selection;
|
||||
}
|
||||
|
||||
timer_stop(t);
|
||||
|
||||
for(size_t i = 0; i < OPTION_COUNT; i++)
|
||||
menu_destroy_game(options[i]);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
//---
|
||||
// menu: Main menu
|
||||
//---
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Run the main menu and return the selected entry. start is the entry shown at
|
||||
the start; default 0. */
|
||||
int menu_level_select(int start);
|
25
src/render.c
25
src/render.c
|
@ -123,7 +123,7 @@ fixed_t camera_ppu(camera_t const *c)
|
|||
//---
|
||||
|
||||
static inline void render_tile(int x, int y, tileset_t const *tileset,
|
||||
int tile_id, int time_ms)
|
||||
int tile_id, int time_ms, int flags)
|
||||
{
|
||||
/* If the tile is animated, find the position in the cycle */
|
||||
if(tileset->tiles[tile_id].anim_length > 0) {
|
||||
|
@ -147,14 +147,12 @@ static inline void render_tile(int x, int y, tileset_t const *tileset,
|
|||
dsubimage(x, y, tileset->sheet,
|
||||
TILE_WIDTH * (tile_id % tileset->width),
|
||||
TILE_HEIGHT * (tile_id / tileset->width),
|
||||
TILE_WIDTH, TILE_HEIGHT, DIMAGE_NOCLIP);
|
||||
TILE_WIDTH, TILE_HEIGHT, flags);
|
||||
}
|
||||
|
||||
static void render_map_layer(game_t const *game, camera_t const *c, int ss_x,
|
||||
int ss_y, int layer)
|
||||
void render_map_layer(map_t const *map, camera_t const *c, int ss_x, int ss_y,
|
||||
int layer, uint16_t *map_anim, int flags)
|
||||
{
|
||||
map_t const *map = game->map;
|
||||
|
||||
/* Render floor and walls */
|
||||
for(int row = -2; row < map->height + 2; row++)
|
||||
for(int col = -1; col < map->width + 1; col++) {
|
||||
|
@ -170,12 +168,12 @@ static void render_map_layer(game_t const *game, camera_t const *c, int ss_x,
|
|||
continue;
|
||||
}
|
||||
|
||||
int time_ms = game->map_anim[map->width * row + col];
|
||||
int time_ms = map_anim ? map_anim[map->width * row + col] : 0;
|
||||
|
||||
if(map->tileset->tiles[cell->base].plane == layer)
|
||||
render_tile(p.x, p.y, map->tileset, cell->base, time_ms);
|
||||
render_tile(p.x, p.y, map->tileset, cell->base, time_ms, flags);
|
||||
if(cell->decor && map->tileset->tiles[cell->decor].plane == layer)
|
||||
render_tile(p.x, p.y, map->tileset, cell->decor, time_ms);
|
||||
render_tile(p.x, p.y, map->tileset, cell->decor, time_ms, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,16 +395,19 @@ void render_game(game_t const *g, bool show_hitboxes)
|
|||
prof_enter(ctx);
|
||||
|
||||
/* Render map floor and floor entities */
|
||||
render_map_layer(g, camera, ss_x, ss_y, HORIZONTAL);
|
||||
render_map_layer(g->map, camera, ss_x, ss_y, HORIZONTAL, g->map_anim,
|
||||
DIMAGE_NOCLIP);
|
||||
render_entities(g, camera, floor_depth_measure, ss_x, ss_y, show_hitboxes);
|
||||
|
||||
/* Render map walls and vertical entities
|
||||
TODO ECS: Sort walls and wall entities together for proper ordering!*/
|
||||
render_map_layer(g, camera, ss_x, ss_y, VERTICAL);
|
||||
render_map_layer(g->map, camera, ss_x, ss_y, VERTICAL, g->map_anim,
|
||||
DIMAGE_NOCLIP);
|
||||
render_entities(g, camera, wall_depth_measure, ss_x, ss_y, show_hitboxes);
|
||||
|
||||
/* Render ceiling tiles (including out of bounds) and ceiling entities */
|
||||
render_map_layer(g, camera, ss_x, ss_y, CEILING);
|
||||
render_map_layer(g->map, camera, ss_x, ss_y, CEILING, g->map_anim,
|
||||
DIMAGE_NOCLIP);
|
||||
render_entities(g, camera, ceiling_depth_measure, ss_x,ss_y,show_hitboxes);
|
||||
|
||||
prof_leave(ctx);
|
||||
|
|
|
@ -59,6 +59,14 @@ fixed_t camera_ppu(camera_t const *c);
|
|||
/* Render window overlay. */
|
||||
void render_window(int x, int y, int w, int h);
|
||||
|
||||
/* Render a single layer of the map, with animated tiles.
|
||||
ss_x and ss_y are additional displacement for screenshake; default 0.
|
||||
layer is HORIZONTAL (floor), VERTICAL (wall), or CEILING.
|
||||
map_anim is the indivual tiles' animation time, can be NULL.
|
||||
flags is the flags for dsubimage() for the tiles. */
|
||||
void render_map_layer(map_t const *map, camera_t const *c, int ss_x, int ss_y,
|
||||
int layer, uint16_t *map_anim, int flags);
|
||||
|
||||
/* Render game full-screen. */
|
||||
struct game;
|
||||
void render_game(struct game const *g, bool show_hitboxes);
|
||||
|
|
Loading…
Reference in New Issue