From 0b338bbd007048551526ab4fa4130d53b414e650 Mon Sep 17 00:00:00 2001 From: jacopo grandi Date: Wed, 24 Feb 2021 16:38:42 +0100 Subject: fire and movement animations --- build/army/balance 1000 melee.txt | Bin 21560 -> 21560 bytes build/army/balance 1000 the second.txt | Bin 21560 -> 21560 bytes build/army/balance 1000.txt | Bin 21560 -> 21560 bytes build/army/balance melee maul.txt | Bin 21560 -> 21560 bytes build/army/best army ever.txt | Bin 21560 -> 21560 bytes build/army/lotsa dudes.txt | Bin 0 -> 21560 bytes build/content/sprites.pdn | Bin 30575 -> 30572 bytes build/test.exe | Bin 786658 -> 791607 bytes design/notes.txt | 35 +++++++- gst/fxs.c | 55 ++++++++++++ gst/fxs.h | 25 ++++++ gst/gst.c | 159 +++++++++++++++++++++++++++++---- gst/gst.h | 12 ++- gst/units.c | 13 +-- gst/units.h | 5 +- main.c | 68 +++----------- render/render_text.c | 5 +- render/render_text.h | 4 +- 18 files changed, 289 insertions(+), 92 deletions(-) create mode 100644 build/army/lotsa dudes.txt create mode 100644 gst/fxs.c create mode 100644 gst/fxs.h diff --git a/build/army/balance 1000 melee.txt b/build/army/balance 1000 melee.txt index 86ffd09..b45bbea 100644 Binary files a/build/army/balance 1000 melee.txt and b/build/army/balance 1000 melee.txt differ diff --git a/build/army/balance 1000 the second.txt b/build/army/balance 1000 the second.txt index 6db93ae..48b8155 100644 Binary files a/build/army/balance 1000 the second.txt and b/build/army/balance 1000 the second.txt differ diff --git a/build/army/balance 1000.txt b/build/army/balance 1000.txt index a44f973..b74045b 100644 Binary files a/build/army/balance 1000.txt and b/build/army/balance 1000.txt differ diff --git a/build/army/balance melee maul.txt b/build/army/balance melee maul.txt index fede815..a3ababa 100644 Binary files a/build/army/balance melee maul.txt and b/build/army/balance melee maul.txt differ diff --git a/build/army/best army ever.txt b/build/army/best army ever.txt index 7e76ce1..5898346 100644 Binary files a/build/army/best army ever.txt and b/build/army/best army ever.txt differ diff --git a/build/army/lotsa dudes.txt b/build/army/lotsa dudes.txt new file mode 100644 index 0000000..6314165 Binary files /dev/null and b/build/army/lotsa dudes.txt differ diff --git a/build/content/sprites.pdn b/build/content/sprites.pdn index 1775674..49aef29 100644 Binary files a/build/content/sprites.pdn and b/build/content/sprites.pdn differ diff --git a/build/test.exe b/build/test.exe index 01857dc..2fddb01 100644 Binary files a/build/test.exe and b/build/test.exe differ diff --git a/design/notes.txt b/design/notes.txt index dabdd19..ecd9a30 100644 --- a/design/notes.txt +++ b/design/notes.txt @@ -1,13 +1,12 @@ tasks: (date) +[ ] implement healing beam (issued on 24:02:21) [ ] implement net hud and minilobby (issued on 18:02:21) [ ] implement brain behaviour (issued on 18:02:21) [ ] implement lobby cost constraints (issued on 18:02:21) [ ] implement edit unit directly (issued on 18:02:21) [ ] implement persistent settings ini (issued on 18:02:21) [ ] implement stats hud view (issued on 18:02:21) -[ ] implement move animation (issued on 18:02:21) -[ ] implement fire animation (issued on 18:02:21) [ ] implement explosions (issued on 18:02:21) [ ] design 3d units (issued on 18:02:21) [ ] design 3d map tiles (issued on 18:02:21) @@ -16,6 +15,8 @@ tasks: (date) [ ] implement sound (issued on 18:02:21) +[x] implement fire animation (issued on 18:02:21, done on 24:02:21) +[x] implement move animation (issued on 18:02:21, done on 24:02:21) [x] implement army hud view (issued on 18:02:21, done on 22:02:21) [x] implement naming template and army (issued on 18:02:21, done on 22:02:21) [x] implement cost function (issued on 18:02:21, done on 20:02:21) @@ -27,6 +28,7 @@ tasks: (date) [x] implement augment calculations (issued on 18:02:21, done on 18:02:21) [x] implement augment hud view (issued on 18:02:21, done on 18:02:21) + bugs: [ ] symmetric integration (found on 18:02:21) @@ -54,8 +56,35 @@ view from 18:02:21 to the end: details: +implement fire animation: + istantaneous: shot fxs and explosions are with their own timing + get an fx module -> bullets, damage, aoe explosions + spawn fxs at evenly spaced times throughout the turn + uneven salvo? (small random delay?) -> maybe + bullet travel <= time btw last shot and start of next turn + calculate target position by interpolating + when needed spawn explosion + what is a bullet? sprite? line? -> for now a line + + + +implement move animation: + interpolate from prev turn to current turn linerarly + modify unit.pos? do it in gst_render. + order of operations: m0, f0, m1, f1, m2, f2, ... + transitions: m0->m1 while f0, m1->m2 while f1, ... + at turn k: + k-1 m and f have to be available + at time t, timeof(k-1) < timeof(k) < t: + t is between k and k+1 + render animated position from m(k-1) to m(k), fire f(k-1) + need army snapshot from k-1 and from k + the one from k is the current state at t + the one before has to be saved somewhere -> army position buffer +-> done, little testing + implement naming army -> done -implement naming template -> almost +implement naming template -> done implement stats hud view: ? stats have to include individual weapon cooldowns and damage, what to do diff --git a/gst/fxs.c b/gst/fxs.c new file mode 100644 index 0000000..2078a89 --- /dev/null +++ b/gst/fxs.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +#include + +void fx_init (fxs *fx) { + fx->bullets = (bullet*)malloc(sizeof(bullet)*1024); + fx->bulletslen = 0; +} + +void fx_add_bullet (fxs *fx, bullet *b) { + fx->bullets[fx->bulletslen] = *b; + fx->bulletslen++; +} + +void fx_process (fxs *fx, float time) { + for (int i=0; ibulletslen; i++) { + bullet *b = fx->bullets+i; + if (time > b->endtime) { + // remove by replacing with last, dont care for order + *b = fx->bullets[fx->bulletslen-1]; + fx->bulletslen--; + } + } +} + + +void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time) { + for (int i=0; ibulletslen; i++) { + bullet *b = fx->bullets+i; + float travel_time = b->endtime - b->starttime; + float interval_time = time - b->starttime; + float amt = interval_time / travel_time; + if (amt < 0) amt = 0; if (amt > 1) amt = 1; + float pos[2] = { + b->from[0] *(1-amt) + b->to[0] *amt, + b->from[1] *(1-amt) + b->to[1] *amt + }; + float head[2]; vec2_sub(head, b->from, b->to); + vec2_norm(head); vec2_mul(head, head, 10); + SDL_SetRenderDrawColor(rend, + b->color[0], + b->color[1], + b->color[2], + 255); + SDL_RenderDrawLine(rend, + -cam[0] + pos[0], + -cam[1] + pos[1], + -cam[0] + pos[0] + head[0], + -cam[1] + pos[1] + head[1] + ); + } +} diff --git a/gst/fxs.h b/gst/fxs.h new file mode 100644 index 0000000..1efe97a --- /dev/null +++ b/gst/fxs.h @@ -0,0 +1,25 @@ +#ifndef FXS_H +#define FXS_H + +#include + +typedef struct { + float from[2]; + float to[2]; + float starttime; + float endtime; + float size; + int color[3]; +} bullet; + +typedef struct { + bullet *bullets; + int bulletslen; +} fxs; + +void fx_init (fxs *fx); +void fx_add_bullet (fxs *fx, bullet *b); +void fx_process (fxs *fx, float time); +void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time); + +#endif \ No newline at end of file diff --git a/gst/gst.c b/gst/gst.c index a97b4f9..6842826 100644 --- a/gst/gst.c +++ b/gst/gst.c @@ -13,7 +13,7 @@ void gst_init (gamestate *gst) { gst->starttime = FLT_MAX; gst->turn = 0; gst->coveredtime = 0; - gst->turnspeed = 0.35f; + gst->turnspeed = 0.75; } void gst_destroy (gamestate *gst) { @@ -32,6 +32,13 @@ void gst_get_maparmy(gamestate *gst, map **m, army **ar) { } } +void gst_lastpos (gamestate *gst) { + for (int i=0; iar.uslen; i++) { + gst->ar_lastpos[i][0] = gst->ar.us[i].pos[0]; + gst->ar_lastpos[i][1] = gst->ar.us[i].pos[1]; + } +} + void gst_tobattle (gamestate *gst) { if (gst->playernum == 1) { //info_load_army(gst->army_bp+1, "army"); @@ -63,6 +70,7 @@ void gst_tobattle (gamestate *gst) { gst->ar.us[gst->ar.uslen].owner = i; } } + gst_lastpos(gst); gst->starttime = FLT_MAX; gst->turn = 0; gst->coveredtime = 0; @@ -74,6 +82,51 @@ void gst_toeditor(gamestate *gst) { gst->playernum = 1; } +void gst_spawn_bullets (gamestate *gst, fxs *fx, a_dmg dmgs[], int dmgslen, + float time) +{ + map *m; army *ar; + gst_get_maparmy(gst, &m, &ar); + + bullet b; + int counts[MAXUNITS]; + for (int j=0;juslen; i++) { + for (int j=0; jus+i; + if (dmgs[j].u == u) { counts[i]++; } + } + } + int curr[MAXUNITS]; + for (int j=0;juslen; i++) { + for (int j=0; jus+i; + if (dmgs[j].u == u) { + unit *t = dmgs[j].t; + b.from[0] = u->pos[0]+16; + b.from[1] = u->pos[1]+16; + b.to[0] = t->pos[0]+16; + b.to[1] = t->pos[1]+16; + float n = (float)curr[i]/counts[i]; + float shot_time = time + n*gst->turnspeed; + b.starttime = shot_time; + b.endtime = shot_time + 0.1; + if (u->owner == 0) { + b.color[0] = 0; b.color[1] = 255; b.color[2] = 0; + } else { + b.color[0] = 255; b.color[1] = 0; b.color[2] = 0; + } + fx_add_bullet(fx, &b); + curr[i] ++; + } + } + } + +} + int gst_check_victory (gamestate *gst) { int counts[gst->playernum], max=-1, imax = -1; for (int i=0; iar.uslen; i++) { @@ -86,23 +139,93 @@ int gst_check_victory (gamestate *gst) { return imax; } -void gst_process (gamestate *gst, infos *info, float t) { - if (gst->starttime > t) gst->starttime = t; - float t_elapsed = t-gst->starttime; - if (t_elapsed > gst->coveredtime) { - gst->coveredtime += gst->turnspeed; - gst->turn ++; - map *m; army *ar; - gst_get_maparmy(gst, &m, &ar); - int move = army_move(info, ar, m); - int fire = army_fire(info, ar, m); - army_upkeep(info, ar, m); - printf("%d, %d\n", move, fire); - if (move == 0 && fire == 0) { - gst->turn_until_finish--; - } else { gst->turn_until_finish = 5; } - if (gst->turn_until_finish <= 0) { - gst->over = 1; +void gst_process (gamestate *gst, infos *info, fxs *fx, float t) { + if (gst->state == 1) { + if (gst->starttime > t) gst->starttime = t; + float t_elapsed = t-gst->starttime; + if (t_elapsed > gst->coveredtime) { + // next turn + gst_lastpos(gst); + gst->coveredtime += gst->turnspeed; + gst->turn ++; + map *m; army *ar; + gst_get_maparmy(gst, &m, &ar); + int move = army_move(info, ar, m); + + a_dmg dmgs[1024*8]; + int fire = army_fire(info, ar, m, dmgs); + army_upkeep(info, ar, m); + printf("%d, %d\n", move, fire); + if (move == 0 && fire == 0) { + gst->turn_until_finish--; + } else { gst->turn_until_finish = 5; } + if (gst->turn_until_finish <= 0) { + gst->over = 1; + } + gst_spawn_bullets(gst, fx, dmgs, fire, t); } } +} + +void gst_render (SDL_Renderer *rend, SDL_Texture *txsprites, txtd *textd, + gamestate *gst, infos *info, float t) +{ + float ts = 32; + int posx = gst->cam[0]; + int posy = gst->cam[1]; + map *m; army *ar; + gst_get_maparmy(gst, &m, &ar); + + // render map + for (int y=0; ysy; y++) { + for (int x=0; xsx; x++) { + float px = x*ts; + float py = y*ts; + SDL_Rect srcRect = { 1*ts, 0*ts, ts, ts }; + SDL_Rect dstRect = { (int)px-posx, (int)py-posy, ts, ts }; + SDL_RenderCopy(rend, txsprites, &srcRect, &dstRect); + } + } + + /* assuming one turn = 1s, amt domain = [0, 1) */ + float amt = t - (gst->starttime+gst->coveredtime); + amt = (amt / gst->turnspeed) + 1; + if (amt > 1) amt = 1; if (amt < 0) amt = 0; // clamping away fuzzyness + + // render enemies + for (int i=0; iuslen; i++) { + if (ar->us[i].hp <= 0) continue; + float present_x = ar->us[i].pos[0]; + float present_y = ar->us[i].pos[1]; + + float x = present_x, y = present_y; + if (gst->state == 1) { + x = present_x*(amt) + gst->ar_lastpos[i][0]*(1-amt); + y = present_y*(amt) + gst->ar_lastpos[i][1]*(1-amt); + } + + SDL_Rect srcRect = { ar->us[i].info.chassis*ts, ts, ts, ts }; + SDL_Rect dstRect = { (int)x-posx, (int)y-posy, ts, ts }; + SDL_RenderCopy(rend, txsprites, &srcRect, &dstRect); + + float amt = ar->us[i].hp + / info_unit_get_health(info, &ar->us[i].info); + SDL_Rect hprect = { + (int)x-posx, (int)y-posy+ts-5, + ts*amt, 6 }; + int sw = 1 ? ar->us[i].owner : 0; + SDL_SetRenderDrawColor(rend, 255*sw, 255*(1-sw), 0, 255); + SDL_RenderFillRect(rend, &hprect); + + SDL_SetTextureColorMod(textd->tex_small, sw*100, 100*(1-sw), 0); + char shp[32]; sprintf(shp, "%.0f", ar->us[i].hp); + float php[2] = { (int)x-posx, (int)y-posy+ts-5 }; + render_text_small(rend, shp, php, textd); + + SDL_SetTextureColorMod(textd->tex_small, 255, 160, 0); + char sch[32]; sprintf(sch, "%.0f", ar->us[i].charge); + float pch[2] = { (int)x-posx, (int)y-posy+ts+1 }; + render_text_small(rend, sch, pch, textd); + SDL_SetTextureColorMod(textd->tex_small, 0, 0, 0); + } } \ No newline at end of file diff --git a/gst/gst.h b/gst/gst.h index 171e213..ad0a685 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -4,6 +4,11 @@ #include #include #include +#include +#include + +#include +#include #define MAXMAP 10 @@ -13,6 +18,7 @@ typedef struct { int playernum; map map_battle; army ar; + float ar_lastpos[MAXUNITS][2]; int state; float cam[2]; float starttime; @@ -26,8 +32,12 @@ typedef struct { void gst_init (gamestate *gst); void gst_destroy (gamestate *gst); void gst_get_maparmy(gamestate *gst, map **m, army **ar); + void gst_tobattle (gamestate *gst); void gst_toeditor (gamestate *gst); -void gst_process (gamestate *gst, infos *info, float t); + +void gst_process (gamestate *gst, infos *info, fxs *fx, float t); +void gst_render (SDL_Renderer *rend, SDL_Texture *txsprites, txtd *textd, + gamestate *gst, infos *info, float t); #endif \ No newline at end of file diff --git a/gst/units.c b/gst/units.c index 89c9489..b699e26 100644 --- a/gst/units.c +++ b/gst/units.c @@ -184,7 +184,7 @@ int army_move (infos *info, army *ar, map *m) { return iter; } -int army_fire (infos *info, army *ar, map *m) { +int army_fire (infos *info, army *ar, map *m, a_dmg dmgs[]) { for (int i=0; iuslen; i++) { unit *u = ar->us+i; int lw = u->info.levels[LEVEL_CHASSIS]; @@ -192,7 +192,7 @@ int army_fire (infos *info, army *ar, map *m) { u->cooldown[j] += 1; } } - struct dmg { unit *u; float dam; } dmgs[1024*8]; int dmgslen = 0; + int dmgslen = 0; unit *t[32]; for (int i=0; iuslen; i++) { unit *u = ar->us+i; @@ -205,7 +205,8 @@ int army_fire (infos *info, army *ar, map *m) { float range = info_unit_get_range(info, &u->info, j); unit_search(info, ar, m, u, t, range); if (t[0]!=NULL) { - dmgs[dmgslen].u = t[0]; + dmgs[dmgslen].u = u; + dmgs[dmgslen].t = t[0]; dmgs[dmgslen].dam = info_unit_get_damage_target( info, &u->info, j, &t[0]->info); dmgslen++; @@ -216,9 +217,9 @@ int army_fire (infos *info, army *ar, map *m) { } } for (int i=0; ihp -= dmgs[i].dam; - if (dmgs[i].u->hp <= 0) { - unit_dead(ar, m, dmgs[i].u); + dmgs[i].t->hp -= dmgs[i].dam; + if (dmgs[i].t->hp <= 0) { + unit_dead(ar, m, dmgs[i].t); } } return dmgslen; diff --git a/gst/units.h b/gst/units.h index d574b79..c7cc575 100644 --- a/gst/units.h +++ b/gst/units.h @@ -31,12 +31,15 @@ typedef struct army_ { void unit_init (infos *info, army *ar, map *m, int x, int y, info_unit *iu, int owner, unit *u); void unit_remove (army *ar, map *m, unit *u); + void army_grid_init(army *ar); void army_init (army *ar, map *m); void army_destory(army *ar); void army_spawn (army *ar, map *m, unit u); int army_move (infos *info, army *ar, map *m); -int army_fire (infos *info, army *ar, map *m); + +typedef struct { unit *u, *t; float dam; } a_dmg; +int army_fire (infos *info, army *ar, map *m, a_dmg dmgs[]); void army_upkeep (infos *info, army *ar, map *m); #endif \ No newline at end of file diff --git a/main.c b/main.c index 89e5edd..b34ea61 100644 --- a/main.c +++ b/main.c @@ -53,8 +53,8 @@ int main( int argc, char* args[] ) { SDL_SetTextureColorMod(textd.tex, 0, 0, 0); SDL_Surface* imagesmall = SDL_LoadBMP("content/gfsmall.bmp"); - SDL_Texture* txsmall = SDL_CreateTextureFromSurface(rend, imagesmall); - SDL_SetTextureColorMod(txsmall, 0, 0, 0); + textd.tex_small = SDL_CreateTextureFromSurface(rend, imagesmall); + SDL_SetTextureColorMod(textd.tex_small, 0, 0, 0); SDL_Surface* sprites = SDL_LoadBMP("content/sprites.bmp"); SDL_Texture* txsprites = SDL_CreateTextureFromSurface(rend, sprites); @@ -107,6 +107,10 @@ int main( int argc, char* args[] ) { float mlast[2] = {0, 0}; + // fxs + fxs fx; + fx_init(&fx); + // sockets net_client netc; net_server nets; @@ -150,21 +154,13 @@ int main( int argc, char* args[] ) { float delta[2] = { mkb.mx-mlast[0], mkb.my-mlast[1] }; vec2_sub(gst.cam, gst.cam, delta); } - /* - if (mkb_search(&mkb, SDL_SCANCODE_E)) { - map *m; army *ar; - gst_get_maparmy(&gst, &m, &ar); - army_move(&info, ar, m); - army_fire(&info, ar, m); - }*/ hud_process(&gs, &_hud, &mkb, &info, gst.army_bp+0, &gst.map_editor, &textd, &gst, &netc, &nets, sounds); - if (gst.state == 1) { - gst_process(&gst, &info, tot_time); - } + gst_process(&gst, &info, &fx, tot_time); + fx_process(&fx, tot_time); render = true; unprocessed_time -= FRAME_TIME; @@ -176,53 +172,9 @@ int main( int argc, char* args[] ) { SDL_SetRenderDrawColor(rend, 255, 255, 255, 255); SDL_RenderClear(rend); - float ts = 32; - int posx = gst.cam[0]; - int posy = gst.cam[1]; - - map *m; army *ar; - gst_get_maparmy(&gst, &m, &ar); - - // render map - for (int y=0; ysy; y++) { - for (int x=0; xsx; x++) { - float px = x*ts; - float py = y*ts; - SDL_Rect srcRect = { 1*ts, 0*ts, ts, ts }; - SDL_Rect dstRect = { (int)px-posx, (int)py-posy, ts, ts }; - SDL_RenderCopy(rend, txsprites, &srcRect, &dstRect); - } - } + gst_render(rend, txsprites, &textd, &gst, &info, tot_time); - // render enemies - for (int i=0; iuslen; i++) { - if (ar->us[i].hp <= 0) continue; - float x = ar->us[i].pos[0]; - float y = ar->us[i].pos[1]; - SDL_Rect srcRect = { ar->us[i].info.chassis*ts, ts, ts, ts }; - SDL_Rect dstRect = { (int)x-posx, (int)y-posy, ts, ts }; - SDL_RenderCopy(rend, txsprites, &srcRect, &dstRect); - - float amt = ar->us[i].hp - / info_unit_get_health(&info, &ar->us[i].info); - SDL_Rect hprect = { - (int)x-posx, (int)y-posy+ts-5, - ts*amt, 6 }; - int sw = 1 ? ar->us[i].owner : 0; - SDL_SetRenderDrawColor(rend, 255*sw, 255*(1-sw), 0, 255); - SDL_RenderFillRect(rend, &hprect); - - SDL_SetTextureColorMod(txsmall, sw*100, 100*(1-sw), 0); - char shp[32]; sprintf(shp, "%.0f", ar->us[i].hp); - float php[2] = { (int)x-posx, (int)y-posy+ts-5 }; - render_text_small(rend, shp, php, txsmall); - - SDL_SetTextureColorMod(txsmall, 255, 160, 0); - char sch[32]; sprintf(sch, "%.0f", ar->us[i].charge); - float pch[2] = { (int)x-posx, (int)y-posy+ts+1 }; - render_text_small(rend, sch, pch, txsmall); - SDL_SetTextureColorMod(txsmall, 0, 0, 0); - } + fx_render(rend, &fx, gst.cam, tot_time); hud_render(&_hud, rend, &textd, &mkb, &info, txsprites, &gst, tot_time); diff --git a/render/render_text.c b/render/render_text.c index 6b801eb..c701fd7 100644 --- a/render/render_text.c +++ b/render/render_text.c @@ -50,15 +50,14 @@ void render_text_scaled (SDL_Renderer* rend, char str[], } } -void render_text_small (SDL_Renderer* rend, char str[], float off[], - SDL_Texture *texsmall) +void render_text_small (SDL_Renderer* rend, char str[], float off[], txtd *t) { int width = 0; for (int i=0; str[i]!='\0'; i++) { int char_i = str[i]; SDL_Rect srcRect = { (char_i%32)*5+1, (char_i/32)*7+1, 4, 6 }; SDL_Rect dstRect = { off[0]+width, off[1], 4, 6 }; - SDL_RenderCopy(rend, texsmall, &srcRect, &dstRect); + SDL_RenderCopy(rend, t->tex_small, &srcRect, &dstRect); width += 5; } } \ No newline at end of file diff --git a/render/render_text.h b/render/render_text.h index a9e952e..3cad87b 100644 --- a/render/render_text.h +++ b/render/render_text.h @@ -5,6 +5,7 @@ typedef struct { SDL_Texture *tex; + SDL_Texture *tex_small; int cw[128]; } txtd; @@ -15,7 +16,6 @@ void render_text (SDL_Renderer* gRenderer, char str[], float off[], txtd *t); void render_text_scaled (SDL_Renderer* gRenderer, char str[], float off[], txtd *t, float scale); -void render_text_small (SDL_Renderer* rend, char str[], float off[], - SDL_Texture *texsmall); +void render_text_small (SDL_Renderer* rend, char str[], float off[], txtd *t); #endif \ No newline at end of file -- cgit v1.2.3-54-g00ecf