diff options
Diffstat (limited to 'gst')
-rw-r--r-- | gst/fxs.c | 98 | ||||
-rw-r--r-- | gst/fxs.h | 32 | ||||
-rw-r--r-- | gst/gst.c | 111 | ||||
-rw-r--r-- | gst/gst.h | 2 | ||||
-rw-r--r-- | gst/units.c | 40 |
5 files changed, 226 insertions, 57 deletions
@@ -1,5 +1,6 @@ #include <stdlib.h> #include <stdio.h> +#include <math.h> #include "../umath/vec.h" @@ -7,31 +8,105 @@ #include "units.h" void fx_init (fxs *fx) { - fx->bullets = (bullet*)malloc(sizeof(bullet)*1024); + fx->bullets = (bullet*)malloc(sizeof(bullet)*FXS_BULLET_MAX); fx->bulletslen = 0; + fx->explosions = (explosion*)malloc(sizeof(explosion)*FXS_EXPLOSION_MAX); + fx->explosionslen = 0; } void fx_add_bullet (fxs *fx, bullet *b) { - if (fx->bulletslen >= 1024-1) return; + if (fx->bulletslen >= FXS_BULLET_MAX-1) return; fx->bullets[fx->bulletslen] = *b; fx->bulletslen++; } +void fx_spread_to_head (float spread, float head[]) { + head[0] = 1-spread; if (spread<0.5) head[0] = spread; + head[1] = 1-spread*2; + vec2_norm(head); +} + +/* + * param: pos is the center of the explosion + * param: vel is the heading of the explosion + * param: force is added to vel and scaled by mass + * param: spread [0, 1] is half the angle of the explosion + * param: speed [0, inf] is the initial speed + */ +void fx_explosion_init (fxs *fx, explosion *e, + float pos[], float vel[], float color[], float force[], + float spread, float speed, int n, float time, float lifetime) +{ + float normvel[2] = { vel[0], vel[1] }; vec2_norm(normvel); + float perpvel[2] = { normvel[1], -normvel[0] }; + e->pos[0] = pos[0]; e->pos[1] = pos[1]; + e->partslen = n; + e->force[0] = force[0]; e->force[1] = force[1]; + e->starttime = time; + e->friction = 0.95; + for (int j=0; j<n; j++) { + particle *p = e->parts+j; + float sample = rand()%1000/1000.0 * spread; + float head[2]; fx_spread_to_head(sample, head); + if (j%2 == 0) head[0] *= -1; + float dir[2] = { + -head[0]*normvel[1] - head[1]*perpvel[1], + head[0]*normvel[0] + head[1]*perpvel[0] + }; + p->lifetime = lifetime; + p->mass = 1; + p->pos[0] = pos[0]; p->pos[1] = pos[1]; + p->vel[0] = dir[0]; p->vel[1] = dir[1]; + vec2_mul(p->vel, p->vel, speed+(rand()%1000)/1000.0*speed/2); + p->color[0] = color[0]; + p->color[1] = color[1]; + p->color[2] = color[2]; + } +} + +void fx_add_explosion (fxs *fx, explosion *e) { + if (fx->explosionslen >= FXS_EXPLOSION_MAX-1) return; + fx->explosions[fx->explosionslen] = *e; + fx->explosionslen++; +} + void fx_process (fxs *fx, float time) { for (int i=0; i<fx->bulletslen; i++) { bullet *b = fx->bullets+i; + if (b->starttime > time) continue; if (time > b->endtime) { // remove by replacing with last, dont care for order *b = fx->bullets[fx->bulletslen-1]; fx->bulletslen--; } } + + for (int i=0; i<fx->explosionslen; i++) { + explosion *e = fx->explosions+i; + if (e->starttime > time) continue; + int sum = e->partslen; + for (int j=0; j<e->partslen; j++) { + if (e->starttime + e->parts[j].lifetime >= time) { + vec2_add(e->parts[j].pos, e->parts[j].pos, e->parts[j].vel); + float forcemass[2]; + vec2_mul(forcemass, e->force, e->parts[j].mass); + vec2_add(e->parts[j].vel, e->parts[j].vel, forcemass); + vec2_mul(e->parts[j].vel, e->parts[j].vel, e->friction); + } else { sum -= 1; } + } + if (sum == 0) { + // remove by replacing with last, dont care for order + *e = fx->explosions[fx->explosionslen-1]; + fx->explosionslen--; + } + } } void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time) { for (int i=0; i<fx->bulletslen; i++) { bullet *b = fx->bullets+i; + if (b->starttime > time) continue; float travel_time = b->endtime - b->starttime; float interval_time = time - b->starttime; float amt = interval_time / travel_time; @@ -46,10 +121,7 @@ void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time) { if (dist < 10) { mag = dist; } vec2_norm(head); vec2_mul(head, head, mag); SDL_SetRenderDrawColor(rend, - b->color[0], - b->color[1], - b->color[2], - 255); + b->color[0], b->color[1], b->color[2], 255); SDL_RenderDrawLine(rend, -cam[0] + pos[0], -cam[1] + pos[1], @@ -57,4 +129,18 @@ void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time) { -cam[1] + pos[1] + head[1] ); } + + for (int i=0; i<fx->explosionslen; i++) { + explosion *e = fx->explosions+i; + if (e->starttime > time) continue; + for (int j=0; j<e->partslen; j++) { + particle *p = e->parts+j; + if (e->starttime + p->lifetime >= time) { + SDL_SetRenderDrawColor(rend, + p->color[0], p->color[1], p->color[2], 255); + SDL_RenderDrawPoint(rend, + -cam[0] + p->pos[0], -cam[1] + p->pos[1]); + } + } + } } @@ -3,22 +3,52 @@ #include <SDL2/SDL.h> +#define FXS_BULLET_MAX 4096 +#define FXS_EXPLOSION_MAX 2048 + typedef struct { float from[2]; float to[2]; float starttime; float endtime; float size; - int color[3]; + float color[3]; } bullet; typedef struct { + float pos[2]; + float vel[2]; + float color[3]; + float size; + float mass; + float lifetime; +} particle; + +typedef struct { + float pos[2]; + float force[2]; + float friction; + particle parts[32]; + int partslen; + float starttime; +} explosion; + +typedef struct { bullet *bullets; int bulletslen; + explosion *explosions; + int explosionslen; } fxs; void fx_init (fxs *fx); + void fx_add_bullet (fxs *fx, bullet *b); + +void fx_explosion_init (fxs *fx, explosion *e, + float pos[], float vel[], float color[], float force[], + float spread, float speed, int n, float time, float lifetime); +void fx_add_explosion (fxs *fx, explosion *e); + void fx_process (fxs *fx, float time); void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time); @@ -4,6 +4,7 @@ #include <float.h> #include "gst.h" +#include "../umath/vec.h" void gst_init (gamestate *gst) { map_init(&gst->map_editor, MAXMAP, MAXMAP, 32); @@ -33,11 +34,9 @@ void gst_get_maparmy(gamestate *gst, map **m, army **ar) { } } -void gst_lastpos (gamestate *gst) { - for (int i=0; i<gst->ar.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_ar_past_cycle (gamestate *gst) { + gst->ar_past[1] = gst->ar_past[0]; + gst->ar_past[0] = gst->ar; } void gst_compute_stats (gamestate *gst, infos *info) { @@ -48,7 +47,6 @@ void gst_compute_stats (gamestate *gst, infos *info) { void gst_tobattle (gamestate *gst, infos *info) { if (gst->playernum == 1) { - //info_load_army(gst->army_bp+1, "army"); gst->army_bp[1] = gst->army_bp[0]; gst->playernum = 2; } @@ -79,7 +77,7 @@ void gst_tobattle (gamestate *gst, infos *info) { } gst_compute_stats(gst, info); - gst_lastpos(gst); + gst_ar_past_cycle(gst); gst->starttime = FLT_MAX; gst->turn = 0; gst->coveredtime = 0; @@ -117,21 +115,62 @@ void gst_spawn_bullets (gamestate *gst, fxs *fx, a_dmg dmgs[], int dmgslen, unit *u = ar->us+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 travel_time = 0.1; + + float u_past_x = gst->ar_past[1].us[i].pos[0]; + float u_past_y = gst->ar_past[1].us[i].pos[1]; + float u_pres_x = gst->ar_past[0].us[i].pos[0]; + float u_pres_y = gst->ar_past[0].us[i].pos[1]; + + int t_i = 0; + for (int k=0; k<ar->uslen; k++) { + if (ar->us+k == t) { t_i = k; break; } + } + + float t_past_x = gst->ar_past[1].us[t_i].pos[0]; + float t_past_y = gst->ar_past[1].us[t_i].pos[1]; + float t_pres_x = gst->ar_past[0].us[t_i].pos[0]; + float t_pres_y = gst->ar_past[0].us[t_i].pos[1]; + + // interpolate from the past + b.from[0] = u_pres_x*(n) + u_past_x*(1-n)+16 +rand()%8-4; + b.from[1] = u_pres_y*(n) + u_past_y*(1-n)+16 +rand()%8-4; + b.to[0] = t_pres_x*(n) + t_past_x*(1-n)+16 +rand()%16-8; + b.to[1] = t_pres_y*(n) + t_past_y*(1-n)+16 +rand()%16-8; + + float travel_time = 0.3; float shot_time = time + n*gst->turnspeed; b.starttime = shot_time; b.endtime = shot_time + travel_time; - 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; - } + + float colors[2][3] = { {0,255,0}, {255,0,0} }; + int selcol = 0; + + if (u->owner == 0) { selcol = 0; } + else { selcol = 1; } + b.color[0] = colors[selcol][0]; + b.color[1] = colors[selcol][1]; + b.color[2] = colors[selcol][2]; fx_add_bullet(fx, &b); + + + { /* shooting particles */ + float vel[2]; vec2_sub(vel, b.to, b.from); + float force[2] = { 0, 0 }; + explosion e; + fx_explosion_init(fx, &e, b.from, vel, colors[selcol], + force, 0.1, 2, 4, b.starttime, 0.2); + fx_add_explosion(fx, &e); + } + + { /* hit particles */ + float vel[2]; vec2_sub(vel, b.to, b.from); + float force[2] = { 0, 0 }; + explosion e; + fx_explosion_init(fx, &e, b.to, vel, colors[1-selcol], + force, 0.15, 4, 8, b.endtime, 0.8); + fx_add_explosion(fx, &e); + } curr[i] ++; } } @@ -154,7 +193,6 @@ int gst_check_victory (gamestate *gst) { } void gst_next_turn (gamestate *gst, infos *info, fxs *fx, float t) { - gst_lastpos(gst); gst->coveredtime += gst->turnspeed; gst->turn ++; map *m; army *ar; @@ -170,6 +208,7 @@ void gst_next_turn (gamestate *gst, infos *info, fxs *fx, float t) { if (gst->turn_until_finish <= 0) { gst->over = 1; } + gst_ar_past_cycle(gst); gst_spawn_bullets(gst, fx, dmgs, fire, t); } @@ -214,24 +253,34 @@ void gst_render (SDL_Renderer *rend, SDL_Texture *txsprites, txtd *textd, amt = (amt / gst->turnspeed) + 1; if (amt > 1) amt = 1; if (amt < 0) amt = 0; // clamping away fuzzyness + army *past = ar; + army *present = ar; + if (gst->state == 1) { + past = gst->ar_past +1; + present = gst->ar_past +0; + } + // render units for (int i=0; i<ar->uslen; i++) { - if (ar->us[i].hp <= 0) continue; - float present_x = ar->us[i].pos[0]; - float present_y = ar->us[i].pos[1]; + if (present->us[i].hp <= 0) continue; + + float past_x = past->us[i].pos[0]; + float past_y = past->us[i].pos[1]; + + float present_x = present->us[i].pos[0]; + float present_y = present->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); - } + float x = present_x*(amt) + past_x*(1-amt); + float y = present_y*(amt) + past_y*(1-amt); - SDL_Rect srcRect = { ar->us[i].info.chassis*ts, ts, ts, ts }; + SDL_Rect srcRect = { + present->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); - stats_unit base; stats_unit_compute(info, &ar->us[i].info, &base); - float amt = ar->us[i].hp / base.frame.hp; + stats_unit base; + stats_unit_compute(info, &present->us[i].info, &base); + float amt = present->us[i].hp / base.frame.hp; SDL_Rect hprect = { (int)x-posx, (int)y-posy+ts-5, ts*amt, 6 }; @@ -240,12 +289,12 @@ void gst_render (SDL_Renderer *rend, SDL_Texture *txsprites, txtd *textd, 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); + char shp[32]; sprintf(shp, "%.0f", present->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); + char sch[32]; sprintf(sch, "%.0f", present->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); @@ -20,7 +20,7 @@ typedef struct { int playernum; map map_battle; army ar; - float ar_lastpos[MAXUNITS][2]; + army ar_past[2]; stats_unit ustats[MAXUNITS]; int state; diff --git a/gst/units.c b/gst/units.c index aeced1b..8b84d52 100644 --- a/gst/units.c +++ b/gst/units.c @@ -181,6 +181,7 @@ int army_move_step (infos *info, army *ar, map *m, stats_unit *ustats) { int army_move (infos *info, army *ar, map *m, stats_unit *ustats) { for (int i=0; i<ar->uslen; i++) { ar->us[i].move_points += ustats[i].frame.speed; + if (ar->us[i].move_points > 1) ar->us[i].move_points = 1; } int iter = 0, finished = army_move_step(info, ar, m, ustats); for (; iter<5 && !finished; iter++) { @@ -197,6 +198,7 @@ int army_fire (infos *info, army *ar, map *m, a_dmg dmgs[], int lw = u->info.levels[LEVEL_CHASSIS]; for (int j=0; j<ustats[i].weaponlen; j++) { u->cooldown[j] += 1; + if (u->cooldown[j] > 1) u->cooldown[j] = 1; } } int dmgslen = 0; @@ -209,24 +211,26 @@ int army_fire (infos *info, army *ar, map *m, a_dmg dmgs[], for (int j=0; j<ustats[i].weaponlen; j++) { if (u->cooldown[j] <= 0) continue; float range = ustats[i].weapon[j].range; - unit_search(info, ar, m, u, t, range); - if (t[0]!=NULL) { - dmgs[dmgslen].u = u; - dmgs[dmgslen].t = t[0]; - - int t_i = 0; - for (int k=0; k<ar->uslen; k++) { - if (ar->us+k == t[0]) { t_i = k; break; } - } - float dam = stats_compute_damage( - &ustats[i].weapon[j], - &ustats[t_i].frame, u->reduced_armor); - - dmgs[dmgslen].dam = dam; - dmgslen++; - u->cooldown[j] -= ustats[i].weapon[j].cooldown; - u->charge -= ustats[i].weapon[j].charge_per_shot; - if (u->charge < 0) u->charge = 0; + while (u->cooldown[j] > 0) { + unit_search(info, ar, m, u, t, range); + if (t[0]!=NULL) { + dmgs[dmgslen].u = u; + dmgs[dmgslen].t = t[0]; + + int t_i = 0; + for (int k=0; k<ar->uslen; k++) { + if (ar->us+k == t[0]) { t_i = k; break; } + } + float dam = stats_compute_damage( + &ustats[i].weapon[j], + &ustats[t_i].frame, u->reduced_armor); + + dmgs[dmgslen].dam = dam; + dmgslen++; + u->cooldown[j] -= ustats[i].weapon[j].cooldown; + u->charge -= ustats[i].weapon[j].charge_per_shot; + if (u->charge < 0) u->charge = 0; + } else break; } } } |