diff --git a/assets.mdesk b/assets.mdesk index de7e2a8..e9820de 100644 --- a/assets.mdesk +++ b/assets.mdesk @@ -2,6 +2,14 @@ { filepath: "copyrighted/merchant.png", } +@image knight_idle: +{ + filepath: "_Idle.png", +} +@image knight_run: +{ + filepath: "_Run.png", +} @image animated_terrain: { filepath: "copyrighted/animated_terrain.png", diff --git a/assets/_Idle.png b/assets/_Idle.png new file mode 100644 index 0000000..daf3db4 Binary files /dev/null and b/assets/_Idle.png differ diff --git a/assets/_Run.png b/assets/_Run.png new file mode 100644 index 0000000..181cf33 Binary files /dev/null and b/assets/_Run.png differ diff --git a/codegen.c b/codegen.c index 1ddc56c..1793881 100644 --- a/codegen.c +++ b/codegen.c @@ -174,25 +174,42 @@ int main(int argc, char **argv) { assert(level_parse.node != 0, MD_S8Lit("Failed to load level file")); MD_Node *layers = MD_ChildFromString(level_parse.node->first_child, MD_S8Lit("layers"), 0); - int width = atoi(nullterm(MD_ChildFromString(layers->first_child, MD_S8Lit("width"), 0)->first_child->string)); - int height = atoi(nullterm(MD_ChildFromString(layers->first_child, MD_S8Lit("height"), 0)->first_child->string)); - MD_Node *data = MD_ChildFromString(layers->first_child, MD_S8Lit("data"), 0); - - fprintf(output, "Level %.*s = {\n.tiles = {\n", MD_S8VArg(variable_name)); - int num_index = 0; - fprintf(output, "{ "); - for(MD_EachNode(tile_id_node, data->first_child)) { - fprintf(output, "%.*s, ", MD_S8VArg(tile_id_node->string)); - - if(num_index % width == width - 1) { - if(MD_NodeIsNil(tile_id_node->next)) { - fprintf(output, "},\n}\n}; // %.*s\n", MD_S8VArg(variable_name)); - } else { - fprintf(output, "},\n{ "); + fprintf(output, "Level %.*s = {\n", MD_S8VArg(variable_name)); + for(MD_EachNode(lay, layers->first_child)) { + MD_String8 type = MD_ChildFromString(lay, MD_S8Lit("type"), 0)->first_child->string; + if(MD_S8Match(type, MD_S8Lit("objectgroup"), 0)) { + for(MD_EachNode(object, MD_ChildFromString(lay, MD_S8Lit("objects"), 0)->first_child)) { + dump(object); + if(MD_S8Match(MD_ChildFromString(object, MD_S8Lit("name"), 0)->first_child->string, MD_S8Lit("spawn"), 0)) { + MD_String8 x_string = MD_ChildFromString(object, MD_S8Lit("x"), 0)->first_child->string; + MD_String8 y_string = MD_ChildFromString(object, MD_S8Lit("y"), 0)->first_child->string; + fprintf(output, ".spawnpoint = { %.*s, %.*s },\n", MD_S8VArg(x_string), MD_S8VArg(y_string)); + } + } + } + if(MD_S8Match(type, MD_S8Lit("tilelayer"), 0)) { + int width = atoi(nullterm(MD_ChildFromString(layers->first_child, MD_S8Lit("width"), 0)->first_child->string)); + int height = atoi(nullterm(MD_ChildFromString(layers->first_child, MD_S8Lit("height"), 0)->first_child->string)); + MD_Node *data = MD_ChildFromString(layers->first_child, MD_S8Lit("data"), 0); + + int num_index = 0; + fprintf(output, ".tiles = {\n"); + fprintf(output, "{ "); + for(MD_EachNode(tile_id_node, data->first_child)) { + fprintf(output, "%.*s, ", MD_S8VArg(tile_id_node->string)); + + if(num_index % width == width - 1) { + if(MD_NodeIsNil(tile_id_node->next)) { + fprintf(output, "},\n},\n"); + } else { + fprintf(output, "},\n{ "); + } + } + num_index += 1; } } - num_index += 1; } + fprintf(output, "\n}; // %.*s\n", MD_S8VArg(variable_name)); } } diff --git a/main.c b/main.c index c8c79ae..52cce0e 100644 --- a/main.c +++ b/main.c @@ -36,10 +36,21 @@ typedef struct TileSet { AnimatedTile animated[128]; } TileSet; +typedef struct AnimatedSprite { + sg_image *img; + double time_per_frame; + int num_frames; + HMM_Vec2 start; + float horizontal_diff_btwn_frames; + HMM_Vec2 region_size; +} AnimatedSprite; + + #define LEVEL_TILES 60 #define TILE_SIZE 32 // in pixels typedef struct Level { TileInstance tiles[LEVEL_TILES][LEVEL_TILES]; + HMM_Vec2 spawnpoint; } Level; HMM_Vec2 tilecoord_to_world(int x, int y) { @@ -74,6 +85,24 @@ sg_image load_image(const char *path) { #include "quad-sapp.glsl.h" #include "assets.gen.c" +AnimatedSprite knight_idle = { + .img = &image_knight_idle, + .time_per_frame = 0.3, + .num_frames = 10, + .start = {16.0f, 0.0f}, + .horizontal_diff_btwn_frames = 120.0, + .region_size = {80.0f, 80.0f}, +}; + +AnimatedSprite knight_running = { + .img = &image_knight_run, + .time_per_frame = 0.06, + .num_frames = 10, + .start = {19.0f, 0.0f}, + .horizontal_diff_btwn_frames = 120.0, + .region_size = {80.0f, 80.0f}, +}; + sg_image image_font = {0}; const float font_size = 64.0; stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs @@ -87,6 +116,8 @@ static struct { sg_bindings bind; } state; +HMM_Vec2 character_pos = {0}; // world space point + void init(void) { stm_setup(); sg_setup(&(sg_desc){ @@ -95,6 +126,10 @@ void init(void) { load_assets(); + // player spawnpoint + HMM_Vec2 spawnpoint_tilecoord = HMM_MulV2F(level_level0.spawnpoint, 1.0/TILE_SIZE); + character_pos = tilecoord_to_world((int)spawnpoint_tilecoord.X, (int)spawnpoint_tilecoord.Y); + // load font { FILE* fontFile = fopen("assets/orange kid.ttf", "rb"); @@ -172,7 +207,10 @@ void init(void) { }); state.pass_action = (sg_pass_action) { - .colors[0] = { .action=SG_ACTION_CLEAR, .value={12.5f/255.0f, 12.5f/255.0f, 12.5f/255.0f, 1.0f } } + //.colors[0] = { .action=SG_ACTION_CLEAR, .value={12.5f/255.0f, 12.5f/255.0f, 12.5f/255.0f, 1.0f } } + //.colors[0] = { .action=SG_ACTION_CLEAR, .value={255.5f/255.0f, 255.5f/255.0f, 255.5f/255.0f, 1.0f } } + // 0x898989 is the color in tiled + .colors[0] = { .action=SG_ACTION_CLEAR, .value={137.0f/255.0f, 137.0f/255.0f, 137.0f/255.0f, 1.0f } } }; } @@ -354,6 +392,31 @@ void draw_quad(bool world_space, HMM_Vec2 *points_in, sg_image image, AABB image sg_draw(0, 6, 1); } +void swap(HMM_Vec2 *p1, HMM_Vec2 *p2) { + HMM_Vec2 tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} + +void draw_animated_sprite(AnimatedSprite *s, double time, bool flipped, HMM_Vec2 pos, Color tint) { + sg_image spritesheet_img = *s->img; + int index = (int)floor(time/s->time_per_frame) % s->num_frames; + + HMM_Vec2 points[4] = {0}; + quad_points_centered_size(points, pos, s->region_size); + + if(flipped) { + swap(&points[0], &points[1]); + swap(&points[3], &points[2]); + } + + AABB region; + region.upper_left = HMM_AddV2(s->start, HMM_V2(index * s->horizontal_diff_btwn_frames, 0.0f)); + region.lower_right = HMM_V2(region.upper_left.X + (float)s->region_size.X, (float)s->region_size.Y); + + draw_quad(true, points, spritesheet_img, region, tint); +} + void colorbox(bool world_space, HMM_Vec2 upper_left, HMM_Vec2 lower_right, Color color) { HMM_Vec2 size = HMM_SubV2(lower_right, upper_left); @@ -443,7 +506,7 @@ double time = 0.0; double last_frame_processing_time = 0.0; uint64_t last_frame_time; HMM_Vec2 mouse_pos = {0}; // in screen space -HMM_Vec2 character_pos = {0}; // world space point +bool character_facing_left = false; bool keydown[SAPP_KEYCODE_MENU] = {0}; #ifdef DEVTOOLS bool mouse_frozen = false; @@ -551,22 +614,14 @@ void frame(void) { } #endif -#endif - +#endif // devtools - // 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((int)img_size(image_merchant).X % cell_size == 0); - AABB region; - 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(true, points, image_merchant, region, WHITE); + if(HMM_LenV2(movement) > 0.01) { + character_facing_left = movement.X < 0.0; + draw_animated_sprite(&knight_running, time, character_facing_left, character_pos, WHITE); + } else { + draw_animated_sprite(&knight_idle, time, character_facing_left, character_pos, WHITE); + } sg_end_pass(); sg_commit();