diff --git a/app.c b/app.c index d9d328c..e4729b5 100644 --- a/app.c +++ b/app.c @@ -8,6 +8,8 @@ #include "player.h" #include "types.h" #include "render_bundle.h" +#include "render_component.h" +#include "mapper_misc.h" #include #include @@ -58,6 +60,27 @@ App *app_NewApp() { hit3->hitbox->fixed = true; entity_Commit(app->entity, hit3); + Entity *text1 = entity_Create(app->entity, "text_plate_large_1"); + ADD_COMPONENT(text1, position); + text1->position->position = vec2(600, 550); + text1->render = render_NewComponent(app, "info_plate"); + misc_InstantiateTextbox(app, text1, "So long lives this,\nAnd this gives life to thee.", misc_TextboxUpright(110, 110), -220); + entity_Commit(app->entity, text1); + + Entity *text2 = entity_Create(app->entity, "text_plate_1"); + ADD_COMPONENT(text2, position); + text2->position->position = vec2(250, 200); + text2->render = render_NewComponent(app, "info_plate_small_1"); + misc_InstantiateTextbox(app, text2, "Press Space to jump.\nYou can jump again midair.", misc_TextboxUpright(70, 70), -180); + entity_Commit(app->entity, text2); + + Entity *text3 = entity_Create(app->entity, "text_plate_2"); + ADD_COMPONENT(text3, position); + text3->position->position = vec2(750, 200); + text3->render = render_NewComponent(app, "info_plate_small_2"); + misc_InstantiateTextbox(app, text3, "Press ; to dash.\nYou can only dash one time midair.", misc_TextboxUpright(70, 70), -180); + entity_Commit(app->entity, text3); + return app; } diff --git a/app_render.cpp b/app_render.cpp index 4552232..3dd33fe 100644 --- a/app_render.cpp +++ b/app_render.cpp @@ -5,6 +5,7 @@ #include "physics.h" #include "easyx.h" #include "render_bundle.h" +#include "render_component.h" #include "util/tree.h" #include "types.h" #include "render_util.h" @@ -63,14 +64,38 @@ void app_Render(App *app) { render_FillCircleW(app, vec2(200, 100), 20); - render_DrawBundleW(app, render_FindBundle("info_plate"), vec2(600, 550)); + // render_DrawBundleW(app, render_FindBundle("info_plate"), vec2(600, 550)); render_DrawBundleW(app, render_FindBundle("info_plate_small_1"), vec2(250, 200)); render_DrawBundleW(app, render_FindBundle("info_plate_small_2"), vec2(750, 200)); + // Draw entities + for (tree_Node *i = tree_FirstNode(app->entity->entities); + i != NULL; + i = tree_Node_Next(i)) { + Entity *e = (Entity *)i->data; + if (e->render) { + Component_Render *r = e->render; + + // Calculate global position as offset + Vec2 pos = {.x = 0.0, .y = 0.0}; + if (e->position) + pos = e->position->position; + // Has bundle + if (r->bundle) + render_DrawBundleW(app, r->bundle, pos); + // Has custom rendering + if (r->custom) + r->custom(app, e, camera_TransformVec2(app->camera, pos), r->custom_data); + } + } + // Draw particles setfillcolor(RGB(255, 255, 255)); setbkcolor(RGB(0, 0, 0)); particle_Render(app->particle); + + + settextcolor(RGB(255, 255, 255)); } } diff --git a/mapper_misc.c b/mapper_misc.c index b4ce704..4508140 100644 --- a/mapper_misc.c +++ b/mapper_misc.c @@ -2,6 +2,7 @@ #include "mapper_misc.h" #include "app.h" #include "entity.h" +#include "physics.h" #include "types.h" #include "util/assert.h" #include @@ -30,7 +31,8 @@ void misc_thinker_HazardRespawn(App *app, Entity *e, Duration deltaTime) { } if (app->player->player == NULL) // No player return; - Component_Player *p = app->player->player; + Component_Player *p = app->player->player; + Box2 playerbox = physics_HitboxAbsolute(p->super->hitbox); Box2 worldbox; // Offset if position component exists Vec2 worldspawn; @@ -42,7 +44,7 @@ void misc_thinker_HazardRespawn(App *app, Entity *e, Duration deltaTime) { worldspawn = e->misc->respawn->respawn_pos; } - if (box2_Contains(worldbox, p->super->position->position)) + if (box2_Intersects(worldbox, playerbox, NULL)) p->hazardRespawn = worldspawn; } @@ -56,13 +58,14 @@ void misc_thinker_Textbox(App *app, Entity *e, Duration deltaTime) { t->progress = fmaxf(0.0f, t->progress - duration_Seconds(deltaTime) * MISC_TEXTBOX_FADEIN_SPEED); return; } - Component_Player *p = app->player->player; + Component_Player *p = app->player->player; + Box2 playerbox = physics_HitboxAbsolute(p->super->hitbox); Box2 worldbox; // Offset if position component exists ASSERT(e->position && "Textboxes must have a position component"); worldbox = box2_Offset(t->trigger_box, e->position->position); - if (box2_Contains(worldbox, p->super->position->position)) + if (box2_Intersects(worldbox, playerbox, NULL)) // Fade in t->progress = fminf(1.0f, t->progress + duration_Seconds(deltaTime) * MISC_TEXTBOX_FADEIN_SPEED); else @@ -73,8 +76,8 @@ void misc_thinker_Textbox(App *app, Entity *e, Duration deltaTime) { // Utility functions for creating misc entities void misc_InstantiateTextbox(App *app, Entity *e, const char *text, Box2 trigger_box, float offset) { - ASSERT(e->misc == NULL && "Instantiate must be called with e.misc not set yet"); - ASSERT(e->render == NULL && "Instantiate must be called with e.render not set yet"); + ASSERT(e->misc == NULL && "Instantiate must be called with e.misc not set"); + ASSERT((e->render == NULL || e->render->custom == NULL) && "Instantiate for Textbox must be called with e.render.custom not set"); e->misc = zero_malloc(sizeof(Component_Misc)); e->misc->textbox = zero_malloc(sizeof(misc_Textbox)); @@ -82,6 +85,20 @@ void misc_InstantiateTextbox(App *app, Entity *e, const char *text, Box2 trigger e->misc->textbox->trigger_box = trigger_box; e->misc->textbox->offset = offset; - e->render = render_NewComponentFunc(app, &misc_render_Textbox, NULL); + if (!e->render) + e->render = render_NewComponentFunc(app, &misc_render_Textbox, NULL); + else + e->render->custom = &misc_render_Textbox; e->thinker = &misc_thinker_Textbox; } + +void misc_InstantiateHazardRespawn(App *app, Entity *e, Box2 trigger_box, Vec2 respawn_pos) { + ASSERT(e->misc == NULL && "Instantiate must be called with e.misc not set"); + e->misc = zero_malloc(sizeof(Component_Misc)); + e->misc->respawn = zero_malloc(sizeof(misc_HazardRespawn)); + + e->misc->respawn->respawn_pos = respawn_pos; + e->misc->respawn->trigger_box = trigger_box; + + e->thinker = &misc_thinker_HazardRespawn; +} diff --git a/mapper_misc.h b/mapper_misc.h index f84ff61..1d566fa 100644 --- a/mapper_misc.h +++ b/mapper_misc.h @@ -11,7 +11,7 @@ typedef struct _App App; typedef struct _Entity Entity; -#define MISC_TEXTBOX_FADEIN_SPEED 5.0 // Fades in/out in 1/5 seconds +#define MISC_TEXTBOX_FADEIN_SPEED 6.0 // Fades in/out in 1/6 seconds // A textbox that shows itself when the player is close typedef struct { @@ -55,6 +55,19 @@ void misc_DeleteComponent(Component_Misc *misc); // Creates misc + render components & sets the thinker. void misc_InstantiateTextbox(App *app, Entity *e, const char *text, Box2 trigger_box, float offset); +// Inserts the components for a hazard respawn area. +// Creates misc & sets the thinker. +void misc_InstantiateHazardRespawn(App *app, Entity *e, Box2 trigger_box, Vec2 respawn_pos); + + +static inline Box2 misc_TextboxUpright(double width, double height) { + Box2 b = { + .lefttop = { + .x = -width / 2.0, + .y = -height}, + .size = {.x = width, .y = height}}; + return b; +} #ifdef __cplusplus } diff --git a/mapper_misc_render.cpp b/mapper_misc_render.cpp index d31dffd..ff631b2 100644 --- a/mapper_misc_render.cpp +++ b/mapper_misc_render.cpp @@ -62,6 +62,7 @@ extern "C" void misc_render_Textbox(App *app, Entity *e, Vec2 entity_screen_pos, rect.top = (LONG)round(entity_screen_pos.y) + t->offset + 40; // Convert & draw + // https://docs.easyx.cn/zh-cn/drawtext convert_text(t->text); drawtext((LPCTSTR)vector_Data(tbuf), &rect, DT_CENTER | DT_NOCLIP); } diff --git a/types.h b/types.h index ece0e7b..b7f7f13 100644 --- a/types.h +++ b/types.h @@ -55,6 +55,15 @@ typedef struct { Vec2 size; } Box2; +static inline Box2 box2(double x, double y, double width, double height) { + Box2 b; + b.lefttop.x = x; + b.lefttop.y = y; + b.size.x = width; + b.size.y = height; + return b; +} + // Intersection test. bool box2_Intersects(const Box2 x, const Box2 y, Box2 *out_intersection);