More UI features & leaderboards for level time
This commit is contained in:
parent
437ad8c4b0
commit
36ba0b1c9f
12
app.c
12
app.c
@ -37,11 +37,12 @@ App *app_NewApp() {
|
|||||||
ui_RebuildUI(app->ui);
|
ui_RebuildUI(app->ui);
|
||||||
ui_PushState(app->ui, ui_TitleMenu);
|
ui_PushState(app->ui, ui_TitleMenu);
|
||||||
|
|
||||||
app->switch_level = NULL;
|
app->current_level = NULL;
|
||||||
app->timescale = 1.0;
|
app->switch_level = NULL;
|
||||||
app->clear_color = RGB(40, 40, 40);
|
app->timescale = 1.0;
|
||||||
app->wantQuit = false;
|
app->clear_color = RGB(40, 40, 40);
|
||||||
app->paused = false;
|
app->wantQuit = false;
|
||||||
|
app->paused = false;
|
||||||
|
|
||||||
app_QueueLoadLevel(app, "title.txt");
|
app_QueueLoadLevel(app, "title.txt");
|
||||||
|
|
||||||
@ -83,6 +84,7 @@ void app_Advance(App *app, Duration deltaTime) {
|
|||||||
physics_Advance(app->physics, delta_game);
|
physics_Advance(app->physics, delta_game);
|
||||||
entity_Advance(app->entity, delta_game);
|
entity_Advance(app->entity, delta_game);
|
||||||
camera_Advance(app->camera, delta_game);
|
camera_Advance(app->camera, delta_game);
|
||||||
|
app->level_playtime.microseconds += deltaTime.microseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_Advance(app->ui, deltaTime);
|
ui_Advance(app->ui, deltaTime);
|
||||||
|
2
app.h
2
app.h
@ -28,7 +28,9 @@ typedef struct _App {
|
|||||||
System_GameTime *time;
|
System_GameTime *time;
|
||||||
System_UI *ui;
|
System_UI *ui;
|
||||||
|
|
||||||
|
char *current_level;
|
||||||
char *switch_level;
|
char *switch_level;
|
||||||
|
Duration level_playtime;
|
||||||
double timescale;
|
double timescale;
|
||||||
uint32_t clear_color;
|
uint32_t clear_color;
|
||||||
bool wantQuit, debugOn;
|
bool wantQuit, debugOn;
|
||||||
|
@ -47,7 +47,7 @@ void app_DebugText(App *app, vector_Vector *vec_string) {
|
|||||||
PUSH_STRING(buf);
|
PUSH_STRING(buf);
|
||||||
snprintf(
|
snprintf(
|
||||||
buf, sizeof(buf) - 1,
|
buf, sizeof(buf) - 1,
|
||||||
"Particle count[0]: %d\n\nUI Stack:\n", tree_Count(app->particle->parts[0]));
|
"Particle count[0]: %d\n\nCurrent Level: %s\nPlaytime: %.4lfs\n\nUI Stack:\n", tree_Count(app->particle->parts[0]), (app->current_level ? app->current_level : "NULL"), duration_Seconds(app->level_playtime));
|
||||||
PUSH_STRING(buf);
|
PUSH_STRING(buf);
|
||||||
|
|
||||||
for (int i = 0; i < vector_Size(app->ui->state); i++) {
|
for (int i = 0; i < vector_Size(app->ui->state); i++) {
|
||||||
|
11
app_file.c
11
app_file.c
@ -172,7 +172,7 @@ static void _app_LevelCommand(App *app, char *cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CMD("PUT_CAMERA") {
|
CMD("PUT_CAMERA") {
|
||||||
Vec2 center = readvec2();
|
Vec2 center = readvec2();
|
||||||
app->camera->cam = box2_FromCenter(center, app->camera->screen.size);
|
app->camera->cam = box2_FromCenter(center, app->camera->screen.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,8 @@ void _app_SwitchLevel(App *app) {
|
|||||||
// Clear the current level
|
// Clear the current level
|
||||||
entity_Clear(app->entity);
|
entity_Clear(app->entity);
|
||||||
particle_Clear(app->particle);
|
particle_Clear(app->particle);
|
||||||
app->camera->target = NULL;
|
app->camera->target = NULL;
|
||||||
|
app->level_playtime.microseconds = 0;
|
||||||
|
|
||||||
// Read every line
|
// Read every line
|
||||||
char linebuf[512];
|
char linebuf[512];
|
||||||
@ -253,7 +254,9 @@ void _app_SwitchLevel(App *app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
free(app->switch_level);
|
if (app->current_level)
|
||||||
app->switch_level = NULL;
|
free(app->current_level);
|
||||||
|
app->current_level = app->switch_level;
|
||||||
|
app->switch_level = NULL;
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "render_util.h"
|
#include "render_util.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "ui.h"
|
||||||
#include "util/assert.h"
|
#include "util/assert.h"
|
||||||
#include "util/rand.h"
|
#include "util/rand.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -171,7 +172,7 @@ void misc_thinker_ChangeLevel(App *app, Entity *e, Duration deltaTime) {
|
|||||||
|
|
||||||
Box2 worldbox = ABSOLUTE_BOX(e, e->misc->trigger);
|
Box2 worldbox = ABSOLUTE_BOX(e, e->misc->trigger);
|
||||||
if (box2_Intersects(worldbox, playerbox, NULL))
|
if (box2_Intersects(worldbox, playerbox, NULL))
|
||||||
app_QueueLoadLevel(app, e->misc->change_level);
|
ui_EnterIntermission(app->ui, e->misc->change_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
8
types.c
8
types.c
@ -107,6 +107,14 @@ Box2 box2_FromCenter(Vec2 center, Vec2 size) {
|
|||||||
.y = center.y - size.y / 2.0}};
|
.y = center.y - size.y / 2.0}};
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
Box2 box2_FromPivot(Vec2 position, Vec2 pivot, Vec2 size) {
|
||||||
|
Box2 box = {
|
||||||
|
.size = size,
|
||||||
|
.lefttop = {
|
||||||
|
.x = position.x - size.x * pivot.x,
|
||||||
|
.y = position.y - size.y * pivot.y}};
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
Box2 box2_Offset(Box2 box, Vec2 offset) {
|
Box2 box2_Offset(Box2 box, Vec2 offset) {
|
||||||
box.lefttop = vec2_Add(box.lefttop, offset);
|
box.lefttop = vec2_Add(box.lefttop, offset);
|
||||||
|
7
types.h
7
types.h
@ -70,6 +70,12 @@ static inline Box2 box2(double x, double y, double width, double height) {
|
|||||||
b.size.y = height;
|
b.size.y = height;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
static inline Box2 box2v(Vec2 lefttop, Vec2 size) {
|
||||||
|
Box2 b;
|
||||||
|
b.lefttop = lefttop;
|
||||||
|
b.size = size;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Intersection test.
|
// Intersection test.
|
||||||
@ -79,6 +85,7 @@ bool box2_Contains(const Box2 box, const Vec2 point);
|
|||||||
|
|
||||||
Vec2 box2_Center(Box2 box);
|
Vec2 box2_Center(Box2 box);
|
||||||
Box2 box2_FromCenter(Vec2 center, Vec2 size);
|
Box2 box2_FromCenter(Vec2 center, Vec2 size);
|
||||||
|
Box2 box2_FromPivot(Vec2 position, Vec2 pivot, Vec2 size);
|
||||||
|
|
||||||
Box2 box2_Offset(Box2 box, Vec2 offset);
|
Box2 box2_Offset(Box2 box, Vec2 offset);
|
||||||
Box2 box2_OffsetX(Box2 box, double offsetX);
|
Box2 box2_OffsetX(Box2 box, double offsetX);
|
||||||
|
10
ui.c
10
ui.c
@ -12,7 +12,9 @@ const char *ui_StateTitle[ui_StateCount] = {
|
|||||||
"Pause Menu",
|
"Pause Menu",
|
||||||
"Jack's Escape (ver. 3.141592) - Title",
|
"Jack's Escape (ver. 3.141592) - Title",
|
||||||
"Select Level",
|
"Select Level",
|
||||||
"Options"};
|
"Options",
|
||||||
|
"Level Finished",
|
||||||
|
"Leaderboards"};
|
||||||
|
|
||||||
|
|
||||||
static inline double dabs(double x) { return x > 0 ? x : -x; }
|
static inline double dabs(double x) { return x > 0 ? x : -x; }
|
||||||
@ -32,7 +34,8 @@ void ui_DeleteSystem(System_UI *sys) {
|
|||||||
for (int i = 0; i < ui_StateCount; i++)
|
for (int i = 0; i < ui_StateCount; i++)
|
||||||
for (int j = 0; j < vector_Size(sys->parts[i]); j++) {
|
for (int j = 0; j < vector_Size(sys->parts[i]); j++) {
|
||||||
ui_Part *part = (ui_Part *)vector_At(sys->parts[i], j);
|
ui_Part *part = (ui_Part *)vector_At(sys->parts[i], j);
|
||||||
part->free(sys, part, part->user);
|
if (part->free)
|
||||||
|
part->free(sys, part, part->user);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < ui_StateCount; i++)
|
for (int i = 0; i < ui_StateCount; i++)
|
||||||
vector_Destroy(sys->parts[i]);
|
vector_Destroy(sys->parts[i]);
|
||||||
@ -102,7 +105,8 @@ void ui_Advance(System_UI *sys, Duration deltaTime) {
|
|||||||
part->progress = dmax(part->progress - UI_BUTTON_HOVER_SPEED * duration_Seconds(deltaTime), 0.0);
|
part->progress = dmax(part->progress - UI_BUTTON_HOVER_SPEED * duration_Seconds(deltaTime), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
part->update(sys, part, part->user, deltaTime);
|
if (part->update)
|
||||||
|
part->update(sys, part, part->user, deltaTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
54
ui.h
54
ui.h
@ -17,6 +17,8 @@ typedef enum {
|
|||||||
ui_TitleMenu,
|
ui_TitleMenu,
|
||||||
ui_SceneSelect,
|
ui_SceneSelect,
|
||||||
ui_Options,
|
ui_Options,
|
||||||
|
ui_InterMission,
|
||||||
|
ui_Leaderboards,
|
||||||
ui_StateCount // Keep at last
|
ui_StateCount // Keep at last
|
||||||
} ui_State;
|
} ui_State;
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ typedef struct _ui_Part {
|
|||||||
uintptr_t user; // user data
|
uintptr_t user; // user data
|
||||||
void (*draw)(System_UI *sys, struct _ui_Part *part, uintptr_t user); // called when the UI is to be drawn
|
void (*draw)(System_UI *sys, struct _ui_Part *part, uintptr_t user); // called when the UI is to be drawn
|
||||||
void (*update)(System_UI *sys, struct _ui_Part *part, uintptr_t user, Duration deltatime); // called when the element is to be updated
|
void (*update)(System_UI *sys, struct _ui_Part *part, uintptr_t user, Duration deltatime); // called when the element is to be updated
|
||||||
void (*free)(System_UI *sys, struct _ui_Part *part, uintptr_t user); // called when the element is to be deleted
|
void (*free)(System_UI *sys, struct _ui_Part *part, uintptr_t user); // called when the element is to be deleted, dont free part!
|
||||||
} ui_Part;
|
} ui_Part;
|
||||||
|
|
||||||
// UI system with its own state machine.
|
// UI system with its own state machine.
|
||||||
@ -57,12 +59,17 @@ void ui_PushPart(System_UI *sys, ui_State layer, ui_Part part);
|
|||||||
void ui_Advance(System_UI *sys, Duration deltaTime);
|
void ui_Advance(System_UI *sys, Duration deltaTime);
|
||||||
void ui_Render(System_UI *sys);
|
void ui_Render(System_UI *sys);
|
||||||
|
|
||||||
void ui_PushState(System_UI *sys, ui_State push_state);
|
void ui_PushState(System_UI *sys, ui_State push_state);
|
||||||
void ui_PopState(System_UI *sys);
|
void ui_PopState(System_UI *sys);
|
||||||
|
|
||||||
ui_State ui_CurrentState(System_UI *sys);
|
ui_State ui_CurrentState(System_UI *sys);
|
||||||
|
|
||||||
|
|
||||||
|
// Called when the level is finished
|
||||||
|
// If next_level is NULL, there are no next level and the
|
||||||
|
// button returns to title screen
|
||||||
|
void ui_EnterIntermission(System_UI *sys, const char *next_level);
|
||||||
|
|
||||||
|
|
||||||
#define UI_PADDING (16)
|
#define UI_PADDING (16)
|
||||||
#define UI_BACKGROUND (0)
|
#define UI_BACKGROUND (0)
|
||||||
|
|
||||||
@ -96,6 +103,45 @@ ui_Part ui_Button_NewLeftAligned(Box2 box, const char *label, ui_ActionCallback
|
|||||||
// ui_Part ui_Button_NewColored(Box2 box, const char *label, uint32_t bg, uint32_t hover, uint32_t clicked, ui_ActionCallback callback, uintptr_t data);
|
// ui_Part ui_Button_NewColored(Box2 box, const char *label, uint32_t bg, uint32_t hover, uint32_t clicked, ui_ActionCallback callback, uintptr_t data);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *label; // Allocated & copied, NULL means no label
|
||||||
|
int align; // <0: left aligned; ==0: center aligned; >0: right aligned
|
||||||
|
} ui_Label;
|
||||||
|
ui_Part ui_Label_New(Box2 box, const char *label, int alignment);
|
||||||
|
void ui_Label_SetLabel(ui_Part *part, const char *label);
|
||||||
|
|
||||||
|
// Creates a new box fill with the given color
|
||||||
|
ui_Part ui_Fill_New(Box2 box, uint32_t color);
|
||||||
|
|
||||||
|
|
||||||
|
// Box organizer
|
||||||
|
typedef struct {
|
||||||
|
vector_Vector *rows; // vector of vector_Vector* of Box2
|
||||||
|
vector_Vector *row_counts; // vector of Ints
|
||||||
|
double width; // Total width, excluding external padding
|
||||||
|
double line_height; // Line height
|
||||||
|
Vec2 position; // Position of the entire bounding box on screen
|
||||||
|
Vec2 pivot; // Pivot or Origin of the position, [0, 1]
|
||||||
|
} ui_BoxBuilder;
|
||||||
|
|
||||||
|
#define UI_BOXBUILDER_DEFAULT_LINEHEIGHT (48)
|
||||||
|
#define UI_BOXBUILDER_DEFAULT_WIDTH (400)
|
||||||
|
#define UI_BOXBUILDER_DEFAULT_PIVOT_X (0.5)
|
||||||
|
#define UI_BOXBUILDER_DEFAULT_PIVOT_Y (0.0)
|
||||||
|
|
||||||
|
ui_BoxBuilder *ui_BoxBuilder_New();
|
||||||
|
void ui_BoxBuilder_Delete(ui_BoxBuilder *builder);
|
||||||
|
|
||||||
|
// Set that this row should have this many columns
|
||||||
|
void ui_BoxBuilder_SetCount(ui_BoxBuilder *builder, int row, int num_cols);
|
||||||
|
|
||||||
|
// Assemble everything
|
||||||
|
void ui_BoxBuilder_Assemble(ui_BoxBuilder *builder);
|
||||||
|
|
||||||
|
// Every number starts from 1
|
||||||
|
Box2 ui_BoxBuilder_At(ui_BoxBuilder *builder, int row, int col);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
99
ui_boxbuilder.c
Normal file
99
ui_boxbuilder.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "util/vector.h"
|
||||||
|
|
||||||
|
ui_BoxBuilder *ui_BoxBuilder_New() {
|
||||||
|
ui_BoxBuilder *builder = zero_malloc(sizeof(ui_BoxBuilder));
|
||||||
|
builder->line_height = UI_BOXBUILDER_DEFAULT_LINEHEIGHT;
|
||||||
|
builder->width = UI_BOXBUILDER_DEFAULT_WIDTH;
|
||||||
|
builder->pivot = vec2(UI_BOXBUILDER_DEFAULT_PIVOT_X, UI_BOXBUILDER_DEFAULT_PIVOT_Y);
|
||||||
|
builder->row_counts = vector_Create(sizeof(int));
|
||||||
|
// builder->rows = vector_Create(sizeof(vector_Vector *));
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
void ui_BoxBuilder_Delete(ui_BoxBuilder *builder) {
|
||||||
|
vector_Destroy(builder->row_counts);
|
||||||
|
for (int i = 0; i < vector_Size(builder->rows); i++) {
|
||||||
|
vector_Vector *vr = *((vector_Vector **)vector_At(builder->rows, i));
|
||||||
|
if (vr)
|
||||||
|
vector_Destroy(vr);
|
||||||
|
}
|
||||||
|
vector_Destroy(builder->rows);
|
||||||
|
free(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set that this row should have this many columns
|
||||||
|
void ui_BoxBuilder_SetCount(ui_BoxBuilder *builder, int row, int num_cols) {
|
||||||
|
if (vector_Size(builder->row_counts) < row) {
|
||||||
|
size_t old_size = vector_Size(builder->row_counts);
|
||||||
|
vector_Resize(builder->row_counts, row);
|
||||||
|
// Set the new parts to zero
|
||||||
|
for (int i = old_size; i < row; i++)
|
||||||
|
*((int *)vector_At(builder->row_counts, i)) = 0;
|
||||||
|
}
|
||||||
|
*((int *)vector_At(builder->row_counts, row - 1)) = num_cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble everything
|
||||||
|
void ui_BoxBuilder_Assemble(ui_BoxBuilder *builder) {
|
||||||
|
if (builder->rows) {
|
||||||
|
// Free the previous vectors
|
||||||
|
for (int i = 0; i < vector_Size(builder->rows); i++) {
|
||||||
|
vector_Vector *vr = *((vector_Vector **)vector_At(builder->rows, i));
|
||||||
|
if (vr)
|
||||||
|
vector_Destroy(vr);
|
||||||
|
}
|
||||||
|
vector_Clear(builder->rows);
|
||||||
|
} else
|
||||||
|
builder->rows = vector_Create(sizeof(vector_Vector *));
|
||||||
|
vector_Resize(builder->rows, vector_Size(builder->row_counts));
|
||||||
|
|
||||||
|
double cursor_y = 0.0;
|
||||||
|
for (int i = 0; i < vector_Size(builder->row_counts); i++) {
|
||||||
|
int row_count = *((int *)vector_At(builder->row_counts, i));
|
||||||
|
if (row_count == 0) {
|
||||||
|
*(vector_Vector **)vector_At(builder->rows, i) = NULL;
|
||||||
|
cursor_y += UI_PADDING;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vector_Vector *row = vector_Create(sizeof(Box2));
|
||||||
|
|
||||||
|
*(vector_Vector **)vector_At(builder->rows, i) = row;
|
||||||
|
|
||||||
|
// Append every box
|
||||||
|
double total_width = builder->width - UI_PADDING * (row_count - 1);
|
||||||
|
double avg_width = total_width / row_count;
|
||||||
|
for (int i = 0; i < row_count; i++) {
|
||||||
|
Box2 box = {
|
||||||
|
.lefttop = {.x = i * (avg_width + UI_PADDING), .y = cursor_y},
|
||||||
|
.size = {.x = avg_width, .y = builder->line_height}};
|
||||||
|
vector_Push(row, &box);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor_y += builder->line_height + UI_PADDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
int row_num = vector_Size(builder->row_counts);
|
||||||
|
Vec2 max_size = {
|
||||||
|
.x = builder->width,
|
||||||
|
.y = builder->line_height * row_num + UI_PADDING * (row_num - 1)};
|
||||||
|
Box2 max_box = box2_FromPivot(builder->position, builder->pivot, max_size);
|
||||||
|
|
||||||
|
// Move every box
|
||||||
|
for (int i = 0; i < vector_Size(builder->row_counts); i++) {
|
||||||
|
int row_count = *((int *)vector_At(builder->row_counts, i));
|
||||||
|
if (row_count == 0)
|
||||||
|
continue;
|
||||||
|
vector_Vector *row = *(vector_Vector **)vector_At(builder->rows, i);
|
||||||
|
for (int i = 0; i < row_count; i++) {
|
||||||
|
Box2 *box = (Box2 *)vector_At(row, i);
|
||||||
|
box->lefttop = vec2_Add(box->lefttop, max_box.lefttop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every number starts from 1
|
||||||
|
Box2 ui_BoxBuilder_At(ui_BoxBuilder *builder, int row, int col) {
|
||||||
|
return *(Box2 *)vector_At(*(vector_Vector **)vector_At(builder->rows, row - 1), col - 1);
|
||||||
|
}
|
113
ui_build.c
113
ui_build.c
@ -1,4 +1,5 @@
|
|||||||
|
|
||||||
|
#include "render_util.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "util/vector.h"
|
#include "util/vector.h"
|
||||||
@ -17,7 +18,7 @@ static void _ui_Action_ResumeGame(System_UI *sys, ui_Part *part, uintptr_t data)
|
|||||||
static void _ui_Action_ReturnToTitle(System_UI *sys, ui_Part *part, uintptr_t data) {
|
static void _ui_Action_ReturnToTitle(System_UI *sys, ui_Part *part, uintptr_t data) {
|
||||||
while (vector_Size(sys->state) > 0 && ui_CurrentState(sys) != ui_TitleMenu) {
|
while (vector_Size(sys->state) > 0 && ui_CurrentState(sys) != ui_TitleMenu) {
|
||||||
INFO("popping \"%s\"", ui_StateTitle[ui_CurrentState(sys)]);
|
INFO("popping \"%s\"", ui_StateTitle[ui_CurrentState(sys)]);
|
||||||
ui_Action_PopState(sys, part, data);
|
ui_Action_PopState(sys, part, 0);
|
||||||
}
|
}
|
||||||
sys->super->paused = false;
|
sys->super->paused = false;
|
||||||
if (vector_Size(sys->state) == 0)
|
if (vector_Size(sys->state) == 0)
|
||||||
@ -46,6 +47,42 @@ static void _ui_Action_Quit(System_UI *sys, ui_Part *part, uintptr_t data) {
|
|||||||
sys->super->wantQuit = true;
|
sys->super->wantQuit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _ui_Action_ReplayLevel(System_UI *sys, ui_Part *part, uintptr_t data) {
|
||||||
|
_ui_Action_SelectLevel(sys, part, (uintptr_t)sys->super->current_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ui_Action_EndIntermission(System_UI *sys, ui_Part *part, uintptr_t data) {
|
||||||
|
if (!data)
|
||||||
|
// next mission string is NULL, return to title
|
||||||
|
_ui_Action_ReturnToTitle(sys, part, 0);
|
||||||
|
else {
|
||||||
|
// load next level
|
||||||
|
// should be able to just use this
|
||||||
|
_ui_Action_SelectLevel(sys, part, data);
|
||||||
|
free((void *)data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui_EnterIntermission(System_UI *sys, const char *next_level) {
|
||||||
|
// Let's malloc & copy this next_level string
|
||||||
|
// And hide it in the last part of this state
|
||||||
|
// It must be a button, so put the string in the callback data
|
||||||
|
ui_Part *last_part = vector_Back(sys->parts[ui_InterMission]);
|
||||||
|
if (((ui_Button *)last_part->user)->callback_data)
|
||||||
|
free((void *)((ui_Button *)last_part->user)->callback_data);
|
||||||
|
if (!next_level || strlen(next_level) == 0)
|
||||||
|
((ui_Button *)last_part->user)->callback_data = 0;
|
||||||
|
else
|
||||||
|
((ui_Button *)last_part->user)->callback_data = (uintptr_t)copy_malloc(next_level);
|
||||||
|
ui_PushState(sys, ui_InterMission);
|
||||||
|
sys->super->paused = true;
|
||||||
|
|
||||||
|
// We need to update the UI elements in this State
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9
|
||||||
|
// "Level Time" <level_time> "Record Time" <record_time> <seperator> <replay_level> <return_to_title> <leaderboards> <sep> <next_level>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define PUSH_UI(part) \
|
#define PUSH_UI(part) \
|
||||||
_p0 = (part); \
|
_p0 = (part); \
|
||||||
@ -105,19 +142,23 @@ void ui_RebuildUI(System_UI *sys) {
|
|||||||
p = sys->parts[ui_Paused];
|
p = sys->parts[ui_Paused];
|
||||||
vector_Clear(p);
|
vector_Clear(p);
|
||||||
PUSH_UI(ui_Button_New(
|
PUSH_UI(ui_Button_New(
|
||||||
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300), vec2(400, 40)),
|
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 250), vec2(400, 40)),
|
||||||
"Resume Game",
|
"Resume Game",
|
||||||
&_ui_Action_ResumeGame, 0))
|
&_ui_Action_ResumeGame, 0))
|
||||||
PUSH_UI(ui_Button_New(
|
PUSH_UI(ui_Button_New(
|
||||||
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300 + (40 + UI_PADDING)), vec2(400, 40)),
|
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 250 + (40 + UI_PADDING)), vec2(400, 40)),
|
||||||
"Reselect Level",
|
"Reselect Level",
|
||||||
&ui_Action_PushState, (uintptr_t)ui_SceneSelect))
|
&ui_Action_PushState, (uintptr_t)ui_SceneSelect))
|
||||||
PUSH_UI(ui_Button_New(
|
PUSH_UI(ui_Button_New(
|
||||||
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300 + 2 * (40 + UI_PADDING)), vec2(400, 40)),
|
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 250 + 2 * (40 + UI_PADDING)), vec2(400, 40)),
|
||||||
|
"Leaderboard for This Level",
|
||||||
|
&ui_Action_PushState, (uintptr_t)ui_Leaderboards))
|
||||||
|
PUSH_UI(ui_Button_New(
|
||||||
|
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 250 + 3 * (40 + UI_PADDING)), vec2(400, 40)),
|
||||||
"Options",
|
"Options",
|
||||||
&ui_Action_PushState, (uintptr_t)ui_Options))
|
&ui_Action_PushState, (uintptr_t)ui_Options))
|
||||||
PUSH_UI(ui_Button_New(
|
PUSH_UI(ui_Button_New(
|
||||||
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300 + 3 * (40 + UI_PADDING) + UI_PADDING), vec2(400, 40)),
|
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 250 + 4 * (40 + UI_PADDING) + UI_PADDING), vec2(400, 40)),
|
||||||
"Return to Title",
|
"Return to Title",
|
||||||
&_ui_Action_ReturnToTitle, 0))
|
&_ui_Action_ReturnToTitle, 0))
|
||||||
|
|
||||||
@ -129,4 +170,66 @@ void ui_RebuildUI(System_UI *sys) {
|
|||||||
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300), vec2(600, 50)),
|
box2_FromCenter(vec2(SCREEN_WIDTH / 2.0, 300), vec2(600, 50)),
|
||||||
"Return",
|
"Return",
|
||||||
&ui_Action_PopState, 0))
|
&ui_Action_PopState, 0))
|
||||||
|
|
||||||
|
|
||||||
|
// InterMission
|
||||||
|
p = sys->parts[ui_InterMission];
|
||||||
|
vector_Clear(p);
|
||||||
|
ui_BoxBuilder *builder = ui_BoxBuilder_New();
|
||||||
|
builder->line_height = 36;
|
||||||
|
builder->pivot = vec2(0.5, 0.625);
|
||||||
|
builder->position = vec2(SCREEN_WIDTH / 2.0, SCREEN_HEIGHT / 2.0);
|
||||||
|
ui_BoxBuilder_SetCount(builder, 1, 1);
|
||||||
|
ui_BoxBuilder_SetCount(builder, 2, 1);
|
||||||
|
ui_BoxBuilder_SetCount(builder, 4, 2);
|
||||||
|
ui_BoxBuilder_SetCount(builder, 5, 1);
|
||||||
|
ui_BoxBuilder_SetCount(builder, 7, 1);
|
||||||
|
ui_BoxBuilder_Assemble(builder);
|
||||||
|
|
||||||
|
PUSH_UI(ui_Label_New(
|
||||||
|
ui_BoxBuilder_At(builder, 1, 1),
|
||||||
|
"Time in This Level", -1))
|
||||||
|
PUSH_UI(ui_Label_New(
|
||||||
|
ui_BoxBuilder_At(builder, 1, 1),
|
||||||
|
"00:00.00", 1))
|
||||||
|
PUSH_UI(ui_Label_New(
|
||||||
|
ui_BoxBuilder_At(builder, 2, 1),
|
||||||
|
"Record Time", -1))
|
||||||
|
PUSH_UI(ui_Label_New(
|
||||||
|
ui_BoxBuilder_At(builder, 2, 1),
|
||||||
|
"00:00.00", 1))
|
||||||
|
PUSH_UI(ui_Fill_New(
|
||||||
|
box2v(
|
||||||
|
vec2_Add(
|
||||||
|
ui_BoxBuilder_At(builder, 4, 1).lefttop,
|
||||||
|
vec2(0, -UI_PADDING)),
|
||||||
|
vec2(builder->width, 1.0)),
|
||||||
|
RGB(128, 128, 128)));
|
||||||
|
PUSH_UI(ui_Button_New(
|
||||||
|
ui_BoxBuilder_At(builder, 4, 1),
|
||||||
|
"Replay Level",
|
||||||
|
&_ui_Action_ReplayLevel, 0))
|
||||||
|
PUSH_UI(ui_Button_New(
|
||||||
|
ui_BoxBuilder_At(builder, 4, 2),
|
||||||
|
"Back to Title",
|
||||||
|
&_ui_Action_ReturnToTitle, 0))
|
||||||
|
PUSH_UI(ui_Button_New(
|
||||||
|
ui_BoxBuilder_At(builder, 5, 1),
|
||||||
|
"View Leaderboards for Level",
|
||||||
|
&ui_Action_PushState, (uintptr_t)ui_Leaderboards))
|
||||||
|
PUSH_UI(ui_Fill_New(
|
||||||
|
box2v(
|
||||||
|
vec2_Add(
|
||||||
|
ui_BoxBuilder_At(builder, 7, 1).lefttop,
|
||||||
|
vec2(0, -UI_PADDING)),
|
||||||
|
vec2(builder->width, 1.0)),
|
||||||
|
RGB(128, 128, 128)));
|
||||||
|
PUSH_UI(ui_Button_New(
|
||||||
|
ui_BoxBuilder_At(builder, 7, 1),
|
||||||
|
"Proceed to Next Level",
|
||||||
|
&_ui_Action_EndIntermission, 0))
|
||||||
|
|
||||||
|
|
||||||
|
p = sys->parts[ui_Leaderboards];
|
||||||
|
vector_Clear(p);
|
||||||
}
|
}
|
||||||
|
58
ui_label.c
Normal file
58
ui_label.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
void _ui_Fill_Draw(System_UI *sys, ui_Part *part, uintptr_t user); // Defined in ui_render.cpp
|
||||||
|
void _ui_Label_Draw(System_UI *sys, ui_Part *part, uintptr_t user); // Defined in ui_render.cpp
|
||||||
|
void _ui_Label_Free(System_UI *sys, ui_Part *part, uintptr_t user) {
|
||||||
|
ui_Label *label = (ui_Label *)part->user;
|
||||||
|
if (label->label)
|
||||||
|
free(label->label);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_Part ui_Label_New(Box2 box, const char *label_text, int alignment) {
|
||||||
|
ui_Label *label = zero_malloc(sizeof(ui_Label));
|
||||||
|
if (label_text && strlen(label_text) > 0)
|
||||||
|
label->label = copy_malloc(label_text);
|
||||||
|
label->align = alignment;
|
||||||
|
|
||||||
|
ui_Part part = {
|
||||||
|
.box = box,
|
||||||
|
.progress = .0f,
|
||||||
|
.hovered = false,
|
||||||
|
.user = (uintptr_t)label,
|
||||||
|
.draw = &_ui_Label_Draw,
|
||||||
|
.update = NULL,
|
||||||
|
.free = &_ui_Label_Free};
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
void ui_Label_SetLabel(ui_Part *part, const char *label_text) {
|
||||||
|
ui_Label *label = (ui_Label *)part->user;
|
||||||
|
size_t len;
|
||||||
|
if (label_text && (len = strlen(label_text)) > 0) {
|
||||||
|
if (label->label) {
|
||||||
|
label->label = realloc(label->label, len + 1);
|
||||||
|
memcpy(label->label, label_text, len + 1);
|
||||||
|
} else
|
||||||
|
label->label = copy_malloc(label_text);
|
||||||
|
} else {
|
||||||
|
if (label->label) {
|
||||||
|
free(label->label);
|
||||||
|
label->label = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_Part ui_Fill_New(Box2 box, uint32_t color) {
|
||||||
|
ui_Part part = {
|
||||||
|
.box = box,
|
||||||
|
.progress = .0f,
|
||||||
|
.hovered = false,
|
||||||
|
.user = (uintptr_t)color,
|
||||||
|
.draw = &_ui_Fill_Draw,
|
||||||
|
.update = NULL,
|
||||||
|
.free = NULL};
|
||||||
|
return part;
|
||||||
|
}
|
@ -34,7 +34,8 @@ extern "C" void ui_Render(System_UI *sys) {
|
|||||||
if (sys->bg.size.x > sys->bg_target.size.x * 0.9)
|
if (sys->bg.size.x > sys->bg_target.size.x * 0.9)
|
||||||
for (int i = 0; i < vector_Size(sys->parts[layer]); i++) {
|
for (int i = 0; i < vector_Size(sys->parts[layer]); i++) {
|
||||||
ui_Part *part = (ui_Part *)vector_At(sys->parts[layer], i);
|
ui_Part *part = (ui_Part *)vector_At(sys->parts[layer], i);
|
||||||
part->draw(sys, part, part->user);
|
if (part->draw)
|
||||||
|
part->draw(sys, part, part->user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,14 +67,46 @@ extern "C" void _ui_Button_Draw(System_UI *sys, ui_Part *part, void *user) {
|
|||||||
setfillcolor(color_final);
|
setfillcolor(color_final);
|
||||||
settextcolor(RGB(255, 255, 255));
|
settextcolor(RGB(255, 255, 255));
|
||||||
|
|
||||||
Box2 padded_box = part->box;
|
|
||||||
padded_box.lefttop.x += UI_PADDING;
|
|
||||||
padded_box.size.x -= 2 * UI_PADDING;
|
|
||||||
|
|
||||||
solidrectangle(
|
solidrectangle(
|
||||||
(int)round(part->box.lefttop.x),
|
(int)round(part->box.lefttop.x),
|
||||||
(int)round(part->box.lefttop.y),
|
(int)round(part->box.lefttop.y),
|
||||||
(int)round(part->box.lefttop.x + part->box.size.x),
|
(int)round(part->box.lefttop.x + part->box.size.x),
|
||||||
(int)round(part->box.lefttop.y + part->box.size.y));
|
(int)round(part->box.lefttop.y + part->box.size.y));
|
||||||
render_DrawTextEx(b->label, padded_box, (b->left_aligned ? DT_LEFT : DT_CENTER) | DT_VCENTER | DT_SINGLELINE);
|
if (b->left_aligned) {
|
||||||
|
Box2 padded_box = part->box;
|
||||||
|
padded_box.lefttop.x += UI_PADDING;
|
||||||
|
padded_box.size.x -= 2 * UI_PADDING;
|
||||||
|
|
||||||
|
render_DrawTextEx(b->label, padded_box, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
||||||
|
} else
|
||||||
|
render_DrawTextEx(b->label, part->box, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void _ui_Label_Draw(System_UI *sys, ui_Part *part, uintptr_t user) {
|
||||||
|
ui_Label *label = (ui_Label *)user;
|
||||||
|
if (!label->label || strlen(label->label) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Box2 padded_box = part->box;
|
||||||
|
padded_box.lefttop.x += UI_PADDING;
|
||||||
|
padded_box.size.x -= 2 * UI_PADDING;
|
||||||
|
|
||||||
|
setbkcolor(0);
|
||||||
|
settextcolor(RGB(255, 255, 255));
|
||||||
|
|
||||||
|
if (label->align < 0)
|
||||||
|
render_DrawTextEx(label->label, padded_box, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
|
||||||
|
else if (label->align > 0)
|
||||||
|
render_DrawTextEx(label->label, padded_box, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
|
||||||
|
else // align == 0
|
||||||
|
render_DrawTextEx(label->label, padded_box, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void _ui_Fill_Draw(System_UI *sys, ui_Part *part, uintptr_t user) {
|
||||||
|
setfillcolor(part->user);
|
||||||
|
solidrectangle(
|
||||||
|
(int)round(part->box.lefttop.x),
|
||||||
|
(int)round(part->box.lefttop.y),
|
||||||
|
(int)round(part->box.lefttop.x + part->box.size.x),
|
||||||
|
(int)round(part->box.lefttop.y + part->box.size.y));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user