engine-c: vehicle tread/wheel roll via Unit.anim
This commit is contained in:
parent
48960b11fa
commit
8b55fa687a
3 changed files with 149 additions and 4 deletions
|
|
@ -220,6 +220,88 @@ static void draw_unit_shadow(SDL_Renderer *ren, int cx, int cy, int rad) {
|
|||
}
|
||||
}
|
||||
|
||||
static int live_unit_wheeled(UnitType t) {
|
||||
return t == UT_BUGGY || t == UT_JEEP || t == UT_HARVESTER
|
||||
|| t == UT_BEAST || t == UT_MISSILE || t == UT_MEDIC;
|
||||
}
|
||||
static int live_unit_tracked(UnitType t) {
|
||||
return t == UT_TANK || t == UT_RAVAGER;
|
||||
}
|
||||
static int live_unit_rolling(UnitType t) {
|
||||
return live_unit_wheeled(t) || live_unit_tracked(t);
|
||||
}
|
||||
|
||||
/* Spoke (wheeled) / hash (tracked) on tyre discs; phase = Unit.anim rad.
|
||||
* Local 30×30 chassis coords match snapshot LX/LY, scaled to live sz. */
|
||||
static void live_tyre_mark(SDL_Renderer *ren, int cx, int cy, int rad,
|
||||
float phase, int wheeled) {
|
||||
int n = wheeled ? 4 : 3;
|
||||
float step = (float)(2.0 * M_PI / (double)n);
|
||||
float r0 = wheeled ? rad * 0.30f : rad * 0.55f;
|
||||
float r1 = rad * 0.90f;
|
||||
SDL_SetRenderDrawColor(ren, 205, 200, 180, 240);
|
||||
for (int i = 0; i < n; i++) {
|
||||
float a = phase + i * step;
|
||||
int x1 = cx + (int)(cosf(a) * r0);
|
||||
int y1 = cy + (int)(sinf(a) * r0);
|
||||
int x2 = cx + (int)(cosf(a) * r1);
|
||||
int y2 = cy + (int)(sinf(a) * r1);
|
||||
SDL_RenderDrawLine(ren, x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
|
||||
static void live_draw_tyre_marks(SDL_Renderer *ren, Unit *u, int cx, int cy, int sz) {
|
||||
if (!live_unit_rolling(u->type)) return;
|
||||
float c = cosf(u->heading), s = sinf(u->heading);
|
||||
float sc = (float)sz / 30.0f;
|
||||
float ph = u->anim;
|
||||
#define LTX(lx, ly) (cx + (int)((((lx)-15)*sc)*c - (((ly)-15)*sc)*s))
|
||||
#define LTY(lx, ly) (cy + (int)((((lx)-15)*sc)*s + (((ly)-15)*sc)*c))
|
||||
#define LRAD(n) ((int)((n) * sc + 0.5f))
|
||||
switch (u->type) {
|
||||
case UT_BUGGY:
|
||||
live_tyre_mark(ren, LTX(8,7), LTY(8,7), LRAD(4), ph, 1);
|
||||
live_tyre_mark(ren, LTX(22,7), LTY(22,7), LRAD(4), ph, 1);
|
||||
live_tyre_mark(ren, LTX(8,23), LTY(8,23), LRAD(4), ph, 1);
|
||||
live_tyre_mark(ren, LTX(22,23),LTY(22,23),LRAD(4), ph, 1);
|
||||
break;
|
||||
case UT_TANK:
|
||||
live_tyre_mark(ren, LTX(8,23), LTY(8,23), LRAD(4), ph, 0);
|
||||
live_tyre_mark(ren, LTX(22,23),LTY(22,23),LRAD(4), ph, 0);
|
||||
break;
|
||||
case UT_HARVESTER:
|
||||
live_tyre_mark(ren, LTX(8,23), LTY(8,23), LRAD(4), ph, 1);
|
||||
live_tyre_mark(ren, LTX(22,23),LTY(22,23),LRAD(4), ph, 1);
|
||||
break;
|
||||
case UT_JEEP:
|
||||
live_tyre_mark(ren, LTX(9,22), LTY(9,22), LRAD(4), ph, 1);
|
||||
live_tyre_mark(ren, LTX(21,22),LTY(21,22),LRAD(4), ph, 1);
|
||||
break;
|
||||
case UT_BEAST:
|
||||
live_tyre_mark(ren, LTX(9,21), LTY(9,21), LRAD(3), ph, 1);
|
||||
live_tyre_mark(ren, LTX(14,22),LTY(14,22),LRAD(3), ph, 1);
|
||||
live_tyre_mark(ren, LTX(19,21),LTY(19,21),LRAD(3), ph, 1);
|
||||
live_tyre_mark(ren, LTX(23,22),LTY(23,22),LRAD(3), ph, 1);
|
||||
break;
|
||||
case UT_RAVAGER:
|
||||
live_tyre_mark(ren, LTX(7,23), LTY(7,23), LRAD(4), ph, 0);
|
||||
live_tyre_mark(ren, LTX(23,23),LTY(23,23),LRAD(4), ph, 0);
|
||||
break;
|
||||
case UT_MISSILE:
|
||||
live_tyre_mark(ren, LTX(9,23), LTY(9,23), LRAD(4), ph, 1);
|
||||
live_tyre_mark(ren, LTX(21,23),LTY(21,23),LRAD(4), ph, 1);
|
||||
break;
|
||||
case UT_MEDIC:
|
||||
live_tyre_mark(ren, LTX(10,24),LTY(10,24),LRAD(4), ph, 1);
|
||||
live_tyre_mark(ren, LTX(20,24),LTY(20,24),LRAD(4), ph, 1);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
#undef LTX
|
||||
#undef LTY
|
||||
#undef LRAD
|
||||
}
|
||||
|
||||
void render_units(Game *g) {
|
||||
for (int i = 0; i < g->unit_count; i++) {
|
||||
Unit *u = &g->units[i];
|
||||
|
|
@ -234,6 +316,8 @@ void render_units(Game *g) {
|
|||
draw_unit_shadow(g->ren, cx, cy, sz / 4 + 4);
|
||||
SDL_Texture *tex = g->spr.unit[u->type][u->faction];
|
||||
draw_tex_world(g, tex, u->x, u->y, sz, sz, u->heading, 255);
|
||||
/* rotating spokes / tread hashes (parity with snapshot tyre_mark) */
|
||||
live_draw_tyre_marks(g->ren, u, cx, cy, sz);
|
||||
/* cream heading tick (parity with snapshot LX/LY overlay) */
|
||||
{
|
||||
float tick = (float)(sz / 2 + 6);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,23 @@ static void terrain_color(TerrainType t, uint8_t *r, uint8_t *g, uint8_t *b) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Spoke (wheeled) or hash (tracked) marks on a tyre disc; phase = Unit.anim rad. */
|
||||
static void tyre_mark(int cx, int cy, int rad, float phase, int wheeled) {
|
||||
uint8_t sr = 205, sg = 200, sb = 180;
|
||||
int n = wheeled ? 4 : 3;
|
||||
float step = (float)(2.0 * M_PI / (double)n);
|
||||
float r0 = wheeled ? rad * 0.30f : rad * 0.55f;
|
||||
float r1 = rad * 0.90f;
|
||||
for (int i = 0; i < n; i++) {
|
||||
float a = phase + i * step;
|
||||
int x1 = cx + (int)(cosf(a) * r0);
|
||||
int y1 = cy + (int)(sinf(a) * r0);
|
||||
int x2 = cx + (int)(cosf(a) * r1);
|
||||
int y2 = cy + (int)(sinf(a) * r1);
|
||||
line(x1, y1, x2, y2, sr, sg, sb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Classic RTS silhouette: thin black outline, then bright faction fill.
|
||||
* Dark outer discs previously read as olive-mud blobs under NN zoom. */
|
||||
static void draw_unit(Unit *u, int sx, int sy) {
|
||||
|
|
@ -113,6 +130,7 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
uint8_t mr = 70, mg = 65, mb = 58; /* tyre */
|
||||
float c = cosf(u->heading), s = sinf(u->heading);
|
||||
const float sc = SHOT_UNIT_SCALE;
|
||||
float ph = u->anim; /* continuous roll phase for wheeled/tracked */
|
||||
#define SI(n) ((int)((n) * sc + 0.5f))
|
||||
#define LX(lx, ly) (sx + (int)((((lx)-15)*sc)*c - (((ly)-15)*sc)*s))
|
||||
#define LY(lx, ly) (sy + (int)((((lx)-15)*sc)*s + (((ly)-15)*sc)*c))
|
||||
|
|
@ -135,6 +153,10 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
disc(LX(22,7), LY(22,7), SI(4), mr, mg, mb);
|
||||
disc(LX(8,23), LY(8,23), SI(4), mr, mg, mb);
|
||||
disc(LX(22,23), LY(22,23), SI(4), mr, mg, mb);
|
||||
tyre_mark(LX(8,7), LY(8,7), SI(4), ph, 1);
|
||||
tyre_mark(LX(22,7), LY(22,7), SI(4), ph, 1);
|
||||
tyre_mark(LX(8,23), LY(8,23), SI(4), ph, 1);
|
||||
tyre_mark(LX(22,23), LY(22,23), SI(4), ph, 1);
|
||||
line(sx, sy, LX(29,15), LY(29,15), 40, 36, 30);
|
||||
break;
|
||||
case UT_TANK:
|
||||
|
|
@ -144,6 +166,8 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
line(sx, sy, LX(30,15), LY(30,15), 50, 45, 35);
|
||||
disc(LX(8,23), LY(8,23), SI(4), mr, mg, mb);
|
||||
disc(LX(22,23), LY(22,23), SI(4), mr, mg, mb);
|
||||
tyre_mark(LX(8,23), LY(8,23), SI(4), ph, 0);
|
||||
tyre_mark(LX(22,23), LY(22,23), SI(4), ph, 0);
|
||||
break;
|
||||
case UT_ARTILLERY:
|
||||
fill_rect(sx-SI(13), sy-SI(5), SI(26), SI(12), ok, og, ob);
|
||||
|
|
@ -158,6 +182,8 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
fill_rect(sx-SI(10), sy-SI(5), SI(20), SI(10), 200, 170, 90);
|
||||
disc(LX(8,23), LY(8,23), SI(4), mr, mg, mb);
|
||||
disc(LX(22,23), LY(22,23), SI(4), mr, mg, mb);
|
||||
tyre_mark(LX(8,23), LY(8,23), SI(4), ph, 1);
|
||||
tyre_mark(LX(22,23), LY(22,23), SI(4), ph, 1);
|
||||
line(LX(5,7), LY(5,7), LX(5,2), LY(5,2), lr, lg, lb);
|
||||
break;
|
||||
case UT_JEEP:
|
||||
|
|
@ -165,6 +191,8 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
fill_rect(sx-SI(9), sy-SI(4), SI(18), SI(8), br, bg, bb);
|
||||
disc(LX(9,22), LY(9,22), SI(4), mr, mg, mb);
|
||||
disc(LX(21,22), LY(21,22), SI(4), mr, mg, mb);
|
||||
tyre_mark(LX(9,22), LY(9,22), SI(4), ph, 1);
|
||||
tyre_mark(LX(21,22), LY(21,22), SI(4), ph, 1);
|
||||
line(LX(15,11), LY(15,11), LX(15,3), LY(15,3), lr, lg, lb);
|
||||
line(sx, sy, LX(28,15), LY(28,15), 50, 45, 35);
|
||||
break;
|
||||
|
|
@ -181,6 +209,10 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
disc(LX(14,22), LY(14,22), SI(3), mr, mg, mb);
|
||||
disc(LX(19,21), LY(19,21), SI(3), mr, mg, mb);
|
||||
disc(LX(23,22), LY(23,22), SI(3), mr, mg, mb);
|
||||
tyre_mark(LX(9,21), LY(9,21), SI(3), ph, 1);
|
||||
tyre_mark(LX(14,22), LY(14,22), SI(3), ph, 1);
|
||||
tyre_mark(LX(19,21), LY(19,21), SI(3), ph, 1);
|
||||
tyre_mark(LX(23,22), LY(23,22), SI(3), ph, 1);
|
||||
disc(LX(23,12), LY(23,12), SI(5), lr, lg, lb);
|
||||
break;
|
||||
case UT_RAVAGER:
|
||||
|
|
@ -190,6 +222,8 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
line(sx, sy, LX(29,15), LY(29,15), 50, 45, 35);
|
||||
disc(LX(7,23), LY(7,23), SI(4), mr, mg, mb);
|
||||
disc(LX(23,23), LY(23,23), SI(4), mr, mg, mb);
|
||||
tyre_mark(LX(7,23), LY(7,23), SI(4), ph, 0);
|
||||
tyre_mark(LX(23,23), LY(23,23), SI(4), ph, 0);
|
||||
break;
|
||||
case UT_FLAME:
|
||||
fill_rect(sx-SI(10), sy-SI(4), SI(20), SI(15), ok, og, ob);
|
||||
|
|
@ -202,6 +236,8 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
fill_rect(sx-SI(9), sy-SI(2), SI(18), SI(10), br, bg, bb);
|
||||
disc(LX(9,23), LY(9,23), SI(4), mr, mg, mb);
|
||||
disc(LX(21,23), LY(21,23), SI(4), mr, mg, mb);
|
||||
tyre_mark(LX(9,23), LY(9,23), SI(4), ph, 1);
|
||||
tyre_mark(LX(21,23), LY(21,23), SI(4), ph, 1);
|
||||
line(sx, sy, LX(28,6), LY(28,6), 255, 80, 60);
|
||||
break;
|
||||
case UT_MEDIC:
|
||||
|
|
@ -209,6 +245,8 @@ static void draw_unit(Unit *u, int sx, int sy) {
|
|||
fill_rect(sx-SI(8), sy-SI(3), SI(16), SI(11), 245, 245, 245);
|
||||
disc(LX(10,24), LY(10,24), SI(4), mr, mg, mb);
|
||||
disc(LX(20,24), LY(20,24), SI(4), mr, mg, mb);
|
||||
tyre_mark(LX(10,24), LY(10,24), SI(4), ph, 1);
|
||||
tyre_mark(LX(20,24), LY(20,24), SI(4), ph, 1);
|
||||
disc(LX(15,9), LY(15,9), SI(5), 240, 50, 50);
|
||||
fill_rect(LX(14,6)-1, LY(14,6)-SI(4), SI(3), SI(8), 255, 255, 255);
|
||||
fill_rect(LX(11,8)-SI(4), LY(11,8)-1, SI(8), SI(3), 255, 255, 255);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,23 @@
|
|||
|
||||
static int unit_alloc_id(Game *g) { return g->unit_next_id++; }
|
||||
|
||||
/* Wheeled / tracked chassis: Unit.anim is continuous tyre phase (rad), not a pulse. */
|
||||
static int unit_wheeled(UnitType t) {
|
||||
return t == UT_BUGGY || t == UT_JEEP || t == UT_HARVESTER
|
||||
|| t == UT_BEAST || t == UT_MISSILE || t == UT_MEDIC;
|
||||
}
|
||||
static int unit_tracked(UnitType t) {
|
||||
return t == UT_TANK || t == UT_RAVAGER;
|
||||
}
|
||||
static int unit_rolling(UnitType t) {
|
||||
return unit_wheeled(t) || unit_tracked(t);
|
||||
}
|
||||
static void unit_roll_phase(Unit *u, float sp) {
|
||||
/* ~1 revolution per ~40 world px */
|
||||
u->anim = fmodf(u->anim + (sp / 40.0f) * (float)(2.0 * M_PI), (float)(2.0 * M_PI));
|
||||
if (u->anim < 0.0f) u->anim += (float)(2.0 * M_PI);
|
||||
}
|
||||
|
||||
Unit *unit_by_id(Game *g, int id) {
|
||||
for (int i = 0; i < g->unit_count; i++)
|
||||
if (!g->units[i].dead && g->units[i].id == id)
|
||||
|
|
@ -336,7 +353,8 @@ static void unit_combat_step(Game *g, Unit *u, float dt) {
|
|||
particle_burst(g, mx, my, 3, 1, 255, 160, 50);
|
||||
u->atk_cd = ((u->type == UT_ARTILLERY) ? 2.2f
|
||||
: (u->type == UT_INFANTRY ? 0.8f : 1.0f)) / u->reload_mul;
|
||||
u->anim = 1.0f;
|
||||
/* rolling chassis keep continuous tyre phase — no fire pulse */
|
||||
if (!unit_rolling(u->type)) u->anim = 1.0f;
|
||||
audio_sfx(1);
|
||||
}
|
||||
return;
|
||||
|
|
@ -405,7 +423,7 @@ static void unit_harvester_step(Game *g, Unit *u, float dt) {
|
|||
int add = (d->cargo - u->cargo > take) ? take : (int)(d->cargo - u->cargo);
|
||||
u->cargo += add;
|
||||
map_deplete_scrap(&g->map, tx, ty, add);
|
||||
u->anim = 1.0f;
|
||||
if (!unit_rolling(u->type)) u->anim = 1.0f;
|
||||
}
|
||||
if (u->cargo >= d->cargo) {
|
||||
int rid = harvester_find_refinery(g, u);
|
||||
|
|
@ -505,7 +523,8 @@ void unit_update(Game *g, float dt) {
|
|||
for (int i = 0; i < g->unit_count; i++) {
|
||||
Unit *u = &g->units[i];
|
||||
if (u->dead) continue;
|
||||
if (u->anim > 0) u->anim -= dt * 3;
|
||||
/* infantry/pulse anim decays; wheeled/tracked keep phase radians */
|
||||
if (!unit_rolling(u->type) && u->anim > 0) u->anim -= dt * 3;
|
||||
if (u->repath_timer > 0) u->repath_timer -= dt;
|
||||
if (u->ability_cd > 0) u->ability_cd -= dt;
|
||||
|
||||
|
|
@ -576,7 +595,8 @@ void unit_update(Game *g, float dt) {
|
|||
u->heading = (float)atan2(wy - u->y, wx - u->x);
|
||||
u->x += (wx - u->x) / d * sp;
|
||||
u->y += (wy - u->y) / d * sp;
|
||||
u->anim = 1.0f;
|
||||
if (unit_rolling(u->type)) unit_roll_phase(u, sp);
|
||||
else u->anim = 1.0f;
|
||||
}
|
||||
}
|
||||
} else if (u->state == STATE_MOVING) {
|
||||
|
|
@ -585,8 +605,11 @@ void unit_update(Game *g, float dt) {
|
|||
if (d < 4) { u->state = STATE_IDLE; }
|
||||
else {
|
||||
float sp = u->speed * dt;
|
||||
u->heading = (float)atan2(u->dest_y - u->y, u->dest_x - u->x);
|
||||
u->x += (u->dest_x - u->x)/d * sp;
|
||||
u->y += (u->dest_y - u->y)/d * sp;
|
||||
if (unit_rolling(u->type)) unit_roll_phase(u, sp);
|
||||
else u->anim = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue