Compare commits

...

3 Commits

Author SHA1 Message Date
Lephenixnoir 4b835efb83
energy, speed increase, level bg color
Weird bug occurred on lv2 after going through the blue platform for the
4th time and reaching 100%, blue flashes and eventually a System ERROR.
Could not reproduce by increasing the energy collection rate, even at
200%.
2023-06-01 01:23:57 +02:00
Lephenixnoir 0b99ee6a38
update to Azur's implicit shader configuration 2023-05-29 12:47:21 +02:00
Lephenixnoir b6fb44c80a
platform colors and blue platform effect 2023-05-28 10:07:53 +02:00
11 changed files with 245 additions and 33 deletions

View File

@ -28,6 +28,7 @@ set(ASSETS
assets-cg/bosonx_logo_empty.png
assets-cg/lepheyatis_logo.png
assets-cg/font_boson.png
assets-cg/font_energy.png
assets-cg/erik_running.gif
assets-cg/erik_jumping.gif
assets-cg/stages/stage1.png

BIN
assets-cg/font_energy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 B

View File

@ -33,6 +33,11 @@ font_boson.png:
proportional: true
height: 9
font_energy.png:
type: bopti-image
name: img_font_energy
profile: p8_rgb565a
*.gif:
custom-type: animation
name_regex: (.*)\.gif anim_\1

View File

@ -154,19 +154,18 @@ num game_height_at(struct game *game, num z, int face)
: -KILL_PLANE_RADIUS;
}
#if 0
bool game_player_above_platform(struct game *game, num height)
const struct platform *game_platform_under_player(struct game const *game,
struct player const *player)
{
struct player const *player = &game->player;
if(player->stance != player::Running)
return NULL;
for(auto const &p: game->level.platform_buffer) {
if(player->platform == p.face
&& player->z >= p.z && player->z <= p.z + p.length
&& height >= space_platform_height(p.height)) {
return true;
&& player->z >= p.z && player->z <= p.z + p.length) {
return &p;
}
}
return false;
return NULL;
}
#endif

View File

@ -6,6 +6,7 @@
#include "level.h"
#include <gint/display.h>
#include <libprof.h>
/* A player's movement and data information. */
struct player
@ -67,7 +68,10 @@ struct player
//======= Data =======//
/* TODO: Energy -> speed multiplier, skin, others? */
/* Energy collected, in percent */
num energy_percent;
/* TODO: Skin, others? */
};
/* Dynamic information about one or multiple attempts at a single level. */
@ -85,6 +89,10 @@ struct game
struct {
bool footer; /* Show performance footer */
} debug;
struct {
prof_t effect_bpp;
} perf;
};
//======= Functions on the game world space =======//
@ -116,10 +124,8 @@ void game_advance(struct game *game);
/* Get platform height at the provided position. */
num game_height_at(struct game *game, num z, int face);
#if 0
/* Check if the player would be standing over a platform with the provided
height coordinate. This ignores player's height value. */
bool game_player_above_platform(struct game *game, num height);
#endif
/* Returns the platform on which the player is running, if any. */
const struct platform *game_platform_under_player(struct game const *game,
struct player const *player);
#endif /* __GAME_H__ */

View File

@ -4,7 +4,7 @@
#include <stdlib.h>
/* Geometric parameters */
#define G_PLATFORM_LEN num(3.0)
#define G_PLATFORM_LEN num(2.5)
#define G_PLATFORM_SPC num(0.5)
#define G_PLATFORM_LEN_INITIAL num(6.0)
/* Probabilities */
@ -39,7 +39,8 @@ AcceleronGenerator::AcceleronGenerator():
....R..... [h=8]
....|.....
....|.....
...B|..... [h=5]
....|.....
...B...... [h=5]
...|.#.... [h=4]
...|.|....
....#..... [h=1]
@ -90,22 +91,23 @@ static num generate_ascending_funnel(struct level *level, num z)
p.length = G_PLATFORM_LEN * 3;
p.height = 8;
level->platform_buffer.push_back(p);
z += G_PLATFORM_LEN * 3 + G_PLATFORM_SPC;
p.type = PLATFORM_BLUE;
p.face = 3;
p.z = z + G_PLATFORM_LEN * 2;
p.z = z;
p.length = G_PLATFORM_LEN * 3;
p.height = 5;
level->platform_buffer.push_back(p);
p.type = PLATFORM_WHITE;
p.face = 5;
p.z = z + G_PLATFORM_LEN * 3;
p.z = z + G_PLATFORM_LEN;
p.length = G_PLATFORM_LEN * 2;
p.height = 4;
level->platform_buffer.push_back(p);
z += G_PLATFORM_LEN * 5 + G_PLATFORM_SPC;
z += G_PLATFORM_LEN * 3 + G_PLATFORM_SPC;
/* Exit platform */
p.type = PLATFORM_WHITE;

View File

@ -1,5 +1,6 @@
#include "level.h"
#include "generator.h"
#include "util.h"
#include <gint/display.h>
struct level level_create(int level)
@ -7,14 +8,18 @@ struct level level_create(int level)
struct level l;
switch(level) {
default:
l.gen = std::make_unique<struct gen1>();
l.bgcolor = RGB24(0x49759f);
break;
case 2:
l.gen = std::make_unique<AcceleronGenerator>();
l.bgcolor = RGB24(0xe7c272);
break;
case 3:
l.gen = std::make_unique<struct gen3>();
l.bgcolor = C_WHITE;
break;
default:
l.gen = std::make_unique<struct gen1>();
}
return l;
}

View File

@ -26,6 +26,7 @@ struct Generator;
struct level {
std::vector<struct platform> platform_buffer;
std::unique_ptr<Generator> gen;
uint16_t bgcolor;
};

View File

@ -39,6 +39,7 @@ int play_level(int level_id)
player->height = 1.0;
player->vheight = 0.0;
player->frame = 0;
player->energy_percent = 0.0;
/* FPS regulation setup */
int volatile need_frame = 1;
@ -56,6 +57,8 @@ int play_level(int level_id)
camera->platform,
str(camera->angle_vector));
image_t *effect_bpp = NULL;
bool game_run = true;
while(game_run) {
while(!need_frame) sleep();
@ -67,14 +70,18 @@ int play_level(int level_id)
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(RGB24(0x49759f));
azrp_clear(game.level.bgcolor);
prof_t perf_comp = prof_make();
prof_enter_norec(perf_comp);
@ -82,7 +89,7 @@ int play_level(int level_id)
for(auto it = game.level.platform_buffer.rbegin();
it != game.level.platform_buffer.rend();
++it) {
int color = camera_platform_color(&game.camera, it->face);
int color = render_platform_color(&*it, &game.camera, game.t);
struct prect p = space_platform_position(&*it);
/* Near plane clipping */
@ -104,6 +111,21 @@ int play_level(int level_id)
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();
@ -173,7 +195,8 @@ int play_level(int level_id)
//======= Simulation =======//
player->z += player->vz * dt;
num vz = player->vz * (num(1) + player->energy_percent / 200);
player->z += vz * dt;
player->height += player->vheight * dt;
/* Apply gravity */
@ -203,7 +226,7 @@ int play_level(int level_id)
&& player->jump_t > TIME_JUMP_THRUST_MIN
&& !keydown(player->jump_key)) {
player->stance = player::Falling;
player->vheight = 0.0;
player->vheight = -1;
}
if(player->height >= floor - STEP_HEIGHT
@ -231,11 +254,18 @@ int play_level(int level_id)
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;
}
@ -246,6 +276,7 @@ int main(void)
__printf_enable_fp();
prof_init();
render_init();
space_init();
extern font_t font_boson;
@ -259,12 +290,6 @@ int main(void)
log_init(true);
#endif
azrp_config_scale(1);
azrp_shader_clear_configure();
azrp_shader_image_p8_configure();
azrp_shader_image_p4_configure();
azrp_shader_triangle_configure();
while (1) {
if (menu_title() != 0) {
gint_osmenu();

View File

@ -72,7 +72,7 @@ void camera_project_prect(struct camera *camera, struct prect *p)
p->fr.y = -p->fr.y * far_f + half_screen.y;
}
int camera_platform_color(struct camera *camera, int platform_id)
int camera_platform_color(struct camera const *camera, int platform_id)
{
/* Accounting for the full angle is too precise and results in weird
color jumps at different times across platforms, instead switch at half
@ -86,6 +86,62 @@ int camera_platform_color(struct camera *camera, int platform_id)
return C_RGB(gray, gray, gray);
}
//======= Rendering tools =======//
static uint16_t blue_ramp[32];
static void split_RGB(uint32_t RGB, int *R, int *G, int *B)
{
*R = (RGB >> 16) & 0xff;
*G = (RGB >> 8) & 0xff;
*B = (RGB >> 0) & 0xff;
}
static uint32_t make_RGB(int R, int G, int B)
{
return ((R & 0xff) << 16) | ((G & 0xff) << 8) | (B & 0xff);
}
static void gradient(uint32_t RGB1, uint32_t RGB2, uint16_t *gradient, int N)
{
int R1, G1, B1, R2, G2, B2;
split_RGB(RGB1, &R1, &G1, &B1);
split_RGB(RGB2, &R2, &G2, &B2);
for(int i = 0; i < N; i++) {
int R = ((N-1-i) * R1 + i * R2) / (N-1);
int G = ((N-1-i) * G1 + i * G2) / (N-1);
int B = ((N-1-i) * B1 + i * B2) / (N-1);
gradient[i] = RGB24(make_RGB(R, G, B));
}
}
void render_init(void)
{
/* Generate a gradient ramp for blue platforms */
gradient(0x5090d0, 0x2060b0, blue_ramp, 32);
}
uint16_t render_color_blue_platform(num t)
{
int step = (int)(32 * t.frac()) & 31;
int phase = (int)t & 1;
return phase ? blue_ramp[31 - step] : blue_ramp[step];
}
uint16_t render_platform_color(struct platform const *p,
struct camera const *camera, num t)
{
if(p->type == PLATFORM_WHITE)
return camera_platform_color(camera, p->face);
if(p->type == PLATFORM_BLUE)
return render_color_blue_platform(t);
if(p->type == PLATFORM_RED)
return RGB24(0xd06060);
return RGB24(0xff00ff);
}
void render_triangle(vec3 *p1, vec3 *p2, vec3 *p3, int color)
{
azrp_triangle(
@ -109,3 +165,95 @@ void render_anim_frame(int x, int y, struct anim *anim, int frame)
y + anim->y_offsets[frame] - anim->y_anchor,
anim->frames[frame]);
}
static bool render_energy_str_glyph_params(int c, int *ix, int *w)
{
if(c >= '0' && c <= '9') {
*ix = 13 * (c - '0') - (c >= '2' ? 3 : 0);
*w = (c == '1') ? 8 : 11;
return true;
}
if(c == '.') {
*ix = 127;
*w = 4;
return true;
}
if(c == '%') {
*ix = 132;
*w = 8;
return true;
}
return false;
}
void render_energy_str(int x, int y, int halign, char const *str)
{
extern image_t img_font_energy;
int ix, w;
/* First compute width of string */
int total_width = 0;
for(int i = 0; str[i]; i++) {
if(render_energy_str_glyph_params(str[i], &ix, &w))
total_width += w + 2;
}
total_width -= (total_width ? 2 : 0);
/* Apply horizontal alignment */
if(halign == DTEXT_CENTER)
x -= total_width >> 1;
if(halign == DTEXT_RIGHT)
x -= total_width - 1;
/* Render string */
for(int i = 0; str[i]; i++) {
if(!render_energy_str_glyph_params(str[i], &ix, &w))
continue;
azrp_subimage(x, y, &img_font_energy, ix, 0, w,
img_font_energy.height, DIMAGE_NONE);
x += w + 2;
}
}
void render_effect_bpp(image_t **image, num t)
{
enum { BPP_PARTICLE = 0x81 };
static uint16_t bpp_palette[] = {
[0] = RGB24(0xff00ff), /* alpha */
[BPP_PARTICLE-0x80] = RGB24(0x5090d0),
};
static int const bpp_W = 34;
static int const bpp_H = 68;
if(!*image) {
*image = image_alloc(bpp_W, bpp_H, IMAGE_P8_RGB565A);
image_set_palette(*image, bpp_palette, 1, false);
}
image_clear(*image);
uint8_t *pixels = (uint8_t *)(*image)->data;
for(int i = 0; i < 24; i++) {
/* Particule #i appears after i 32-th of a second */
num start = num(i) / 32;
if(t < start)
continue;
num16 local_time = num16(2 * ((t - start) % num(0.5)));
int x0_int = (23 * i) % (bpp_W - 2);
num16 x0 = num16(x0_int);
num16 y0 = num16(bpp_H - 1 - ((37 * i) & 15));
num16 vx = num16(bpp_W / 2 - x0_int) / 4;
num16 x = x0 + vx * local_time;
num16 y = y0 - (bpp_H - 16) * local_time;
for(int dy = 0; dy <= 3; dy++)
for(int dx = 0; dx <= 3; dx++) {
pixels[((int)y + dy) * (*image)->stride + (int)x + dx] =
BPP_PARTICLE;
}
}
}

View File

@ -69,7 +69,20 @@ vec3 camera_project_point(struct camera *, vec3 point);
void camera_project_prect(struct camera *, struct prect *rect);
/* Compute the platform's color based on the camera's angle. */
int camera_platform_color(struct camera *camera, int platform_id);
int camera_platform_color(struct camera const *camera, int platform_id);
//======= Rendering tools =======//
/* Initialize/precompute globals. */
void render_init(void);
/* Color of a blue platform at the specified world time. */
uint16_t render_color_blue_platform(num t);
/* Color of the provided platform viewed from the provided camera at the given
world time. */
uint16_t render_platform_color(struct platform const *p,
struct camera const *camera, num t);
/* Queue an Azur command to render the triangle defined by p1/p2/p3. Only the
x/y coordinates are used, z is ignored. */
@ -79,7 +92,14 @@ void render_triangle(vec3 *p1, vec3 *p2, vec3 *p3, int color);
used, z is ignored. */
void render_dots(std::initializer_list<vec3> const &&points);
/* Render an energy string (energy font, characters supported: 0-9.%) */
void render_energy_str(int x, int y, int halign, char const *str);
/* Render a frame of an animation. */
void render_anim_frame(int x, int y, struct anim *anim, int frame);
/* Render the blue platform particle effect at time t. If *image is NULL,
creates it automatically. */
void render_effect_bpp(image_t **image, num t);
#endif /* __RENDERH__ */