clean up game logic
This commit is contained in:
parent
7c52c73716
commit
9c0287fbc4
|
@ -16,4 +16,4 @@ finish: 34
|
|||
24: plane ARROW ARROW_+Z
|
||||
26: plane DAMAGE HLINES_2_4
|
||||
|
||||
30-33: text "Look at you, all dizzy\njust from rolling a bit.\n\nFocus, I need some results!"
|
||||
30-33: text "Look at you, all dizzy\njust from rolling a bit.\n\nGet ready, we need results!"
|
||||
|
|
|
@ -9,9 +9,8 @@ struct cd_raytrace_cmd
|
|||
uint8_t shader_id;
|
||||
uint8_t _[3];
|
||||
|
||||
/* Camera and world used for rendering */
|
||||
struct camera const *camera;
|
||||
struct world const *world;
|
||||
/* Game being rendered (should not change during a frame) */
|
||||
struct game const *game;
|
||||
/* Current y value */
|
||||
int y;
|
||||
};
|
||||
|
@ -24,7 +23,7 @@ void cd_raytrace_shader(void *uniforms0, void *cmd0, void *fragment)
|
|||
|
||||
int frag_height = uniforms;
|
||||
int h = (frag_height > 112 - cmd->y) ? 112 - cmd->y : frag_height;
|
||||
render_fragment(cmd->camera, cmd->world, (uint16_t *)fragment, cmd->y, h);
|
||||
render_fragment(cmd->game, (uint16_t *)fragment, cmd->y, h);
|
||||
cmd->y += h;
|
||||
}
|
||||
|
||||
|
@ -34,14 +33,13 @@ static void register_shader(void)
|
|||
CD_RAYTRACE_SHADER_ID = azrp_register_shader(cd_raytrace_shader);
|
||||
}
|
||||
|
||||
void cd_raytrace(struct camera const *camera, struct world const *world)
|
||||
void cd_raytrace(struct game const *game)
|
||||
{
|
||||
prof_enter(azrp_perf_cmdgen);
|
||||
|
||||
struct cd_raytrace_cmd cmd;
|
||||
cmd.shader_id = CD_RAYTRACE_SHADER_ID;
|
||||
cmd.camera = camera;
|
||||
cmd.world = world;
|
||||
cmd.game = game;
|
||||
cmd.y = 0;
|
||||
|
||||
azrp_queue_command(&cmd, sizeof cmd, 0, azrp_frag_count);
|
||||
|
|
|
@ -124,6 +124,10 @@ struct level {
|
|||
struct element_text *texts;
|
||||
};
|
||||
|
||||
/* Total number of levels. */
|
||||
int level_count(void);
|
||||
/* Get a level by ID. */
|
||||
struct level const *level_get(int id);
|
||||
/* Check whether world coordinates x/z would collide with an object plane of
|
||||
the provided shape. */
|
||||
bool level_plane_collides(num16 x, num16 z, uint32_t shape);
|
||||
|
@ -132,32 +136,65 @@ bool level_plane_collides(num16 x, num16 z, uint32_t shape);
|
|||
// Dynamic world information
|
||||
//---
|
||||
|
||||
struct world {
|
||||
struct game {
|
||||
/* Camera (including player position) */
|
||||
struct camera *camera;
|
||||
/* Neon cycle specification - independent from level */
|
||||
num16 neon_position;
|
||||
num16 neon_period;
|
||||
|
||||
/* Current objects */
|
||||
num depth;
|
||||
struct element_mirror *mirror;
|
||||
struct element_plane *plane;
|
||||
struct element_text *text;
|
||||
/* Current level and its level number. When level is NULL and/or level_id is
|
||||
negative, we are in the main menu. */
|
||||
struct level const *level;
|
||||
int level_id;
|
||||
/* Current position within level's element arrays */
|
||||
int mirror_index;
|
||||
int plane_index;
|
||||
int text_index;
|
||||
/* Corresponding elements (these are the only active elements) */
|
||||
struct element_mirror *mirror;
|
||||
struct element_plane *plane;
|
||||
struct element_text *text;
|
||||
|
||||
/* Distance traversed within the current level */
|
||||
num depth;
|
||||
|
||||
/* Number of blank frames to show (for death transitions) */
|
||||
int blank_frames;
|
||||
|
||||
/* Cursor position within the main menu */
|
||||
int menu_cursor;
|
||||
};
|
||||
|
||||
/* Check whether we are in the main menu. */
|
||||
bool game_in_menu(struct game const *game);
|
||||
/* Transition to the main menu. */
|
||||
void game_load_menu(struct game *game);
|
||||
/* Transition to a level. */
|
||||
void game_load_level(struct game *game, int index, int blank_frames);
|
||||
/* Restart current level. */
|
||||
void game_restart_level(struct game *g, int blank_frames);
|
||||
/* Go the previous level (or menu if currently at the first level). */
|
||||
void game_prev_level_or_menu(struct game *g);
|
||||
/* Go the next level (or menu if currently at the last level). */
|
||||
void game_next_level_or_menu(struct game *g);
|
||||
/* Return the plane currently in collision with the player, if any, or NULL. */
|
||||
const struct element_plane *game_plane_collision(struct game const *g);
|
||||
/* Advancee in level by unloading passed elements and loading incoming ones.
|
||||
Check game_plane_collision() before calling this function. */
|
||||
void game_advance_in_level(struct game *g);
|
||||
|
||||
//---
|
||||
// Raytracing
|
||||
//---
|
||||
|
||||
/* Core function. Renders an image of the provided world through the provided
|
||||
camera. Renders lines [y_start ... y_start+y_height) on the specified VRAM
|
||||
fragment. */
|
||||
void render_fragment(struct camera const *camera, struct world const *world,
|
||||
uint16_t *fragment, int y_start, int y_height);
|
||||
/* Core function. Renders an image of the provided game; renders lines
|
||||
[y_start ... y_start+y_height) on the specified VRAM fragment. */
|
||||
void render_fragment(struct game const *game, uint16_t *fragment,
|
||||
int y_start, int y_height);
|
||||
|
||||
/* Azur shader wrapping the raytracing function. */
|
||||
void cd_raytrace(struct camera const *camera, struct world const *world);
|
||||
void cd_raytrace(struct game const *game);
|
||||
/* Shader configuration function, must be called at initialization and after
|
||||
any scale change. */
|
||||
void cd_raytrace_configure(void);
|
||||
|
|
137
src/game.cc
137
src/game.cc
|
@ -1,5 +1,39 @@
|
|||
/* Functions for game-specific mechanics. */
|
||||
#include "chaos-drop.h"
|
||||
#include <azur/azur.h>
|
||||
|
||||
#ifdef AZUR_TOOLKIT_GINT
|
||||
extern struct level level_1_1, level_1_2, level_1_3;
|
||||
extern struct level level_2_1, level_2_2, level_2_3;
|
||||
extern struct level level_3_1, level_3_2, level_3_3;
|
||||
static struct level const *ALL_LEVELS[] = {
|
||||
&level_1_1, &level_1_2, &level_1_3,
|
||||
&level_2_1, &level_2_2, &level_2_3,
|
||||
};
|
||||
#else
|
||||
/* TODO: PC/SDL build: Embed levels as in the add-in */
|
||||
static struct level const lv_test = {
|
||||
.name = "<Test>",
|
||||
.finish = num(1024),
|
||||
.mirror_count = 1,
|
||||
.mirrors = (struct element_mirror[]){
|
||||
{ .begin = 256, .end = 768 },
|
||||
},
|
||||
.plane_count = 2,
|
||||
.planes = (struct element_plane[]){
|
||||
{ .y = 384, .shape = 0b01010'10101'01010'10101'01010,
|
||||
.type = ELEMENT_PLANE_DAMAGE, .data = 0 },
|
||||
{ .y = 384+64, .shape = 0b11111'10001'10001'10001'11111,
|
||||
.type = ELEMENT_PLANE_DAMAGE, .data = 0 },
|
||||
},
|
||||
.text_count = 1,
|
||||
.texts = (struct element_text[]){
|
||||
{ .begin = 32, .end = 256,
|
||||
.str = "Red stuff bad!\nDon't touch the red stuff!", },
|
||||
},
|
||||
};
|
||||
static struct level const *ALL_LEVELS[] = { &lv_test };
|
||||
#endif
|
||||
|
||||
void camera_set_fov(struct camera *camera, float fov_degrees)
|
||||
{
|
||||
|
@ -113,6 +147,16 @@ void camera_update_angles(struct camera *camera)
|
|||
camera->up = c2w * vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
int level_count(void)
|
||||
{
|
||||
return sizeof ALL_LEVELS / sizeof ALL_LEVELS[0];
|
||||
}
|
||||
|
||||
const struct level *level_get(int id)
|
||||
{
|
||||
return (id >= 0 && id < level_count()) ? ALL_LEVELS[id] : NULL;
|
||||
}
|
||||
|
||||
bool level_plane_collides(num16 x, num16 z, uint32_t shape)
|
||||
{
|
||||
int cx = ((x + num16(WORLD_SIZE)) * num16(5.0 / 2 / WORLD_SIZE)).ifloor();
|
||||
|
@ -121,3 +165,96 @@ bool level_plane_collides(num16 x, num16 z, uint32_t shape)
|
|||
return (unsigned)cx < 5 && (unsigned)cz < 5
|
||||
&& ((shape >> (5*cz + 4-cx)) & 1);
|
||||
}
|
||||
|
||||
bool game_in_menu(struct game const *g)
|
||||
{
|
||||
return !g->level;
|
||||
}
|
||||
|
||||
static void game_reset_level_data(struct game *g)
|
||||
{
|
||||
g->level = NULL;
|
||||
g->level_id = -1;
|
||||
g->mirror_index = 0;
|
||||
g->plane_index = 0;
|
||||
g->text_index = 0;
|
||||
g->mirror = NULL;
|
||||
g->plane = NULL;
|
||||
g->text = NULL;
|
||||
g->depth = 0;
|
||||
}
|
||||
|
||||
void game_load_menu(struct game *g)
|
||||
{
|
||||
game_reset_level_data(g);
|
||||
g->level = NULL;
|
||||
g->level_id = -1;
|
||||
}
|
||||
|
||||
void game_load_level(struct game *g, int index, int blank_frames)
|
||||
{
|
||||
struct level const *level = level_get(index);
|
||||
if(!level)
|
||||
return;
|
||||
|
||||
game_reset_level_data(g);
|
||||
g->level = level;
|
||||
g->level_id = index;
|
||||
g->blank_frames = blank_frames;
|
||||
}
|
||||
|
||||
void game_restart_level(struct game *g, int blank_frames)
|
||||
{
|
||||
if(!game_in_menu(g))
|
||||
game_load_level(g, g->level_id, blank_frames);
|
||||
}
|
||||
|
||||
void game_prev_level_or_menu(struct game *g)
|
||||
{
|
||||
if(g->level_id > 0)
|
||||
game_load_level(g, g->level_id - 1, 0);
|
||||
else
|
||||
game_load_menu(g);
|
||||
}
|
||||
|
||||
void game_next_level_or_menu(struct game *g)
|
||||
{
|
||||
if(g->level_id >= 0 && g->level_id + 1 < level_count())
|
||||
game_load_level(g, g->level_id + 1, 0);
|
||||
else
|
||||
game_load_menu(g);
|
||||
}
|
||||
|
||||
const struct element_plane *game_plane_collision(struct game const *g)
|
||||
{
|
||||
return g->plane && g->depth > g->plane->y - num(4) ? g->plane : NULL;
|
||||
}
|
||||
|
||||
void game_advance_in_level(struct game *g)
|
||||
{
|
||||
struct level const *level = g->level;
|
||||
|
||||
/* Remove old elements */
|
||||
|
||||
if(g->mirror && g->depth > g->mirror->end)
|
||||
g->mirror = NULL;
|
||||
if(game_plane_collision(g))
|
||||
g->plane = NULL;
|
||||
if(g->text && g->depth > g->text->end)
|
||||
g->text = NULL;
|
||||
|
||||
/* Load incoming elements */
|
||||
|
||||
if(!g->mirror && g->mirror_index < level->mirror_count
|
||||
&& level->mirrors[g->mirror_index].begin < g->depth + num(64)) {
|
||||
g->mirror = &level->mirrors[g->mirror_index++];
|
||||
}
|
||||
if(!g->plane && g->plane_index < level->plane_count
|
||||
&& level->planes[g->plane_index].y < g->depth + num(64)) {
|
||||
g->plane = &level->planes[g->plane_index++];
|
||||
}
|
||||
if(!g->text && g->text_index < level->text_count
|
||||
&& level->texts[g->text_index].begin < g->depth + num(64)) {
|
||||
g->text = &level->texts[g->text_index++];
|
||||
}
|
||||
}
|
||||
|
|
304
src/main.cc
304
src/main.cc
|
@ -282,190 +282,105 @@ void render_centered_text(char const *str)
|
|||
}
|
||||
}
|
||||
|
||||
static struct camera *camera = NULL;
|
||||
static struct world *world = NULL;
|
||||
static int reset_frames = 0;
|
||||
static bool debug = false;
|
||||
|
||||
static bool menu_active = true;
|
||||
static int menu_cursor = 0;
|
||||
|
||||
#ifdef AZUR_TOOLKIT_GINT
|
||||
extern struct level level_1_1, level_1_2, level_1_3;
|
||||
extern struct level level_2_1, level_2_2, level_2_3;
|
||||
extern struct level level_3_1, level_3_2, level_3_3;
|
||||
static struct level const *levels[] = {
|
||||
&level_1_1, &level_1_2, &level_1_3,
|
||||
&level_2_1, &level_2_2, &level_2_3,
|
||||
};
|
||||
#else
|
||||
/* Basic basic level */
|
||||
static struct level const lv_test = {
|
||||
.name = "<Test>",
|
||||
.finish = num(1024),
|
||||
.mirror_count = 1,
|
||||
.mirrors = (struct element_mirror[]){
|
||||
{ .begin = 256, .end = 768 },
|
||||
},
|
||||
.plane_count = 2,
|
||||
.planes = (struct element_plane[]){
|
||||
{ .y = 384, .shape = 0b01010'10101'01010'10101'01010,
|
||||
.type = ELEMENT_PLANE_DAMAGE, .data = 0 },
|
||||
{ .y = 384+64, .shape = 0b11111'10001'10001'10001'11111,
|
||||
.type = ELEMENT_PLANE_DAMAGE, .data = 0 },
|
||||
},
|
||||
.text_count = 1,
|
||||
.texts = (struct element_text[]){
|
||||
{ .begin = 32, .end = 256,
|
||||
.str = "Red stuff bad!\nDon't touch the red stuff!", },
|
||||
},
|
||||
};
|
||||
static struct level const *levels[] = { &lv_test };
|
||||
#endif
|
||||
|
||||
#define LEVEL_COUNT ((int)(sizeof levels / sizeof levels[0]))
|
||||
static int current_level = 0;
|
||||
|
||||
void load_level_number(int number)
|
||||
void game_render(struct game *g)
|
||||
{
|
||||
if(number < 0)
|
||||
number = 0;
|
||||
if(number > LEVEL_COUNT)
|
||||
number = LEVEL_COUNT - 1;
|
||||
|
||||
current_level = number;
|
||||
}
|
||||
|
||||
void world_reset(struct world *world)
|
||||
{
|
||||
world->neon_position = 0;
|
||||
world->depth = 0;
|
||||
world->neon_period = 64;
|
||||
world->mirror = NULL;
|
||||
world->plane = NULL;
|
||||
world->text = NULL;
|
||||
world->mirror_index = 0;
|
||||
world->plane_index = 0;
|
||||
world->text_index = 0;
|
||||
}
|
||||
|
||||
void world_level_transition(struct world *world)
|
||||
{
|
||||
world->depth = world->depth % num(world->neon_period);
|
||||
world->mirror = NULL;
|
||||
world->plane = NULL;
|
||||
world->text = NULL;
|
||||
world->mirror_index = 0;
|
||||
world->plane_index = 0;
|
||||
world->text_index = 0;
|
||||
}
|
||||
|
||||
void render(void)
|
||||
{
|
||||
struct level const *level = levels[current_level];
|
||||
struct level const *level = g->level;
|
||||
|
||||
#ifdef AZUR_TOOLKIT_GINT
|
||||
extern image_t img_title, img_cursor;
|
||||
|
||||
azrp_perf_clear();
|
||||
if(menu_active) {
|
||||
cd_raytrace(camera, world);
|
||||
if(g->blank_frames > 0) {
|
||||
g->blank_frames--;
|
||||
azrp_clear(0xffff);
|
||||
}
|
||||
else if(game_in_menu(g)) {
|
||||
cd_raytrace(g);
|
||||
azrp_image((azrp_width - img_title.width) / 2, 4, &img_title);
|
||||
|
||||
for(int row = 0; row < 2; row++)
|
||||
for(int col = 0; col < 3; col++) {
|
||||
int i = 3 * row + col;
|
||||
if(i >= LEVEL_COUNT)
|
||||
if(i >= level_count())
|
||||
continue;
|
||||
|
||||
int x = azrp_width / 2 + 40 * (col - 1);
|
||||
int y = 55 + 20 * row;
|
||||
int l = strlen(levels[i]->name);
|
||||
int width = text_size(levels[i]->name, l);
|
||||
char const *name = level_get(i)->name;
|
||||
int l = strlen(name);
|
||||
int width = text_size(name, l);
|
||||
|
||||
if(menu_cursor == i)
|
||||
if(g->menu_cursor == i)
|
||||
azrp_image(x - width/2 - 6, y-2, &img_cursor);
|
||||
|
||||
draw_text(x - width/2, y, levels[i]->name, l);
|
||||
draw_text(x - width/2, y, name, l);
|
||||
}
|
||||
}
|
||||
else if(reset_frames > 0) {
|
||||
reset_frames--;
|
||||
azrp_clear(0xffff);
|
||||
}
|
||||
else {
|
||||
cd_raytrace(camera, world);
|
||||
if(world->text)
|
||||
render_centered_text(world->text->str);
|
||||
cd_raytrace(g);
|
||||
if(g->text)
|
||||
render_centered_text(g->text->str);
|
||||
draw_text(1, 1, level->name, strlen(level->name));
|
||||
}
|
||||
platform_render();
|
||||
|
||||
if(debug) {
|
||||
drect(0, DHEIGHT-20, DWIDTH-1, DHEIGHT-1, C_WHITE);
|
||||
dprint(4, 209, C_BLACK, "render:%4d+%4dus",
|
||||
prof_time(azrp_perf_render) - prof_time(azrp_perf_r61524),
|
||||
prof_time(azrp_perf_r61524));
|
||||
r61524_display(gint_vram, DHEIGHT-20, 20, R61524_DMA_WAIT);
|
||||
}
|
||||
#else
|
||||
if(reset_frames > 0) {
|
||||
reset_frames--;
|
||||
if(g->blank_frames > 0) {
|
||||
g->blank_frames--;
|
||||
memset(vram, 0xff, sizeof vram);
|
||||
}
|
||||
else {
|
||||
render_fragment(camera, world, vram, 0, VHEIGHT);
|
||||
if(world->text)
|
||||
render_centered_text(world->text->str);
|
||||
render_fragment(g, vram, 0, VHEIGHT);
|
||||
if(g->text)
|
||||
render_centered_text(g->text->str);
|
||||
draw_text(1, 1, level->name, strlen(level->name));
|
||||
}
|
||||
platform_render();
|
||||
#endif
|
||||
}
|
||||
|
||||
int update(void)
|
||||
int game_update(struct game *g, bool *debug)
|
||||
{
|
||||
struct input input = {};
|
||||
if(platform_update(&input))
|
||||
return 1;
|
||||
|
||||
struct camera *camera = g->camera;
|
||||
bool menu = game_in_menu(g);
|
||||
|
||||
/* Debug controls */
|
||||
if(input.OPTN)
|
||||
debug = !debug;
|
||||
if(!menu_active && input.RESET_LEVEL) {
|
||||
world_reset(world);
|
||||
reset_frames = 2;
|
||||
*debug = !*debug;
|
||||
if(!menu && input.RESET_LEVEL) {
|
||||
game_restart_level(g, 2);
|
||||
return 0;
|
||||
}
|
||||
if(!menu_active && input.NEXT_LEVEL && current_level < LEVEL_COUNT-1) {
|
||||
world_level_transition(world);
|
||||
load_level_number(current_level+1);
|
||||
reset_frames = 2;
|
||||
if(!menu && input.NEXT_LEVEL) {
|
||||
game_next_level_or_menu(g);
|
||||
g->blank_frames = 2;
|
||||
return 0;
|
||||
}
|
||||
if(!menu_active && input.PREV_LEVEL && current_level > 0) {
|
||||
world_level_transition(world);
|
||||
load_level_number(current_level-1);
|
||||
reset_frames = 2;
|
||||
if(!menu && input.PREV_LEVEL) {
|
||||
game_prev_level_or_menu(g);
|
||||
g->blank_frames = 2;
|
||||
return 0;
|
||||
}
|
||||
if(reset_frames > 0)
|
||||
if(g->blank_frames > 0)
|
||||
return 0;
|
||||
|
||||
if(menu_active) {
|
||||
if(input.left_trigger && menu_cursor > 0) {
|
||||
menu_cursor--;
|
||||
if(menu) {
|
||||
if(input.left_trigger && g->menu_cursor > 0) {
|
||||
g->menu_cursor--;
|
||||
}
|
||||
if(input.right_trigger && menu_cursor + 1 < LEVEL_COUNT) {
|
||||
menu_cursor++;
|
||||
if(input.right_trigger && g->menu_cursor + 1 < level_count()) {
|
||||
g->menu_cursor++;
|
||||
}
|
||||
if(input.up_trigger && menu_cursor >= 3) {
|
||||
menu_cursor -= 3;
|
||||
if(input.up_trigger && g->menu_cursor >= 3) {
|
||||
g->menu_cursor -= 3;
|
||||
}
|
||||
if(input.down_trigger && menu_cursor + 3 < LEVEL_COUNT) {
|
||||
menu_cursor += 3;
|
||||
if(input.down_trigger && g->menu_cursor + 3 < level_count()) {
|
||||
g->menu_cursor += 3;
|
||||
}
|
||||
if(input.enter) {
|
||||
world_level_transition(world);
|
||||
load_level_number(menu_cursor);
|
||||
menu_active = false;
|
||||
game_load_level(g, g->menu_cursor, 0);
|
||||
menu = game_in_menu(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,7 +392,7 @@ int update(void)
|
|||
static num const fall_speed = 2;
|
||||
static float const barrel_snap = 0.5;
|
||||
|
||||
if(!menu_active) {
|
||||
if(!menu) {
|
||||
if(input.left) {
|
||||
camera->pos -= mv_speed * camera->right;
|
||||
camera->yaw = fmaxf(camera->yaw - rot_speed, -rot_max);
|
||||
|
@ -516,88 +431,81 @@ int update(void)
|
|||
camera_update_angles(camera);
|
||||
}
|
||||
|
||||
world->depth += fall_speed;
|
||||
world->neon_position += world->neon_period - num16(fall_speed);
|
||||
world->neon_position %= world->neon_period;
|
||||
g->depth += fall_speed;
|
||||
g->neon_position += g->neon_period - num16(fall_speed);
|
||||
g->neon_position %= g->neon_period;
|
||||
|
||||
if(menu_active)
|
||||
if(menu)
|
||||
return 0;
|
||||
|
||||
// Remove old world elements
|
||||
// Apply collision with plane
|
||||
|
||||
struct world *w = world;
|
||||
|
||||
if(w->mirror && w->depth > w->mirror->end)
|
||||
w->mirror = NULL;
|
||||
if(w->plane && w->depth > w->plane->y - num(4)) {
|
||||
/* Apply plane effect */
|
||||
if((w->plane->type == ELEMENT_PLANE_DAMAGE ||
|
||||
w->plane->type == ELEMENT_PLANE_INVIS)
|
||||
&& level_plane_collides(num16(camera->pos.x), num16(camera->pos.z),
|
||||
w->plane->shape))
|
||||
{
|
||||
world_reset(w);
|
||||
reset_frames = 2;
|
||||
}
|
||||
else if(w->plane->type == ELEMENT_PLANE_ARROW &&
|
||||
camera->roll_quadrant != w->plane->data) {
|
||||
world_reset(w);
|
||||
reset_frames = 2;
|
||||
}
|
||||
w->plane = NULL;
|
||||
struct element_plane const *p = game_plane_collision(g);
|
||||
if((p->type == ELEMENT_PLANE_DAMAGE || p->type == ELEMENT_PLANE_INVIS)
|
||||
&& level_plane_collides(num16(camera->pos.x), num16(camera->pos.z),
|
||||
p->shape))
|
||||
{
|
||||
game_restart_level(g, 2);
|
||||
}
|
||||
if(w->text && w->depth > w->text->end)
|
||||
w->text = NULL;
|
||||
else if(p->type == ELEMENT_PLANE_ARROW && camera->roll_quadrant != p->data)
|
||||
game_restart_level(g, 2);
|
||||
|
||||
// Load incoming world elements
|
||||
// Load incoming level elements
|
||||
|
||||
struct level const *level = levels[current_level];
|
||||
game_advance_in_level(g);
|
||||
|
||||
if(!w->mirror && w->mirror_index < level->mirror_count
|
||||
&& level->mirrors[w->mirror_index].begin < w->depth + num(64)) {
|
||||
w->mirror = &level->mirrors[w->mirror_index++];
|
||||
}
|
||||
if(!w->plane && w->plane_index < level->plane_count
|
||||
&& level->planes[w->plane_index].y < w->depth + num(64)) {
|
||||
w->plane = &level->planes[w->plane_index++];
|
||||
}
|
||||
if(!w->text && w->text_index < level->text_count
|
||||
&& level->texts[w->text_index].begin < w->depth + num(64)) {
|
||||
w->text = &level->texts[w->text_index++];
|
||||
}
|
||||
|
||||
// End of level
|
||||
|
||||
if(!w->mirror && !w->plane && !w->text && w->depth >= level->finish
|
||||
&& !reset_frames) {
|
||||
if(current_level >= LEVEL_COUNT-1) {
|
||||
world_level_transition(w);
|
||||
menu_active = true;
|
||||
}
|
||||
else {
|
||||
world_level_transition(w);
|
||||
load_level_number(current_level + 1);
|
||||
}
|
||||
if(!g->mirror && !g->plane && !g->text && g->depth >= g->level->finish
|
||||
&& !g->blank_frames) {
|
||||
game_next_level_or_menu(g);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
static struct game *game = NULL;
|
||||
static bool debug = false;
|
||||
|
||||
void render(void)
|
||||
{
|
||||
game_render(game);
|
||||
platform_render();
|
||||
|
||||
#ifdef AZUR_TOOLKIT_GINT
|
||||
if(debug) {
|
||||
drect(0, DHEIGHT-20, DWIDTH-1, DHEIGHT-1, C_WHITE);
|
||||
dprint(4, 209, C_BLACK, "render:%4d+%4dus",
|
||||
prof_time(azrp_perf_render) - prof_time(azrp_perf_r61524),
|
||||
prof_time(azrp_perf_r61524));
|
||||
r61524_display(gint_vram, DHEIGHT-20, 20, R61524_DMA_WAIT);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int update(void)
|
||||
{
|
||||
return game_update(game, &debug);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if(azur_init("Chaos Drop!", 3*VWIDTH, 3*VHEIGHT))
|
||||
return 1;
|
||||
|
||||
struct camera c = {};
|
||||
camera = &c;
|
||||
struct camera camera = {};
|
||||
/* TODO: Why do I need such a low FOV?! */
|
||||
camera_set_fov(camera, 80.0);
|
||||
camera_update_angles(camera);
|
||||
camera_set_fov(&camera, 80.0);
|
||||
camera_update_angles(&camera);
|
||||
|
||||
struct world w = {};
|
||||
load_level_number(0);
|
||||
world_reset(&w);
|
||||
world = &w;
|
||||
struct game g = {};
|
||||
g.camera = &camera;
|
||||
g.menu_cursor = 0;
|
||||
g.blank_frames = 0;
|
||||
g.neon_position = 0;
|
||||
g.neon_period = 64;
|
||||
game_load_menu(&g);
|
||||
game = &g;
|
||||
|
||||
init();
|
||||
int rc = azur_main_loop(render, 30, update, -1, AZUR_MAIN_LOOP_TIED);
|
||||
|
|
|
@ -32,7 +32,7 @@ svec3 svec3_of_vec3(vec3 v)
|
|||
the collision point in `*t` and the full-precision y-coordinate of that
|
||||
point in `*collision_y`. Returns the identifier of the object type hit by
|
||||
the ray. If `secondary` is true, invisible planes are not ignored. */
|
||||
static int cast_ray(struct world const *world, svec3 const &origin,
|
||||
static int cast_ray(struct game const *g, svec3 const &origin,
|
||||
svec3 const &rayDir, num16 *t, num *collision_y, bool secondary)
|
||||
{
|
||||
/* We directly compute intersections between rays and walls by exploiting
|
||||
|
@ -102,18 +102,18 @@ static int cast_ray(struct world const *world, svec3 const &origin,
|
|||
/* Determine if there is an intersection with the object plane */
|
||||
|
||||
if(__builtin_expect(
|
||||
world->plane
|
||||
&& (*collision_y > world->plane->y - world->depth)
|
||||
&& (world->plane->type != ELEMENT_PLANE_INVIS || secondary),
|
||||
g->plane
|
||||
&& (*collision_y > g->plane->y - g->depth)
|
||||
&& (g->plane->type != ELEMENT_PLANE_INVIS || secondary),
|
||||
0)) {
|
||||
num16 plane_y = num16(world->plane->y - world->depth);
|
||||
num16 plane_y = num16(g->plane->y - g->depth);
|
||||
num16 plane_t = (plane_y - origin.y) / rayDir.y;
|
||||
num16 plane_x = origin.x + plane_t * rayDir.x;
|
||||
num16 plane_z = origin.z + plane_t * rayDir.z;
|
||||
|
||||
if(level_plane_collides(plane_x, plane_z, world->plane->shape)) {
|
||||
if(level_plane_collides(plane_x, plane_z, g->plane->shape)) {
|
||||
*t = plane_t;
|
||||
*collision_y = world->plane->y - world->depth;
|
||||
*collision_y = g->plane->y - g->depth;
|
||||
return OBJECT_PLANE;
|
||||
}
|
||||
}
|
||||
|
@ -121,9 +121,10 @@ static int cast_ray(struct world const *world, svec3 const &origin,
|
|||
return hit;
|
||||
}
|
||||
|
||||
void render_fragment(struct camera const *camera, struct world const *world,
|
||||
uint16_t *fragment, int y_start, int y_height)
|
||||
void render_fragment(struct game const *g, uint16_t *fragment,
|
||||
int y_start, int y_height)
|
||||
{
|
||||
struct camera const *camera = g->camera;
|
||||
svec3 origin = svec3_of_vec3(camera->pos);
|
||||
svec3 forward = svec3_of_vec3(camera->forward);
|
||||
svec3 right = svec3_of_vec3(camera->right);
|
||||
|
@ -146,11 +147,10 @@ void render_fragment(struct camera const *camera, struct world const *world,
|
|||
for(int x = 0; x < VWIDTH; x++) {
|
||||
num16 t;
|
||||
num coll_y;
|
||||
int obj = cast_ray(world, origin, rayDir, &t, &coll_y, false);
|
||||
int obj = cast_ray(g, origin, rayDir, &t, &coll_y, false);
|
||||
bool darken = false;
|
||||
|
||||
if(__builtin_expect(
|
||||
world->mirror && (obj == LEFT || obj == RIGHT), 0)) {
|
||||
if(__builtin_expect(g->mirror && (obj==LEFT || obj==RIGHT), 0)) {
|
||||
svec3 collision;
|
||||
collision.z = origin.z + t * rayDir.z;
|
||||
|
||||
|
@ -158,37 +158,37 @@ void render_fragment(struct camera const *camera, struct world const *world,
|
|||
bool ok_z = collision.z >= num16(-WORLD_SIZE / 2)
|
||||
&& collision.z < num16(WORLD_SIZE / 2);
|
||||
/* Mirror also does not go on forever */
|
||||
bool ok_y = world->mirror
|
||||
&& coll_y >= (world->mirror->begin - world->depth)
|
||||
&& coll_y < (world->mirror->end - world->depth);
|
||||
bool ok_y = g->mirror
|
||||
&& coll_y >= (g->mirror->begin - g->depth)
|
||||
&& coll_y < (g->mirror->end - g->depth);
|
||||
|
||||
if(ok_z && ok_y) {
|
||||
collision.x = origin.x + t * rayDir.x;
|
||||
collision.y = num16(coll_y);
|
||||
rayDir.x = -rayDir.x;
|
||||
obj = cast_ray(world, collision, rayDir, &t, &coll_y,true);
|
||||
obj = cast_ray(g, collision, rayDir, &t, &coll_y,true);
|
||||
darken = true;
|
||||
rayDir.x = -rayDir.x;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t color = object_colors[
|
||||
obj + (obj == OBJECT_PLANE ? world->plane->type : 0)];
|
||||
obj + (obj == OBJECT_PLANE ? g->plane->type : 0)];
|
||||
|
||||
/* Don't show neons that are too far to avoid flickering */
|
||||
if(coll_y < 64 && obj != OBJECT_PLANE) {
|
||||
num16 neon_pos = world->neon_position;
|
||||
num16 neon_pos = g->neon_position;
|
||||
if(obj == TOP || obj == BOTTOM)
|
||||
neon_pos += world->neon_period * num16(0.5);
|
||||
neon_pos += g->neon_period * num16(0.5);
|
||||
num16 neon = num16(coll_y) - neon_pos;
|
||||
neon.v = neon.v & (world->neon_period.v - 1);
|
||||
neon.v = neon.v & (g->neon_period.v - 1);
|
||||
/* Also make neons larger when they're far to further avoid
|
||||
flickering */
|
||||
num16 neon_size = 1;
|
||||
if(coll_y > 20)
|
||||
neon_size += ((num16(coll_y)-num16(20)) * num16(1.0/4));
|
||||
if(neon <= neon_size)
|
||||
color = world->text ? RGB(15,15,15) : 0xffff;
|
||||
color = g->text ? RGB(15,15,15) : 0xffff;
|
||||
}
|
||||
else if(__builtin_expect(coll_y >= 64, 0)) {
|
||||
if(coll_y > 128)
|
||||
|
|
Loading…
Reference in New Issue