Add pixel art sprites for charger, spawner, and laser turret
Replace colored-rect placeholder rendering with proper 16x16 spritesheet art. Charger: orange armored rhino with horn, eyes, walk cycle (row 7). Spawner: purple hive pod with glowing core and tendrils (row 8). Laser turret: angular metallic housing with red lens that brightens when firing (row 8). All three retain colored-rect fallback when spritesheet is unavailable.
This commit is contained in:
134
src/game/enemy.c
134
src/game/enemy.c
@@ -291,6 +291,8 @@ static void charger_update(Entity *self, float dt, const Tilemap *map) {
|
||||
|
||||
/* Death sequence */
|
||||
if (self->flags & ENTITY_DEAD) {
|
||||
animation_set(&self->anim, &anim_charger_death);
|
||||
animation_update(&self->anim, dt);
|
||||
cd->death_timer -= dt;
|
||||
body->vel.x = 0;
|
||||
if (cd->death_timer <= 0) {
|
||||
@@ -394,43 +396,63 @@ static void charger_update(Entity *self, float dt, const Tilemap *map) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation — use grunt anims as placeholder */
|
||||
if (cd->state == CHARGER_CHARGE) {
|
||||
animation_set(&self->anim, &anim_grunt_walk);
|
||||
/* Animation */
|
||||
if (cd->state == CHARGER_CHARGE || cd->state == CHARGER_PATROL) {
|
||||
animation_set(&self->anim, &anim_charger_walk);
|
||||
} else {
|
||||
animation_set(&self->anim, &anim_grunt_idle);
|
||||
animation_set(&self->anim, &anim_charger_idle);
|
||||
}
|
||||
animation_update(&self->anim, dt);
|
||||
}
|
||||
|
||||
static void charger_render(Entity *self, const Camera *cam) {
|
||||
(void)cam;
|
||||
Body *body = &self->body;
|
||||
ChargerData *cd = (ChargerData *)self->data;
|
||||
|
||||
/* Colored rect fallback — orange/amber color scheme */
|
||||
SDL_Color color;
|
||||
if (cd && cd->state == CHARGER_ALERT) {
|
||||
/* Flash during telegraph */
|
||||
float blink = sinf(cd->state_timer * 30.0f);
|
||||
uint8_t r = (blink > 0) ? 255 : 200;
|
||||
color = (SDL_Color){r, 160, 40, 255};
|
||||
} else if (cd && cd->state == CHARGER_STUNNED) {
|
||||
color = (SDL_Color){160, 160, 100, 255};
|
||||
} else if (cd && cd->state == CHARGER_CHARGE) {
|
||||
color = (SDL_Color){255, 120, 30, 255};
|
||||
} else {
|
||||
color = (SDL_Color){220, 140, 40, 255};
|
||||
}
|
||||
renderer_draw_rect(body->pos, body->size, color, LAYER_ENTITIES, cam);
|
||||
if (g_spritesheet && self->anim.def) {
|
||||
SDL_Rect src = animation_current_rect(&self->anim);
|
||||
|
||||
/* Direction indicator: small triangle in facing direction */
|
||||
float cx = body->pos.x + body->size.x * 0.5f;
|
||||
float cy = body->pos.y + 2.0f;
|
||||
bool left = (self->flags & ENTITY_FACING_LEFT) != 0;
|
||||
float arrow_x = left ? body->pos.x - 3.0f : body->pos.x + body->size.x + 1.0f;
|
||||
renderer_draw_rect(vec2(arrow_x, cy), vec2(2, 3),
|
||||
(SDL_Color){255, 200, 60, 255}, LAYER_ENTITIES, cam);
|
||||
(void)cx;
|
||||
/* Center the 16x16 sprite over the 14x16 hitbox */
|
||||
Vec2 render_pos = vec2(
|
||||
body->pos.x - 1.0f,
|
||||
body->pos.y
|
||||
);
|
||||
|
||||
/* Flash white during alert telegraph */
|
||||
uint8_t alpha = 255;
|
||||
if (cd && cd->state == CHARGER_ALERT) {
|
||||
float blink = sinf(cd->state_timer * 30.0f);
|
||||
alpha = (blink > 0) ? 180 : 255;
|
||||
}
|
||||
|
||||
Sprite spr = {
|
||||
.texture = g_spritesheet,
|
||||
.src = src,
|
||||
.pos = render_pos,
|
||||
.size = vec2(SPRITE_CELL, SPRITE_CELL),
|
||||
.flip_x = (self->flags & ENTITY_FACING_LEFT) != 0,
|
||||
.flip_y = false,
|
||||
.layer = LAYER_ENTITIES,
|
||||
.alpha = alpha,
|
||||
};
|
||||
renderer_submit(&spr);
|
||||
} else {
|
||||
/* Colored rect fallback */
|
||||
SDL_Color color;
|
||||
if (cd && cd->state == CHARGER_ALERT) {
|
||||
float blink = sinf(cd->state_timer * 30.0f);
|
||||
uint8_t r = (blink > 0) ? 255 : 200;
|
||||
color = (SDL_Color){r, 160, 40, 255};
|
||||
} else if (cd && cd->state == CHARGER_STUNNED) {
|
||||
color = (SDL_Color){160, 160, 100, 255};
|
||||
} else if (cd && cd->state == CHARGER_CHARGE) {
|
||||
color = (SDL_Color){255, 120, 30, 255};
|
||||
} else {
|
||||
color = (SDL_Color){220, 140, 40, 255};
|
||||
}
|
||||
renderer_draw_rect(body->pos, body->size, color, LAYER_ENTITIES, cam);
|
||||
}
|
||||
}
|
||||
|
||||
static void charger_destroy(Entity *self) {
|
||||
@@ -494,6 +516,8 @@ static void spawner_update(Entity *self, float dt, const Tilemap *map) {
|
||||
|
||||
/* Death sequence */
|
||||
if (self->flags & ENTITY_DEAD) {
|
||||
animation_set(&self->anim, &anim_spawner_death);
|
||||
animation_update(&self->anim, dt);
|
||||
sd->death_timer -= dt;
|
||||
if (sd->death_timer <= 0) {
|
||||
particle_emit_death_puff(self->body.pos, (SDL_Color){180, 60, 180, 255});
|
||||
@@ -511,6 +535,10 @@ static void spawner_update(Entity *self, float dt, const Tilemap *map) {
|
||||
sd->pulse_timer = 0;
|
||||
}
|
||||
|
||||
/* Animation */
|
||||
animation_set(&self->anim, &anim_spawner_idle);
|
||||
animation_update(&self->anim, dt);
|
||||
|
||||
/* Spawn a grunt when timer expires */
|
||||
if (sd->spawn_timer <= 0) {
|
||||
sd->spawn_timer = SPAWNER_INTERVAL;
|
||||
@@ -530,26 +558,46 @@ static void spawner_update(Entity *self, float dt, const Tilemap *map) {
|
||||
}
|
||||
|
||||
static void spawner_render(Entity *self, const Camera *cam) {
|
||||
(void)cam;
|
||||
Body *body = &self->body;
|
||||
SpawnerData *sd = (SpawnerData *)self->data;
|
||||
|
||||
/* Pulsing purple color when about to spawn */
|
||||
SDL_Color color;
|
||||
if (sd && sd->pulse_timer > 0) {
|
||||
float pulse = sinf(sd->pulse_timer * 12.0f) * 0.5f + 0.5f;
|
||||
uint8_t r = (uint8_t)(140 + 80 * pulse);
|
||||
uint8_t b = (uint8_t)(180 + 60 * pulse);
|
||||
color = (SDL_Color){r, 50, b, 255};
|
||||
} else {
|
||||
color = (SDL_Color){140, 50, 160, 255};
|
||||
}
|
||||
renderer_draw_rect(body->pos, body->size, color, LAYER_ENTITIES, cam);
|
||||
if (g_spritesheet && self->anim.def) {
|
||||
SDL_Rect src = animation_current_rect(&self->anim);
|
||||
|
||||
/* Small inner dot to distinguish from other hazards */
|
||||
float cx = body->pos.x + body->size.x * 0.5f - 2.0f;
|
||||
float cy = body->pos.y + body->size.y * 0.5f - 2.0f;
|
||||
SDL_Color dot = {255, 200, 255, 255};
|
||||
renderer_draw_rect(vec2(cx, cy), vec2(4, 4), dot, LAYER_ENTITIES, cam);
|
||||
Vec2 render_pos = vec2(body->pos.x, body->pos.y);
|
||||
|
||||
/* Pulse brightness when about to spawn */
|
||||
uint8_t alpha = 255;
|
||||
if (sd && sd->pulse_timer > 0) {
|
||||
float pulse = sinf(sd->pulse_timer * 12.0f);
|
||||
alpha = (pulse > 0) ? 200 : 255;
|
||||
}
|
||||
|
||||
Sprite spr = {
|
||||
.texture = g_spritesheet,
|
||||
.src = src,
|
||||
.pos = render_pos,
|
||||
.size = vec2(SPRITE_CELL, SPRITE_CELL),
|
||||
.flip_x = false,
|
||||
.flip_y = false,
|
||||
.layer = LAYER_ENTITIES,
|
||||
.alpha = alpha,
|
||||
};
|
||||
renderer_submit(&spr);
|
||||
} else {
|
||||
/* Colored rect fallback */
|
||||
SDL_Color color;
|
||||
if (sd && sd->pulse_timer > 0) {
|
||||
float pulse = sinf(sd->pulse_timer * 12.0f) * 0.5f + 0.5f;
|
||||
uint8_t r = (uint8_t)(140 + 80 * pulse);
|
||||
uint8_t b = (uint8_t)(180 + 60 * pulse);
|
||||
color = (SDL_Color){r, 50, b, 255};
|
||||
} else {
|
||||
color = (SDL_Color){140, 50, 160, 255};
|
||||
}
|
||||
renderer_draw_rect(body->pos, body->size, color, LAYER_ENTITIES, cam);
|
||||
}
|
||||
}
|
||||
|
||||
static void spawner_destroy(Entity *self) {
|
||||
|
||||
@@ -199,6 +199,14 @@ static void laser_turret_update(Entity *self, float dt, const Tilemap *map) {
|
||||
(SDL_Color){255, 100, 50, 255});
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation */
|
||||
if (ld->state == LASER_CHARGING || ld->state == LASER_FIRING) {
|
||||
animation_set(&self->anim, &anim_laser_turret_fire);
|
||||
} else {
|
||||
animation_set(&self->anim, &anim_laser_turret_idle);
|
||||
}
|
||||
animation_update(&self->anim, dt);
|
||||
}
|
||||
|
||||
/* ── Render ──────────────────────────────────────── */
|
||||
@@ -281,24 +289,47 @@ static void laser_turret_render(Entity *self, const Camera *cam) {
|
||||
(int)(3.0f * fade), beam_col);
|
||||
}
|
||||
|
||||
/* Draw turret body — colored rect fallback (no sprite yet). */
|
||||
SDL_Color base_col;
|
||||
if (ld->state == LASER_FIRING) {
|
||||
base_col = (SDL_Color){200, 80, 50, 255};
|
||||
} else if (ld->state == LASER_CHARGING) {
|
||||
base_col = (SDL_Color){180, 100, 60, 255};
|
||||
} else {
|
||||
base_col = (SDL_Color){140, 100, 80, 255};
|
||||
}
|
||||
renderer_draw_rect(body->pos, body->size, base_col, LAYER_ENTITIES, cam);
|
||||
/* Draw turret body */
|
||||
if (g_spritesheet && self->anim.def) {
|
||||
SDL_Rect src = animation_current_rect(&self->anim);
|
||||
|
||||
/* Small dot indicating aim direction */
|
||||
float dot_dist = 10.0f;
|
||||
float dot_x = cx + cosf(ld->aim_angle) * dot_dist - 1.0f;
|
||||
float dot_y = cy + sinf(ld->aim_angle) * dot_dist - 1.0f;
|
||||
SDL_Color dot_col = {255, 50, 30, 255};
|
||||
renderer_draw_rect(vec2(dot_x, dot_y), vec2(2, 2), dot_col,
|
||||
LAYER_ENTITIES, cam);
|
||||
/* Center the 16x16 sprite over the 14x14 hitbox */
|
||||
Vec2 render_pos = vec2(
|
||||
body->pos.x - 1.0f,
|
||||
body->pos.y - 1.0f
|
||||
);
|
||||
|
||||
Sprite spr = {
|
||||
.texture = g_spritesheet,
|
||||
.src = src,
|
||||
.pos = render_pos,
|
||||
.size = vec2(SPRITE_CELL, SPRITE_CELL),
|
||||
.flip_x = (self->flags & ENTITY_FACING_LEFT) != 0,
|
||||
.flip_y = false,
|
||||
.layer = LAYER_ENTITIES,
|
||||
.alpha = 255,
|
||||
};
|
||||
renderer_submit(&spr);
|
||||
} else {
|
||||
/* Colored rect fallback */
|
||||
SDL_Color base_col;
|
||||
if (ld->state == LASER_FIRING) {
|
||||
base_col = (SDL_Color){200, 80, 50, 255};
|
||||
} else if (ld->state == LASER_CHARGING) {
|
||||
base_col = (SDL_Color){180, 100, 60, 255};
|
||||
} else {
|
||||
base_col = (SDL_Color){140, 100, 80, 255};
|
||||
}
|
||||
renderer_draw_rect(body->pos, body->size, base_col, LAYER_ENTITIES, cam);
|
||||
|
||||
/* Small dot indicating aim direction (only needed for fallback) */
|
||||
float dot_dist = 10.0f;
|
||||
float dot_x = cx + cosf(ld->aim_angle) * dot_dist - 1.0f;
|
||||
float dot_y = cy + sinf(ld->aim_angle) * dot_dist - 1.0f;
|
||||
SDL_Color dot_col = {255, 50, 30, 255};
|
||||
renderer_draw_rect(vec2(dot_x, dot_y), vec2(2, 2), dot_col,
|
||||
LAYER_ENTITIES, cam);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Destroy ─────────────────────────────────────── */
|
||||
|
||||
@@ -993,6 +993,233 @@ static const uint32_t asteroid2[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
};
|
||||
|
||||
/* ── Charger enemy sprites ──────────────────────────── */
|
||||
/* Charger: Orange armored rhino-like ground charger. 14x16 hitbox.
|
||||
* Stocky body, forward horn, angry eyes, stubby legs. */
|
||||
|
||||
#define CHG 0xd98a30FF /* charger orange */
|
||||
#define CHD 0xa86620FF /* charger dark */
|
||||
#define CHL 0xf0b050FF /* charger light */
|
||||
#define CHK 0x7a4a14FF /* charger darkest (outline) */
|
||||
|
||||
static const uint32_t charger_idle1[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, CHK, T, T, T, T, T, CHK, CHK, CHK, T, T, T, T,
|
||||
T, T, CHK, YLW, CHK, T, T, T, CHK, CHL, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, CHK, CHK, CHK, CHK, CHK, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, WHT, BLK, CHG, CHG, WHT, BLK, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, T, CHK, CHG, CHG, CHD, CHD, CHG, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, T, CHK, CHD, CHG, CHG, CHG, CHG, CHD, CHK, T, T, T, T,
|
||||
T, T, T, T, T, CHK, CHD, CHG, CHG, CHD, CHK, T, T, T, T, T,
|
||||
T, T, T, T, CHK, CHK, T, T, T, T, CHK, CHK, T, T, T, T,
|
||||
T, T, T, T, CHK, CHD, T, T, T, T, CHD, CHK, T, T, T, T,
|
||||
T, T, T, T, CHK, CHK, T, T, T, T, CHK, CHK, T, T, T, T,
|
||||
};
|
||||
|
||||
static const uint32_t charger_idle2[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, CHK, T, T, T, T, T, CHK, CHK, CHK, T, T, T, T,
|
||||
T, T, CHK, YLW, CHK, T, T, T, CHK, CHL, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, CHK, CHK, CHK, CHK, CHK, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, WHT, BLK, CHG, CHG, WHT, BLK, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, T, CHK, CHG, CHG, CHD, CHD, CHG, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, T, CHK, CHD, CHG, CHG, CHG, CHG, CHD, CHK, T, T, T, T,
|
||||
T, T, T, T, T, CHK, CHK, T, T, CHK, CHK, T, T, T, T, T,
|
||||
T, T, T, T, T, CHD, CHK, T, T, CHK, CHD, T, T, T, T, T,
|
||||
T, T, T, T, T, CHK, CHK, T, T, CHK, CHK, T, T, T, T, T,
|
||||
};
|
||||
|
||||
/* Charger walk frames — legs alternate */
|
||||
static const uint32_t charger_walk1[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, CHK, T, T, T, T, T, CHK, CHK, CHK, T, T, T, T,
|
||||
T, T, CHK, YLW, CHK, T, T, T, CHK, CHL, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, CHK, CHK, CHK, CHK, CHK, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, WHT, BLK, CHG, CHG, WHT, BLK, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, T, CHK, CHG, CHG, CHD, CHD, CHG, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, T, CHK, CHD, CHG, CHG, CHG, CHG, CHD, CHK, T, T, T, T,
|
||||
T, T, T, T, T, CHK, CHD, CHG, CHG, CHD, CHK, T, T, T, T, T,
|
||||
T, T, T, T, T, CHK, T, T, T, CHK, T, T, T, T, T, T,
|
||||
T, T, T, T, CHK, T, T, T, T, T, CHK, T, T, T, T, T,
|
||||
T, T, T, T, CHK, T, T, T, T, T, CHK, T, T, T, T, T,
|
||||
};
|
||||
|
||||
static const uint32_t charger_walk2[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, CHK, T, T, T, T, T, CHK, CHK, CHK, T, T, T, T,
|
||||
T, T, CHK, YLW, CHK, T, T, T, CHK, CHL, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, CHK, CHK, CHK, CHK, CHK, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, WHT, BLK, CHG, CHG, WHT, BLK, CHG, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, T, T, CHK, CHG, CHG, CHD, CHD, CHG, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T, T,
|
||||
T, T, T, T, CHK, CHD, CHG, CHG, CHG, CHG, CHD, CHK, T, T, T, T,
|
||||
T, T, T, T, T, CHK, CHD, CHG, CHG, CHD, CHK, T, T, T, T, T,
|
||||
T, T, T, T, CHK, T, T, T, T, T, CHK, T, T, T, T, T,
|
||||
T, T, T, T, T, CHK, T, T, T, CHK, T, T, T, T, T, T,
|
||||
T, T, T, T, T, CHK, T, T, T, CHK, T, T, T, T, T, T,
|
||||
};
|
||||
|
||||
/* Charger death — flattened, X eyes */
|
||||
static const uint32_t charger_death1[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, CHK, CHK, CHK, CHK, CHK, CHK, CHK, CHK, CHK, CHK, CHK, CHK, T, T,
|
||||
T, T, CHK, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, CHK, CHG, BLK, CHG, BLK, CHG, BLK, CHG, BLK, CHG, CHG, CHK, T, T,
|
||||
T, T, CHK, CHG, CHG, BLK, CHG, CHG, CHG, BLK, CHG, CHG, CHG, CHK, T, T,
|
||||
T, T, CHK, CHD, CHG, CHG, CHD, CHD, CHD, CHG, CHG, CHD, CHG, CHK, T, T,
|
||||
T, T, T, CHK, CHK, CHK, CHK, CHK, CHK, CHK, CHK, CHK, CHK, T, T, T,
|
||||
};
|
||||
|
||||
/* ── Spawner enemy sprites ─────────────────────────── */
|
||||
/* Spawner: Purple alien hive pod. 16x16 hitbox.
|
||||
* Organic, bulbous body with glowing core and tendrils at base. */
|
||||
|
||||
#define SPW 0xaa44ccFF /* spawner purple */
|
||||
#define SPD 0x7b1fa2FF /* spawner dark purple */
|
||||
#define SPL 0xce93d8FF /* spawner light purple */
|
||||
#define SPK 0x4a1066FF /* spawner outline */
|
||||
|
||||
static const uint32_t spawner_idle1[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, SPK, SPK, SPK, SPK, T, T, T, T, T, T,
|
||||
T, T, T, T, T, SPK, SPW, SPW, SPW, SPW, SPK, T, T, T, T, T,
|
||||
T, T, T, T, SPK, SPW, SPW, SPL, SPL, SPW, SPW, SPK, T, T, T, T,
|
||||
T, T, T, SPK, SPW, SPW, SPL, PRL, PRL, SPL, SPW, SPW, SPK, T, T, T,
|
||||
T, T, T, SPK, SPW, SPL, PRL, WHT, WHT, PRL, SPL, SPW, SPK, T, T, T,
|
||||
T, T, SPK, SPW, SPW, SPL, PRL, WHT, WHT, PRL, SPL, SPW, SPW, SPK, T, T,
|
||||
T, T, SPK, SPW, SPW, SPL, PRL, WHT, WHT, PRL, SPL, SPW, SPW, SPK, T, T,
|
||||
T, T, T, SPK, SPW, SPW, SPL, PRL, PRL, SPL, SPW, SPW, SPK, T, T, T,
|
||||
T, T, T, SPK, SPW, SPW, SPW, SPD, SPD, SPW, SPW, SPW, SPK, T, T, T,
|
||||
T, T, T, T, SPK, SPD, SPW, SPW, SPW, SPW, SPD, SPK, T, T, T, T,
|
||||
T, T, T, T, SPK, SPK, SPD, SPD, SPD, SPD, SPK, SPK, T, T, T, T,
|
||||
T, T, T, SPK, SPD, T, SPK, T, T, SPK, T, SPD, SPK, T, T, T,
|
||||
T, T, SPK, SPD, T, T, T, T, T, T, T, T, SPD, SPK, T, T,
|
||||
T, T, SPK, T, T, T, T, T, T, T, T, T, T, SPK, T, T,
|
||||
};
|
||||
|
||||
/* Spawner idle frame 2 — core pulses brighter */
|
||||
static const uint32_t spawner_idle2[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, SPK, SPK, SPK, SPK, T, T, T, T, T, T,
|
||||
T, T, T, T, T, SPK, SPW, SPW, SPW, SPW, SPK, T, T, T, T, T,
|
||||
T, T, T, T, SPK, SPW, SPL, SPL, SPL, SPL, SPW, SPK, T, T, T, T,
|
||||
T, T, T, SPK, SPW, SPL, PRL, WHT, WHT, PRL, SPL, SPW, SPK, T, T, T,
|
||||
T, T, T, SPK, SPW, PRL, WHT, WHT, WHT, WHT, PRL, SPW, SPK, T, T, T,
|
||||
T, T, SPK, SPW, SPL, PRL, WHT, WHT, WHT, WHT, PRL, SPL, SPW, SPK, T, T,
|
||||
T, T, SPK, SPW, SPL, PRL, WHT, WHT, WHT, WHT, PRL, SPL, SPW, SPK, T, T,
|
||||
T, T, T, SPK, SPW, SPL, PRL, WHT, WHT, PRL, SPL, SPW, SPK, T, T, T,
|
||||
T, T, T, SPK, SPW, SPW, SPL, SPD, SPD, SPL, SPW, SPW, SPK, T, T, T,
|
||||
T, T, T, T, SPK, SPD, SPW, SPW, SPW, SPW, SPD, SPK, T, T, T, T,
|
||||
T, T, T, T, SPK, SPK, SPD, SPD, SPD, SPD, SPK, SPK, T, T, T, T,
|
||||
T, T, T, SPK, SPD, T, SPK, T, T, SPK, T, SPD, SPK, T, T, T,
|
||||
T, T, SPK, SPD, T, T, T, T, T, T, T, T, SPD, SPK, T, T,
|
||||
T, T, SPK, T, T, T, T, T, T, T, T, T, T, SPK, T, T,
|
||||
};
|
||||
|
||||
/* Spawner death — cracked open, dark */
|
||||
static const uint32_t spawner_death1[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, SPK, T, T, T, T, SPK, T, T, T, T, T,
|
||||
T, T, T, T, SPK, SPD, SPK, T, T, SPK, SPD, SPK, T, T, T, T,
|
||||
T, T, T, SPK, SPD, SPW, SPD, SPK, SPK, SPD, SPW, SPD, SPK, T, T, T,
|
||||
T, T, SPK, SPD, SPW, SPW, SPW, SPD, SPD, SPW, SPW, SPW, SPD, SPK, T, T,
|
||||
T, T, SPK, SPD, SPW, SPD, SPK, BLK, BLK, SPK, SPD, SPW, SPD, SPK, T, T,
|
||||
T, T, T, SPK, SPD, SPD, SPK, SPK, SPK, SPK, SPD, SPD, SPK, T, T, T,
|
||||
T, T, T, T, SPK, SPK, T, T, T, T, SPK, SPK, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
};
|
||||
|
||||
/* ── Laser turret sprites ──────────────────────────── */
|
||||
/* Laser turret: Angular metallic housing with red lens. 14x14 hitbox.
|
||||
* Wall-mounted feel, darker/more angular than regular turret. */
|
||||
|
||||
#define LTG 0x707070FF /* laser turret grey */
|
||||
#define LTD 0x484848FF /* laser turret dark */
|
||||
#define LTL 0x989898FF /* laser turret light */
|
||||
#define LTK 0x303030FF /* laser turret outline */
|
||||
#define LTR 0xcc3020FF /* laser turret red lens */
|
||||
#define LRD 0x881818FF /* laser turret red dark */
|
||||
#define LRL 0xff5040FF /* laser turret red light */
|
||||
|
||||
/* Laser turret idle — angular housing, dim red lens */
|
||||
static const uint32_t laser_idle1[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, LTK, LTK, LTK, LTK, LTK, LTK, LTK, LTK, T, T, T, T,
|
||||
T, T, T, LTK, LTL, LTL, LTG, LTG, LTG, LTG, LTL, LTL, LTK, T, T, T,
|
||||
T, T, T, LTK, LTL, LTG, LTG, LTG, LTG, LTG, LTG, LTL, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LTG, LTD, LTD, LTD, LTD, LTG, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LTD, LRD, LTR, LTR, LRD, LTD, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LTD, LTR, LRD, LRD, LTR, LTD, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LTD, LTR, LRD, LRD, LTR, LTD, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LTD, LRD, LTR, LTR, LRD, LTD, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LTG, LTD, LTD, LTD, LTD, LTG, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTL, LTG, LTG, LTG, LTG, LTG, LTG, LTL, LTK, T, T, T,
|
||||
T, T, T, LTK, LTL, LTL, LTG, LTG, LTG, LTG, LTL, LTL, LTK, T, T, T,
|
||||
T, T, T, T, LTK, LTK, LTK, LTK, LTK, LTK, LTK, LTK, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
};
|
||||
|
||||
/* Laser turret firing — lens glows bright, ring highlight */
|
||||
static const uint32_t laser_fire1[16*16] = {
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, LTK, LTK, LTK, LTK, LTK, LTK, LTK, LTK, T, T, T, T,
|
||||
T, T, T, LTK, LTL, LTL, LTG, LTG, LTG, LTG, LTL, LTL, LTK, T, T, T,
|
||||
T, T, T, LTK, LTL, LTG, LTG, LTG, LTG, LTG, LTG, LTL, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LTG, LRL, LRL, LRL, LRL, LTG, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LRL, LTR, WHT, WHT, LTR, LRL, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LRL, WHT, WHT, WHT, WHT, LRL, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LRL, WHT, WHT, WHT, WHT, LRL, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LRL, LTR, WHT, WHT, LTR, LRL, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTG, LTG, LRL, LRL, LRL, LRL, LTG, LTG, LTK, T, T, T,
|
||||
T, T, T, LTK, LTL, LTG, LTG, LTG, LTG, LTG, LTG, LTL, LTK, T, T, T,
|
||||
T, T, T, LTK, LTL, LTL, LTG, LTG, LTG, LTG, LTL, LTL, LTK, T, T, T,
|
||||
T, T, T, T, LTK, LTK, LTK, LTK, LTK, LTK, LTK, LTK, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,
|
||||
};
|
||||
|
||||
|
||||
/* ── Spritesheet generation ────────────────────────── */
|
||||
|
||||
/* All sprite definitions for the sheet - row, column, pixel data */
|
||||
@@ -1068,10 +1295,26 @@ static const SpriteDef s_sprite_defs[] = {
|
||||
{6, 5, asteroid2},
|
||||
{6, 6, powerup_fuel1},
|
||||
{6, 7, powerup_fuel2},
|
||||
|
||||
/* Row 7: Charger */
|
||||
{7, 0, charger_idle1},
|
||||
{7, 1, charger_idle2},
|
||||
{7, 2, charger_walk1},
|
||||
{7, 3, charger_walk2},
|
||||
{7, 4, charger_walk1}, /* reuse frame */
|
||||
{7, 5, charger_walk2}, /* reuse frame */
|
||||
{7, 6, charger_death1},
|
||||
|
||||
/* Row 8: Spawner + Laser Turret */
|
||||
{8, 0, spawner_idle1},
|
||||
{8, 1, spawner_idle2},
|
||||
{8, 2, spawner_death1},
|
||||
{8, 3, laser_idle1},
|
||||
{8, 4, laser_fire1},
|
||||
};
|
||||
|
||||
#define SHEET_COLS 8
|
||||
#define SHEET_ROWS 7
|
||||
#define SHEET_ROWS 9
|
||||
|
||||
SDL_Texture *sprites_generate(SDL_Renderer *renderer) {
|
||||
int w = SHEET_COLS * SPRITE_CELL;
|
||||
@@ -1278,6 +1521,42 @@ static AnimFrame s_drone_frames[] = {
|
||||
FRAME(1, 6, 0.2f),
|
||||
};
|
||||
|
||||
/* Charger */
|
||||
static AnimFrame s_charger_idle_frames[] = {
|
||||
FRAME(0, 7, 0.5f),
|
||||
FRAME(1, 7, 0.5f),
|
||||
};
|
||||
|
||||
static AnimFrame s_charger_walk_frames[] = {
|
||||
FRAME(2, 7, 0.12f),
|
||||
FRAME(3, 7, 0.12f),
|
||||
FRAME(4, 7, 0.12f),
|
||||
FRAME(5, 7, 0.12f),
|
||||
};
|
||||
|
||||
static AnimFrame s_charger_death_frames[] = {
|
||||
FRAME(6, 7, 0.3f),
|
||||
};
|
||||
|
||||
/* Spawner */
|
||||
static AnimFrame s_spawner_idle_frames[] = {
|
||||
FRAME(0, 8, 0.6f),
|
||||
FRAME(1, 8, 0.6f),
|
||||
};
|
||||
|
||||
static AnimFrame s_spawner_death_frames[] = {
|
||||
FRAME(2, 8, 0.3f),
|
||||
};
|
||||
|
||||
/* Laser Turret */
|
||||
static AnimFrame s_laser_turret_idle_frames[] = {
|
||||
FRAME(3, 8, 1.0f),
|
||||
};
|
||||
|
||||
static AnimFrame s_laser_turret_fire_frames[] = {
|
||||
FRAME(4, 8, 0.15f),
|
||||
};
|
||||
|
||||
/* Exported animation definitions */
|
||||
AnimDef anim_player_idle;
|
||||
AnimDef anim_player_run;
|
||||
@@ -1313,6 +1592,16 @@ AnimDef anim_asteroid;
|
||||
|
||||
AnimDef anim_drone;
|
||||
|
||||
AnimDef anim_charger_idle;
|
||||
AnimDef anim_charger_walk;
|
||||
AnimDef anim_charger_death;
|
||||
|
||||
AnimDef anim_spawner_idle;
|
||||
AnimDef anim_spawner_death;
|
||||
|
||||
AnimDef anim_laser_turret_idle;
|
||||
AnimDef anim_laser_turret_fire;
|
||||
|
||||
void sprites_init_anims(void) {
|
||||
anim_player_idle = (AnimDef){s_player_idle_frames, 2, true, NULL};
|
||||
anim_player_run = (AnimDef){s_player_run_frames, 4, true, NULL};
|
||||
@@ -1347,4 +1636,14 @@ void sprites_init_anims(void) {
|
||||
anim_asteroid = (AnimDef){s_asteroid_frames, 2, true, NULL};
|
||||
|
||||
anim_drone = (AnimDef){s_drone_frames, 2, true, NULL};
|
||||
|
||||
anim_charger_idle = (AnimDef){s_charger_idle_frames, 2, true, NULL};
|
||||
anim_charger_walk = (AnimDef){s_charger_walk_frames, 4, true, NULL};
|
||||
anim_charger_death = (AnimDef){s_charger_death_frames, 1, false, NULL};
|
||||
|
||||
anim_spawner_idle = (AnimDef){s_spawner_idle_frames, 2, true, NULL};
|
||||
anim_spawner_death = (AnimDef){s_spawner_death_frames, 1, false, NULL};
|
||||
|
||||
anim_laser_turret_idle = (AnimDef){s_laser_turret_idle_frames, 1, true, NULL};
|
||||
anim_laser_turret_fire = (AnimDef){s_laser_turret_fire_frames, 1, false, NULL};
|
||||
}
|
||||
|
||||
@@ -8,10 +8,15 @@
|
||||
* Each sprite cell is 16x16 pixels.
|
||||
* The sheet is organized in rows:
|
||||
*
|
||||
* Row 0: Player idle (2 frames), run (4 frames), jump (1), fall (1)
|
||||
* Row 1: Grunt idle (2 frames), walk (4 frames), death (2 frames)
|
||||
* Row 2: Flyer idle (2 frames), fly (4 frames), death (2 frames)
|
||||
* Row 3: Projectiles: bullet (2 frames), impact (3 frames), enemy bullet (2)
|
||||
* Row 0: Player idle (2), run (4), jump (1), fall (1)
|
||||
* Row 1: Grunt idle (2), walk (4), death (1)
|
||||
* Row 2: Flyer idle (2), fly (4), death (1)
|
||||
* Row 3: Projectiles: bullet (2), impact (3), enemy bullet (2)
|
||||
* Row 4: Turret (2), platform (1), flame vent (3), force field (2)
|
||||
* Row 5: Force field off (1), powerups: health (2), jetpack (2), drone (2)
|
||||
* Row 6: Drone companion (2), gun powerup (2), asteroid (2), fuel (2)
|
||||
* Row 7: Charger idle (2), walk (4), death (1)
|
||||
* Row 8: Spawner idle (2), death (1), laser turret idle (1), fire (1)
|
||||
*/
|
||||
|
||||
#define SPRITE_CELL 16
|
||||
@@ -62,6 +67,19 @@ extern AnimDef anim_asteroid;
|
||||
/* ── Drone animation ───────────────────────────── */
|
||||
extern AnimDef anim_drone;
|
||||
|
||||
/* ── Charger animations ────────────────────────── */
|
||||
extern AnimDef anim_charger_idle;
|
||||
extern AnimDef anim_charger_walk;
|
||||
extern AnimDef anim_charger_death;
|
||||
|
||||
/* ── Spawner animations ────────────────────────── */
|
||||
extern AnimDef anim_spawner_idle;
|
||||
extern AnimDef anim_spawner_death;
|
||||
|
||||
/* ── Laser turret animations ───────────────────── */
|
||||
extern AnimDef anim_laser_turret_idle;
|
||||
extern AnimDef anim_laser_turret_fire;
|
||||
|
||||
/* Initialize all animation definitions */
|
||||
void sprites_init_anims(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user