From fa3f9865aa19962c0d1cf91c205b7e47b6daf0b7 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Sun, 12 Feb 2023 20:45:08 -0800 Subject: [PATCH] Spawnpoint and animated sprites --- assets.mdesk | 8 +++++ assets/_Idle.png | Bin 0 -> 1524 bytes assets/_Run.png | Bin 0 -> 3134 bytes codegen.c | 49 +++++++++++++++++--------- main.c | 89 ++++++++++++++++++++++++++++++++++++++--------- 5 files changed, 113 insertions(+), 33 deletions(-) create mode 100644 assets/_Idle.png create mode 100644 assets/_Run.png 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 0000000000000000000000000000000000000000..daf3db43d69644d61e445e57e4f8e55602f987a8 GIT binary patch literal 1524 zcmds1iBl7I6iz9qkfB0ti6U)BtVc!6*j6c`6cOZ5j#?oc$^xNs6af)Ufow3&*n<=p zrw&jxU`X&vlzEt`WEcdY7=neZ*9E~WN-kTcZ!B~z3A`Ld7XxS6Kkm>kkOwA zcBPg4^z`7c=2()k8b#s+7$8)vA`b27XKa!{3H}*3W^bY5L*LxQQ$5{ z89Vmz)WtB`_FWp|Ew4blSRtwSQ2@$ukSHi&eg%vv7`-;7deP_sDLDmx3)ZN)uP;#2 zuamd(`P5kq8x#?QduSjR*LfXL^=1#56lNaXR1^YPs!`zD0)UPG9iejZYzUJSc&x8} zTcd8Am*bh`9Z^@wMclnE2-$M1*>DD3mmae{Hc*YOd24t`hfc={rC49vt{9cY_#77i7+T zux^q&J+v1^@DXhmOGKzQQ}oG3fApw%+-xYIeBQy*i0wWEuOp;m^H!4Fgv>(m~Lpm9MXV|52b`bU??6~ zxkkJYo2xZ;8#$7`#r6+~p(SkA;P@XzDaGtbj{LWj$E>e<$WqY_|0LZz|lKi9hSM!;upu>q6*ALB;$ozo;P>h zu^X)7ew3*@k5ou4-6opDe0q0cAANbNXB8k~35!Wcj$>~M*3Y=jdy^mpKTlhps+%Mz z{)-@_;@J@=SfjPFj+F|q-IgF~8^1ecR?D4ob(!N{<*thv7Dqrz-9=`8tJWp4tY(N> zzk~&9S5bw_DjJ)UtUDxCyN#0n%2+<(8Ev1WIk=upZrbca9KAvQp?0c5E6UQync57*CH?zDt?0T}aLxeK4w!+R$cLT&kEK)WgQVCH&(Y3NeWL>k& zi(1!e1w}(`Jpj|Z1FRL06wyp6K}ZP@ydL+>^FKWEVm|X?KHr(&%)FS}!9NB8mbomm zv$F%7IDYgeJG&(n3vuvQjtl%48BV3K7y@F zfgX(+a}2+Z0c}`DY~Jmr_&v`NT`@@Uec^%V*bOd5C%HQVFCGn zZ;jbg8eZVQdJ#LBK0SmzYG>C2|7vZc?RC6WNVBjD#24(i;%8+mD>9s=!sc@`4(Cenjdn0W90HGhcIC%TiKM$Z}X90_vbhFre*DtM+XRNI*p;Ni(3~n z>DDGKe-tXsV1>7#+X4vJY#%s>FE0?l^OGZ!g)$h%3LB=(sG+6AeMgv4-}?RV{8(BVgz7eI(Yjjif5%&vbh1%2Z*HC*#va|(t;?>Y zvoS0BQfNRhw1^McAMnRTby?08Vq^;);gfnlwya?M<${3G1ASLzi0Y9!=xdNUFjEvb znKLmuH*0)g8K$g;*4}p7W>BT5ljp~2H{i?@I=h*JVt~~g%dOL1Ou5uP;YJ1&1k*r4@A#0-w-70 z(crn$LWjlf$KFi2FTXnTE7ZFP(-`!)5Pc3j$H?4zKV+awhKe6%YY$o8T}N1{9lxj? z+qjik=uzUF{52@L;ayr#wwGbZtP<>FGCN|s3rAe>Uh5P%VgZn?I*bfd^TS!S{&To0 zYC+bdzr+_j2ChG`jREnUN4{3r8a{0VtqE#Vx4qwy?rQIG3^{PUjlG;Ex_ywA`myxz zethJ^SL9KX5_U6-=Li=!e-33EVJ|~Ny~=S1_Pz#irzSNsnl>tZ2DkVdB} zCH|8}ENbL8S$7Vunw+w{XHVGT()N1Xl(^ipiU8ROjM~4lG=%;XCVckDTU{oSjpcc% zA7?W#vtr8PsWF+*X!`Mc{Oh4CLoWtPi( zb-@lQt%|VlV$mu^Z-bvyxZ%JksbO7Pc9iSV0_TrG_5sNgvnz@W>LcEnlc;zspcDBx z>N`d6b<7hi;$8+^waGRm_WO`4$SU0y`0Hv{M54PieS7f>EXGr0*^c#}ydOJWfB;DcL#=-OP)U&Sl8>r2tzU6}b@BT`5%(>EQ!6W3M?j2YE$xT)1t z_QMP<5Co_E*cy&tZC%$vT_+vLx>SXGs45}J26y93R5y+Qga#J~_-_|2Olth`8Sz9oBB ztzYwY&u|t$q@QsnLIwGxuk*NQk0%ec7e|q$Clh%BT+G_qI!NZ!j+;nTL+8LVVnVN& z($oJn*n13f0aQA@tFsnNy_8y{LT%F|wfNi}?R!KL-r?3QE$QuTU%H7@r3m*B%@F-P z&+&efuvWDu7AP(o^0*Htkl%Ny$Plxd?|8qi)QtQju~Nc&Kyg5tn-!H^DRilZNl*i> zYuY(jyfxdx5JOgMvwGAV8Tf*>X4?MGJD=%>0Q^#XjwC7sRzz$01$Ya%e2k-{5`95{g!mi-v9V|SGYRo= zxKp>sw`GD=nhdOK#c3@F1ZSJ#mj;c~jp@$etGK%YerLeY9X0V{G7QaR5Ua*+v#yU) zyKWS}qv=B_2Ch_pji(&Wl_9JXSBv5Fy=~3``Bh}`0@(c;7I2c4F7LmE0C1Jz@{iBd zgY9RyQy%V~aEhVO3BeB%G5hD@%4=)FAaAdJ7}LMx%pxGNVr3Toa;k^ z%aBKl5#|oQk2G#N^)mct;f=k4H^18_f22c2mJM_bael9sYr-R2>_6-9(a*~sULBwz z(4c)dviW^~`z=<2G%p)kW}Xpi`2<=Ie2*d&t;B1Qf(OLcBQl50&dFM-8fNTtLH*s{ zc_veK3d)3+HSM2E@_s_vc%^5olf^8*^Kqu+M1Cw207f4U6ZnRv!lYT}g+CALO1cBu zgGoL`0{_;_?er_kr`ff2#d%_#qQS91 z<>T7QymjpHN|#W9xt~9plNfH?&``H~`#(0T#AA`UJ$c@SlfT+~5n^+lc%VLe`IUEoAOj<&LRv`Y*fdm}mxf za@#Yd%U$2tTr2#?Y+}Q(v#Yx&b~#Dvm~P>I31tB*aCgv*LIJ{4jiO*@<9828mBnm6 zwB*SpwaHex@r*beL5bM!DGSt=n_*(k#q>Uo&!5}__bBC?e|q{AA8hHPlb+O8_=S-b z`h=Aczu;gn4L2NPRp;c0SSHzvEtn^BSBS&`UJW-eMhTrOLp7B z(?U(;7Aa3UDWSXy2&20W&Eh`tx5ATO^`XeK<_oMG6PFzrg^rdQ^)lKP)fr@r5#^*n zFuwtCsp%yP>JCot8kp3b2lFE4b{Y=QK9}A$wbywl;)`u{5w?|_)M|#DW4T%GlCyUl zah|#L{;IJY-cu)PA%!PD&!RYc6`>~&MV+%qXz?!!9p$9eNN7n=Ip;J=#uIF15GwES zw&rOC3KEI7etjRer?Hf_p-7eE*_N#3&Q_@tEqaE%zLDBAAAHRV|KUsfDGW1A8od-~ zY%m^w(Zm^8H1+fIJjm9a)5+;riqdp&C!XH(7u&cr#&;7<-Zfz##jXqF8xk#JYSZxw zX0F&T@(fGU_Zt(+IznjZ8zm9?=|~^ch7KWxxdlz$$75{pnC5*$leAR|sXU~?s4skX z+I%*qBF-7kEYJ&Ahu(+yUD|IB$D(oN_CR^uzcqK$c2?a~s=&2Fhi8o;MJ$)KpO-B4 za_{nJB{i4t>{zAUS)p)wlq%CSau@y7OpxYW@X^OPqrLmz;Vr?i6hU`p1Undc`#BLyl%1XJ!1*)^OzFXXZiPoKXL5GqvbzD{`y}S?n27| literal 0 HcmV?d00001 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();