#include "level.h" #include "generator.h" #include "render.h" #include "game.h" #include "util.h" #include "log.h" #include "menu.h" #include #include #include #include #include #include #include #include #include int play_level(int level_id) { struct game game; struct camera *camera = &game.camera; struct player *player = &game.player; game.level = level_create(level_id); game.t = 0.0; game.sections_passed = 0; game.debug.footer = false; camera->set_fov(120.0); camera->screen_size = vec2(DWIDTH, DHEIGHT); player->z = 0.0; player->vz = 3.0; player->platform = 0; player->stance = player::Falling; player->jump_dir = 0; player->jump_t = 0.0; player->height = 1.0; player->vheight = 0.0; player->frame = 0; player->energy_percent = 0.0; /* FPS regulation setup */ int volatile need_frame = 1; int last_frame_us = 0; int timer = timer_configure(TIMER_ANY, 33000, GINT_CALL_SET(&need_frame)); timer_start(timer); camera_track(camera, player); log_printf("platform distance: %s\n", str(space_platform_distance())); log_printf("player: at %s\n", str(player->pos())); log_printf("camera: at %s, screen distance %s, platform %d, " "angle vector %s\n", str(camera->pos), str(camera->screen_distance()), camera->platform, str(camera->angle_vector)); image_t *effect_bpp = NULL; bool game_run = true; while(game_run) { while(!need_frame) sleep(); need_frame = 0; //======= Initial data updates =======// num dt = 1.0 / 30; game.t += dt; prof_t perf_frame = prof_make(); prof_enter_norec(perf_frame); game.perf.effect_bpp = prof_make(); level_update(&game.level, player->z); camera_track(camera, player); struct platform const *standing_on = game_platform_under_player(&game, &game.player); //======= Rendering =======// azrp_perf_clear(); azrp_clear(game.level.bgcolor); prof_t perf_comp = prof_make(); prof_enter_norec(perf_comp); for(auto it = game.level.platform_buffer.rbegin(); it != game.level.platform_buffer.rend(); ++it) { int color = render_platform_color(&*it, &game.camera, game.t); struct prect p = space_platform_position(&*it); /* Near plane clipping */ num near = camera->pos.z + camera->near_plane(); if(p.fl.z <= near) continue; if(p.nl.z <= near) p.nl.z = near; if(p.nr.z <= near) p.nr.z = near; camera_project_prect(&game.camera, &p); render_triangle(&p.nl, &p.fr, &p.fl, color); render_triangle(&p.fr, &p.nl, &p.nr, color); } /* Render player */ vec3 player_dot = camera_project_point(&game.camera, player->pos()); struct anim *player_anim; int player_frame; player->get_anim(&player_anim, &player_frame); render_anim_frame((int)player_dot.x, (int)player_dot.y, player_anim, player_frame); if(standing_on && standing_on->type == PLATFORM_BLUE) { prof_enter(game.perf.effect_bpp); render_effect_bpp(&effect_bpp, game.t); azrp_image((int)player_dot.x - effect_bpp->width / 2, (int)player_dot.y - effect_bpp->height + 2, effect_bpp); prof_leave(game.perf.effect_bpp); } /* Render energy score */ char energy_str[32]; sprintf(energy_str, "%.2f%%", (float)player->energy_percent); azrp_rect(DWIDTH-100, 4, 96, 20, AZRP_RECT_DARKEN); render_energy_str(DWIDTH-8, 8, DTEXT_RIGHT, energy_str); prof_leave_norec(perf_comp); azrp_update(); num floor = 0; if(game.debug.footer) { drect(0, DHEIGHT-20, DWIDTH-1, DHEIGHT-1, C_WHITE); dprint(4, 209, C_BLACK, "render:%4d+%4dus comp:%4dus FPS:%02d", prof_time(azrp_perf_render) - prof_time(azrp_perf_r61524), prof_time(azrp_perf_r61524), prof_time(perf_comp), last_frame_us ? 1000000 / last_frame_us : 0); r61524_display(gint_vram, DHEIGHT-20, 20, R61524_DMA_WAIT); } //======= Input =======// key_event_t ev; while((ev = pollevent()).type != KEYEV_NONE) { if(ev.type == KEYEV_UP || ev.type == KEYEV_HOLD) continue; int key = ev.key; if(key == KEY_EXIT || key == KEY_MENU) game_run = false; if(key == KEY_OPTN) game.debug.footer = !game.debug.footer; if(key == KEY_F1) { game.level = level_create(1); level_update(&game.level, game.player.z); } if(key == KEY_F2) { game.level = level_create(2); level_update(&game.level, game.player.z); } if(key == KEY_F3) { game.level = level_create(3); level_update(&game.level, game.player.z); } if(key == KEY_LEFT && !player->airborne()) { player->stance = player::Jumping; player->jump_dir = -1; player->jump_t = 0.0; player->jump_key = key; player->vheight = JUMP_THRUST; player->frame = 0; } if((key == KEY_UP || key == KEY_SHIFT) && !player->airborne()) { player->stance = player::Jumping; player->jump_dir = 0; player->jump_t = 0.0; player->jump_key = key; player->vheight = JUMP_THRUST; player->frame = 0; } if(key == KEY_RIGHT && !player->airborne()) { player->stance = player::Jumping; player->jump_dir = +1; player->jump_t = 0.0; player->jump_key = key; player->vheight = JUMP_THRUST; player->frame = 0; } } if(!game_run) break; //======= Simulation =======// num vz = player->vz * (num(1) + player->energy_percent / 200); player->z += vz * dt; player->height += player->vheight * dt; /* Apply gravity */ num gravity = 0.0; if(player->stance == player::Jumping) { gravity = HOVERING_GRAVITY; } else if(player->stance == player::Falling) { gravity = FALLING_GRAVITY; } player->vheight += gravity * dt; floor = game_height_at(&game, player->z, player->platform); if(player->airborne()) { player->jump_t += dt; /* Update the current platform number after rotation */ if(player->jump_t > TIME_ROTATION && player->jump_dir) { int p = player->platform + player->jump_dir; p = (p + PLATFORM_COUNT) % PLATFORM_COUNT; player->platform = p; player->jump_dir = 0; } /* Switch to falling if the jump key is released */ if(player->stance == player::Jumping && player->jump_t > TIME_JUMP_THRUST_MIN && !keydown(player->jump_key)) { player->stance = player::Falling; player->vheight = -1; } if(player->height >= floor - STEP_HEIGHT && player->height <= floor) { player->stance = player::Running; player->jump_dir = 0; player->jump_t = 0.0; player->height = floor; player->vheight = 0; player->jump_key = 0; player->frame = 0; } } else if(floor < player->height) { player->stance = player::Falling; player->vheight = 0.0; } /* Death condition #1/2: inside a platform (hit it in front) */ bool death_1 = (player->height >= floor - PLAYER_HEIGHT && player->height < floor - STEP_HEIGHT); /* Death condition #2/2: below the kill plane */ bool death_2 = (player->height < LEVEL_RADIUS - KILL_PLANE_RADIUS); if(death_1 || death_2) break; if(standing_on && standing_on->type == PLATFORM_BLUE) { player->energy_percent += dt * vz * 5.5; } game_advance(&game); prof_leave_norec(perf_frame); last_frame_us = prof_time(perf_frame); } if(effect_bpp) image_free(effect_bpp); timer_stop(timer); return 0; } int main(void) { int level; __printf_enable_fp(); prof_init(); render_init(); space_init(); extern font_t font_boson; dfont(&font_boson); #if LOG_USB_ENABLE dclear(C_WHITE); dtext_opt(DWIDTH/2, DHEIGHT/2, C_BLACK, C_NONE, DTEXT_CENTER, DTEXT_MIDDLE, "Waiting for USB log...", -1); dupdate(); log_init(true); #endif while (1) { if (menu_title() != 0) { gint_osmenu(); continue; } while (menu_select_level(&level) >= 0) { play_level(level + 1); } } return 0; }