From e573fede866783b1246503c2782395ee31068498 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Fri, 10 Feb 2023 12:26:06 -0800 Subject: [PATCH] Camera, player movement, tilemap, better drawing --- .gitignore | 4 ++ assets.mdesk | 10 ++- assets/white square.png | Bin 0 -> 520 bytes codegen.c | 2 +- main.c | 142 +++++++++++++++++++++++++++++++--------- run_codegen.bat | 9 +++ 6 files changed, 135 insertions(+), 32 deletions(-) create mode 100644 assets/white square.png diff --git a/.gitignore b/.gitignore index 0f1ab7e..ef1ae2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +# copyrighted assets which must be bought +assets/copyrighted/ +EPIC RPG World Pack - Ancient Ruins V 1.7/ + # allow shader compiler !thirdparty\sokol-shdc.exe diff --git a/assets.mdesk b/assets.mdesk index be02a17..d6b6ad9 100644 --- a/assets.mdesk +++ b/assets.mdesk @@ -1,4 +1,12 @@ @image merchant: { - filepath = "merchant.png", + filepath = "copyrighted/merchant.png", +} +@image bg_tilesheet: +{ + filepath = "copyrighted/wall-1 - 3 tiles tall.png", +} +@image white_square: +{ + filepath = "white square.png", } diff --git a/assets/white square.png b/assets/white square.png new file mode 100644 index 0000000000000000000000000000000000000000..9054853051cec9a5cff66bf163c4db82cf0e66fe GIT binary patch literal 520 zcmV+j0{8uiP)EX>4Tx04R}tkv&MmKpe$iQ^gM|4ptCx$WWauh)NM$q>4qbP}&NuI+$Gg1x*@~ z6cs^>M{K$3L zaarNK#aS&^S@WL!g@K&5lHxke5yY^BI1&&cqlyyBun?wIBgI6L_M;yDVaJ~!mrSk_ z7&#VDfeOj-ga5(rZq5AEq?;6o0-Z0m{V@u3?E;OOZGRuzcH;!_KLb}<%U`JjGoPf_ zT3YA`=-&n|u3MVC2VCv|Lr=P7NRH&EDdh9O`x$*x78tk%de_|En)^6?0MgXe@(pls z2#ggdd)?#R-R-^od#2gn5Bs8W-Zen4m;e9(32;bRa{vGf6951U69E94oEQKA00(qQ zO+^Ri0tyl?EcBHiPXGV_7D+@wR0!8&{Qv(y0|NsS0|NsC0|Njg1_J@T9^<+I0000< KMNUMnLSTZZhT1y- literal 0 HcmV?d00001 diff --git a/codegen.c b/codegen.c index 64a3652..20bb202 100644 --- a/codegen.c +++ b/codegen.c @@ -59,7 +59,7 @@ int main(int argc, char **argv) { MD_String8 filepath = {0}; for(MD_EachNode(child, node->first_child)) { if(MD_S8Match(child->string, MD_S8Lit("filepath"), 0)) { - filepath = child->next->next->string; + filepath = child->next->next->string; // segfault here but to check for it is ugly } } filepath = MD_S8Fmt(cg_arena, "%.*s/%.*s", MD_S8VArg(ASSETS_FOLDER), MD_S8VArg(filepath)); diff --git a/main.c b/main.c index 17e2651..7f1571c 100644 --- a/main.c +++ b/main.c @@ -73,10 +73,8 @@ void init(void) { }); - /* a shader (use separate shader sources here */ sg_shader shd = sg_make_shader(quad_program_shader_desc(sg_query_backend())); - /* a pipeline state object */ state.pip = sg_make_pipeline(&(sg_pipeline_desc){ .shader = shd, .index_type = SG_INDEXTYPE_UINT16, @@ -86,10 +84,18 @@ void init(void) { [ATTR_quad_vs_texcoord0].format = SG_VERTEXFORMAT_FLOAT2, } }, - .label = "quad-pipeline" + .colors[0].blend = (sg_blend_state) { // allow transparency + .enabled = true, + .src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA, + .dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .op_rgb = SG_BLENDOP_ADD, + .src_factor_alpha = SG_BLENDFACTOR_ONE, + .dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .op_alpha = SG_BLENDOP_ADD, + }, + .label = "quad-pipeline", }); - /* default pass action */ state.pass_action = (sg_pass_action) { .colors[0] = { .action=SG_ACTION_CLEAR, .value={0.0f, 0.0f, 0.0f, 1.0f } } }; @@ -105,20 +111,64 @@ Color col(float r, float g, float b, float a) { return HMM_V4(r, g, b, a); } +#define WHITE col(1.0f, 1.0f, 1.0f, 1.0f) + HMM_Vec2 screen_size() { return HMM_V2((float)sapp_width(), (float)sapp_height()); } +typedef struct Camera { + HMM_Vec2 pos; + float scale; +} Camera; + + +// everything is in pixels in world space, 43 pixels is approx 1 meter measured from +// merchant sprite being 5'6" +const float pixels_per_meter = 43.0f; +Camera cam = {.scale = 2.0f }; + +HMM_Vec2 cam_offset() { + return HMM_AddV2(cam.pos, HMM_MulV2F(screen_size(), 0.5f)); +} + +// screen coords are in bottom right, and in pixels +HMM_Vec2 world_to_screen(HMM_Vec2 world) { + HMM_Vec2 to_return = world; + to_return = HMM_MulV2F(to_return, cam.scale); + to_return = HMM_AddV2(to_return, cam_offset()); + return to_return; +} + +HMM_Vec2 screen_to_world(HMM_Vec2 screen) { + HMM_Vec2 to_return = screen; + to_return = HMM_SubV2(to_return, cam_offset()); + to_return = HMM_MulV2F(to_return, 1.0f/cam.scale); + return to_return; +} + +// out must be of at least length 4 +void quad_points_centered_size(HMM_Vec2 *out, HMM_Vec2 at, HMM_Vec2 size) { + out[0] = HMM_V2(0.0, 0.0); + out[1] = HMM_V2(size.X, 0.0); + out[2] = HMM_V2(size.X, -size.Y); + out[3] = HMM_V2(0.0, -size.Y); + + for(int i = 0; i < 4; i++) { + out[i] = HMM_AddV2(out[i], HMM_V2(-size.X*0.5f, size.Y*0.5f)); + out[i] = HMM_AddV2(out[i], at); + } +} // points must be of length 4, and be in the order: upper left, upper right, lower right, lower left -// the points are in pixels in screen space +// the points are in pixels in screen space. The image region is in pixel space of the image void draw_quad_all_parameters(HMM_Vec2 *points, sg_image image, AABB image_region, Color tint) { float new_vertices[ (2 + 2)*4 ]; HMM_Vec2 region_size = HMM_SubV2(image_region.lower_right, image_region.upper_left); assert(region_size.X > 0.0); assert(region_size.Y > 0.0); HMM_Vec2 tex_coords[4] = { - HMM_AddV2(image_region.upper_left, HMM_V2(0.0, 0.0)), + HMM_AddV2(image_region.upper_left, HMM_V2(0.0, 0.0)), HMM_AddV2(image_region.upper_left, HMM_V2(region_size.X, 0.0)), HMM_AddV2(image_region.upper_left, HMM_V2(region_size.X, region_size.Y)), HMM_AddV2(image_region.upper_left, HMM_V2(0.0, region_size.Y)), @@ -153,52 +203,79 @@ void draw_quad_all_parameters(HMM_Vec2 *points, sg_image image, AABB image_regio sg_draw(0, 6, 1); } +void draw_quad_world_all(HMM_Vec2 *points, sg_image image, AABB image_region, Color tint) { + HMM_Vec2 into_screen[4] = {0}; + memcpy(into_screen, points, sizeof(into_screen)); + for(int i = 0; i < 4; i++) { + into_screen[i] = world_to_screen(into_screen[i]); + } + draw_quad_all_parameters(into_screen, image, image_region, tint); +} + +// in pixels +HMM_Vec2 img_size(sg_image img) { + sg_image_info info = sg_query_image_info(img); + return HMM_V2((float)info.width, (float)info.height); +} + +// full region in pixels +AABB full_region(sg_image img) { + return (AABB) { + .upper_left = HMM_V2(0.0f, 0.0f), + .lower_right = img_size(img), + }; +} + double time = 0.0; uint64_t last_frame_time; -HMM_Vec2 mouse_pos; // in screen space +HMM_Vec2 mouse_pos = {0}; // in screen space +HMM_Vec2 character_pos = {0}; // world space point +bool keydown[SAPP_KEYCODE_MENU] = {0}; #ifdef DEVTOOLS bool mouse_frozen = false; #endif void frame(void) { // time + double dt_double = 0.0; { - double dt = stm_sec(stm_diff(stm_now(), last_frame_time)); - time += dt; + dt_double = stm_sec(stm_diff(stm_now(), last_frame_time)); + time += dt_double; last_frame_time = stm_now(); } - - /*HMM_Vec2 points[] = { - HMM_V2(-0.5f, 0.5f), - HMM_V2(0.5f, 0.5f), - HMM_V2(0.5f, -0.5f), - HMM_V2(-0.5f, -0.5f), - };*/ - float size = 200.0; - HMM_Vec2 points[] = { - HMM_V2(0.0, 0.0), - HMM_V2(size, 0.0), - HMM_V2(size, -size), - HMM_V2(0.0, -size), - }; - for(int i = 0; i < 4; i ++) { - points[i] = HMM_AddV2(points[i], mouse_pos); + float dt = (float)dt_double; + + HMM_Vec2 movement = HMM_V2( + (float)keydown[SAPP_KEYCODE_D] - (float)keydown[SAPP_KEYCODE_A], + (float)keydown[SAPP_KEYCODE_W] - (float)keydown[SAPP_KEYCODE_S] + ); + if(HMM_LenV2(movement) > 1.0) { + movement = HMM_NormV2(movement); } + character_pos = HMM_AddV2(character_pos, HMM_MulV2F(movement, dt * pixels_per_meter * 4.0f)); + cam.pos = HMM_LerpV2(cam.pos, dt*8.0f, HMM_MulV2F(character_pos, -1.0f * cam.scale)); sg_begin_default_pass(&state.pass_action, sapp_width(), sapp_height()); sg_apply_pipeline(state.pip); - int index = (int)floor(time/0.3); + // background + HMM_Vec2 bg_points[4] = {0}; + quad_points_centered_size(bg_points, HMM_V2(0.0, 0.0), img_size(image_bg_tilesheet)); + draw_quad_world_all(bg_points, image_bg_tilesheet, full_region(image_bg_tilesheet), WHITE); - sg_image_info info = sg_query_image_info(image_merchant); + // merchant + int index = (int)floor(time/0.3); + float size = img_size(image_merchant).Y; + HMM_Vec2 points[4] = {0}; + quad_points_centered_size(points, character_pos, HMM_V2(size, size)); int cell_size = 110; - assert(info.width % cell_size == 0); + assert((int)img_size(image_merchant).X % cell_size == 0); AABB region; - region.upper_left = HMM_V2( (float)((index % (info.width/cell_size)) * cell_size), 0.0); + region.upper_left = HMM_V2( (float)((index % ((int)img_size(image_merchant).X/cell_size)) * cell_size), 0.0); region.lower_right = HMM_V2(region.upper_left.X + (float)cell_size, (float)cell_size); - draw_quad_all_parameters(points, image_merchant, region, col(1.0, 1.0, 1.0, 1.0)); + draw_quad_world_all(points, image_merchant, region, WHITE); sg_end_pass(); sg_commit(); @@ -210,6 +287,8 @@ void cleanup(void) { void event(const sapp_event *e) { if(e->type == SAPP_EVENTTYPE_KEY_DOWN) { + assert(e->key_code < sizeof(keydown)/sizeof(*keydown)); + keydown[e->key_code] = true; if(e->key_code == SAPP_KEYCODE_ESCAPE) { sapp_quit(); } @@ -219,6 +298,9 @@ void event(const sapp_event *e) { } #endif } + if(e->type == SAPP_EVENTTYPE_KEY_UP) { + keydown[e->key_code] = false; + } if(e->type == SAPP_EVENTTYPE_MOUSE_MOVE) { bool ignore_movement = false; #ifdef DEVTOOLS diff --git a/run_codegen.bat b/run_codegen.bat index 01c2608..14211bd 100644 --- a/run_codegen.bat +++ b/run_codegen.bat @@ -1,4 +1,13 @@ @echo off + +echo Asset packs which must be bought and unzipped into root directory before running this script: +echo https://rafaelmatos.itch.io/epic-rpg-world-pack-ancient-ruins + +rmdir /S /q assets\copyrighted +mkdir assets\copyrighted +copy "EPIC RPG World Pack - Ancient Ruins V 1.7\EPIC RPG World Pack - Ancient Ruins V 1.7\Characters\NPC Merchant-idle.png" "assets\copyrighted\merchant.png" || goto :error +copy "EPIC RPG World Pack - Ancient Ruins V 1.7\EPIC RPG World Pack - Ancient Ruins V 1.7\Tilesets\wall-1 - 3 tiles tall.png" "assets\copyrighted\wall-1 - 3 tiles tall.png" || goto :error + rmdir /S /q gen mkdir gen