Fx/API/Particles
Bullet creation and death effects (don't know what is new in detail), improvements on the "API", especially around create_projectile() and extensive use of particles in addtion with generic particle/projectile movement and drawing rules (see projectile.h)
This commit is contained in:
parent
5239e7ec08
commit
c811fa76e7
7 changed files with 121 additions and 78 deletions
|
@ -30,9 +30,9 @@ void create_enemy(Enemy **enemies, EnemyDrawRule draw_rule, EnemyLogicRule logic
|
|||
va_list ap;
|
||||
int i;
|
||||
|
||||
memset(e->args, 0, 4);
|
||||
memset(e->args, 0, RULE_ARGC);
|
||||
va_start(ap, args);
|
||||
for(i = 0; i < 4; i++) {
|
||||
for(i = 0; i < RULE_ARGC; i++) {
|
||||
e->args[i] = args;
|
||||
args = va_arg(ap, complex);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "animation.h"
|
||||
#include <complex.h>
|
||||
#include "projectile.h"
|
||||
|
||||
#undef complex
|
||||
#define complex double _Complex
|
||||
|
@ -42,7 +43,7 @@ typedef struct Enemy {
|
|||
int hp;
|
||||
|
||||
void *parent;
|
||||
complex args[4];
|
||||
complex args[RULE_ARGC];
|
||||
} Enemy;
|
||||
|
||||
#define create_enemyg(drule, lrule, pos, hp, par, args) (create_enemy(&global.enemies, drule, lrule, pos, hp, par, args))
|
||||
|
|
10
src/player.c
10
src/player.c
|
@ -92,14 +92,14 @@ void player_logic(Player* plr) {
|
|||
|
||||
if(plr->fire && plr->cha == Youmu) {
|
||||
if(!(global.frames % 4)) {
|
||||
create_projectile("youmu", plr->pos + 10 - I*20, NULL, linear, -20I)->type = PlrProj;
|
||||
create_projectile("youmu", plr->pos - 10 - I*20, NULL, linear, -20I)->type = PlrProj;
|
||||
create_projectile("youmu", plr->pos + 10 - I*20, NULL, linear, rarg(-20I))->type = PlrProj;
|
||||
create_projectile("youmu", plr->pos - 10 - I*20, NULL, linear, rarg(-20I))->type = PlrProj;
|
||||
|
||||
if(plr->power >= 2) {
|
||||
float a = 0.20;
|
||||
if(plr->focus > 0) a = 0.06;
|
||||
create_projectile("youmu", plr->pos - 10 - I*20, NULL, linear, I*-20*cexp(-I*a))->type = PlrProj;
|
||||
create_projectile("youmu", plr->pos + 10 - I*20, NULL, linear, I*-20*cexp(I*a))->type = PlrProj;
|
||||
create_projectile("youmu", plr->pos - 10 - I*20, NULL, linear, rarg(I*-20*cexp(-I*a)))->type = PlrProj;
|
||||
create_projectile("youmu", plr->pos + 10 - I*20, NULL, linear, rarg(I*-20*cexp(I*a)))->type = PlrProj;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ void player_logic(Player* plr) {
|
|||
ref = add_ref(global.enemies);
|
||||
|
||||
if(ref != -1)
|
||||
create_projectile("hghost", plr->pos, NULL, youmu_homing, a*cexp(I*rand()), ref)->type = PlrProj;
|
||||
create_projectile("hghost", plr->pos, NULL, youmu_homing, rarg(a*cexp(I*rand()), ref))->type = PlrProj;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
void youmu_opposite_draw(Enemy *e, int t) {
|
||||
complex pos = e->pos + ((Player *)e->parent)->pos;
|
||||
|
||||
create_particle("!flare", pos, NULL, Shrink, timeout, (complex)10, -e->pos+10I, 1);
|
||||
create_particle("flare", pos, NULL, Shrink, timeout, rarg(10, -e->pos+10I));
|
||||
}
|
||||
|
||||
void youmu_opposite_logic(Enemy *e, int t) {
|
||||
|
@ -30,13 +30,13 @@ void youmu_opposite_logic(Enemy *e, int t) {
|
|||
}
|
||||
|
||||
if(plr->fire && !(global.frames % 4))
|
||||
create_projectile("youmu", e->pos + plr->pos, NULL, linear, -20*cexp(I*e->args[2]))->type = PlrProj;
|
||||
create_projectile("youmu", e->pos + plr->pos, NULL, linear, rarg(-20*cexp(I*e->args[2])))->type = PlrProj;
|
||||
|
||||
e->pos0 = e->pos + plr->pos;
|
||||
}
|
||||
|
||||
int youmu_homing(Projectile *p, int t) { // a[0]: velocity, a[1]: target, a[2]: old velocity
|
||||
// p->angle = t/30.0;
|
||||
p->angle = rand();
|
||||
if(t == EVENT_DEATH) {
|
||||
free_ref(p->args[1]);
|
||||
}
|
||||
|
|
138
src/projectile.c
138
src/projectile.c
|
@ -26,81 +26,77 @@ inline Color *rgb(float r, float g, float b) {
|
|||
return rgba(r, g, b, 1.0);
|
||||
}
|
||||
|
||||
Projectile *create_particle(char *name, complex pos, Color *clr, ProjDRule draw, ProjRule rule, complex arg1, ...) {
|
||||
complex *rarg(complex arg0, ...) {
|
||||
complex *a = calloc(RULE_ARGC, sizeof(complex));
|
||||
va_list ap;
|
||||
complex a[4];
|
||||
int i;
|
||||
|
||||
memset(a, 0, sizeof(a));
|
||||
|
||||
va_start(ap, arg1);
|
||||
va_start(ap, arg0);
|
||||
|
||||
a[0] = arg1;
|
||||
for(i = 1; i < 4; i++) {
|
||||
a[0] = arg0;
|
||||
for(i = 1; i < RULE_ARGC; i++) {
|
||||
a[i] = (complex)va_arg(ap, complex);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return create_projectile_dv(&global.particles, name, pos, clr, draw, rule, a);
|
||||
return a;
|
||||
}
|
||||
|
||||
Projectile *create_projectile(char *name, complex pos, Color *clr, ProjRule rule, complex arg1, ...) {
|
||||
va_list ap;
|
||||
complex a[4], ar;
|
||||
int i;
|
||||
Projectile *create_particle(char *name, complex pos, Color *clr, ProjDRule draw, ProjRule rule, complex *a) {
|
||||
Projectile *p = create_projectile_p(&global.particles, get_tex(name), pos, clr, draw, rule, a);
|
||||
|
||||
memset(a, 0, sizeof(a));
|
||||
|
||||
va_start(ap, arg1);
|
||||
|
||||
a[0] = arg1;
|
||||
for(i = 1; i < 4; i++) {
|
||||
a[i] = (complex)va_arg(ap, complex);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return create_projectile_dv(&global.projs, name, pos, clr, ProjDraw, rule, a);
|
||||
p->type = Particle;
|
||||
return p;
|
||||
}
|
||||
|
||||
Projectile *create_projectile_dv(Projectile **dest, char *name, complex pos, Color *clr,
|
||||
Projectile *create_projectile(char *name, complex pos, Color *clr, ProjRule rule, complex *a) {
|
||||
char *buf = malloc(strlen(name) + 6);
|
||||
strcpy(buf, "proj/");
|
||||
strcat(buf, name);
|
||||
|
||||
Texture *tex = get_tex(buf);
|
||||
free(buf);
|
||||
|
||||
return create_projectile_p(&global.projs, tex, pos, clr, ProjDraw, rule, a);
|
||||
}
|
||||
|
||||
Projectile *create_projectile_p(Projectile **dest, Texture *tex, complex pos, Color *clr,
|
||||
ProjDRule draw, ProjRule rule, complex *args) {
|
||||
Projectile *p = create_element((void **)dest, sizeof(Projectile));
|
||||
|
||||
char buf[128];
|
||||
if(name[0] == '!')
|
||||
strncpy(buf, name+1, sizeof(buf));
|
||||
else {
|
||||
strcpy(buf, "proj/");
|
||||
strcat(buf, name);
|
||||
}
|
||||
|
||||
p->birthtime = global.frames;
|
||||
p->pos = pos;
|
||||
p->pos0 = pos;
|
||||
p->angle = 0;
|
||||
p->rule = rule;
|
||||
p->draw = draw;
|
||||
p->tex = get_tex(buf);
|
||||
p->tex = tex;
|
||||
p->type = FairyProj;
|
||||
p->clr = clr;
|
||||
p->parent = NULL;
|
||||
|
||||
memcpy(p->args, args, sizeof(p->args));
|
||||
|
||||
memset(p->args, 0, sizeof(p->args));
|
||||
if(args) {
|
||||
memcpy(p->args, args, sizeof(p->args));
|
||||
free(args);
|
||||
}
|
||||
|
||||
if(dest != &global.particles && clr != NULL) {
|
||||
Color *color = rgba(clr->r, clr->g, clr->b, clr->a);
|
||||
|
||||
create_particle(name, pos, color, Shrink, bullet_flare_move, 16, (complex)add_ref(p));
|
||||
create_projectile_p(Pa, tex, pos, color, Shrink, bullet_flare_move, rarg(16, (complex)add_ref(p)));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void _delete_projectile(void **projs, void *proj) {
|
||||
((Projectile *)proj)->rule(proj, EVENT_DEATH);
|
||||
|
||||
if(((Projectile*)proj)->clr)
|
||||
free(((Projectile*)proj)->clr);
|
||||
Projectile *p = proj;
|
||||
p->rule(p, EVENT_DEATH);
|
||||
|
||||
if(p->clr)
|
||||
free(p->clr);
|
||||
del_ref(proj);
|
||||
delete_element(projs, proj);
|
||||
}
|
||||
|
@ -158,15 +154,25 @@ void process_projectiles(Projectile **projs, char collision) {
|
|||
if(proj->type == DeadProj && killed < 2) {
|
||||
killed++;
|
||||
action = ACTION_DESTROY;
|
||||
create_particle("!flare", proj->pos, NULL, Fade, timeout, (complex)40);
|
||||
create_particle("flare", proj->pos, NULL, Fade, timeout, rarg(30));
|
||||
create_item(proj->pos, 0, BPoint)->auto_collect = 10;
|
||||
}
|
||||
|
||||
if(collision)
|
||||
col = collision_projectile(proj);
|
||||
|
||||
if(col == 1 && (global.frames - abs(global.plr.recovery)) >= 0)
|
||||
plr_death(&global.plr);
|
||||
if(col && proj->type != Particle) {
|
||||
Color *clr = NULL;
|
||||
if(proj->clr) {
|
||||
clr = malloc(sizeof(Color));
|
||||
memcpy(clr, proj->clr, sizeof(Color));
|
||||
}
|
||||
create_projectile_p(Pa, proj->tex, proj->pos, clr, DeathShrink, timeout_linear, rarg(15, -20I*cexp(proj->angle)));
|
||||
}
|
||||
|
||||
|
||||
if(col == 1 && global.frames - abs(global.plr.recovery) >= 0)
|
||||
plr_death(&global.plr);
|
||||
|
||||
if(action == ACTION_DESTROY || col
|
||||
|| creal(proj->pos) + proj->tex->w/2 < 0 || creal(proj->pos) - proj->tex->w/2 > VIEWPORT_W
|
||||
|
@ -181,6 +187,7 @@ void process_projectiles(Projectile **projs, char collision) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int linear(Projectile *p, int t) { // sure is physics in here; a[0]: velocity
|
||||
p->angle = carg(p->args[0]);
|
||||
p->pos = p->pos0 + p->args[0]*t;
|
||||
|
@ -188,7 +195,7 @@ int linear(Projectile *p, int t) { // sure is physics in here; a[0]: velocity
|
|||
return 1;
|
||||
}
|
||||
|
||||
void ProjDraw(Projectile *proj, int t) {
|
||||
void _ProjDraw(Projectile *proj, int t) {
|
||||
if(proj->clr != NULL) {
|
||||
GLuint shader = get_shader("bullet_color");
|
||||
glUseProgramObjectARB(shader);
|
||||
|
@ -196,32 +203,41 @@ void ProjDraw(Projectile *proj, int t) {
|
|||
glUniform4fv(glGetUniformLocation(shader, "color"), 1, (GLfloat *)proj->clr);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(creal(proj->pos), cimag(proj->pos), 0);
|
||||
glRotatef(proj->angle*180/M_PI+90, 0, 0, 1);
|
||||
|
||||
draw_texture_p(0,0, proj->tex);
|
||||
glPopMatrix();
|
||||
|
||||
glUseProgramObjectARB(0);
|
||||
}
|
||||
|
||||
void Shrink(Projectile *p, int t) {
|
||||
if(p->clr != NULL) {
|
||||
GLuint shader = get_shader("bullet_color");
|
||||
glUseProgramObjectARB(shader);
|
||||
glUniform4fv(glGetUniformLocation(shader, "color"), 1, (GLfloat *)p->clr);
|
||||
}
|
||||
void ProjDraw(Projectile *proj, int t) {
|
||||
glPushMatrix();
|
||||
glTranslatef(creal(proj->pos), cimag(proj->pos), 0);
|
||||
glRotatef(proj->angle*180/M_PI+90, 0, 0, 1);
|
||||
|
||||
_ProjDraw(proj, t);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void Shrink(Projectile *p, int t) {
|
||||
glPushMatrix();
|
||||
float s = 2.0-t/p->args[0]*2;
|
||||
glTranslatef(creal(p->pos), cimag(p->pos), 0);
|
||||
glRotatef(p->angle, 0, 0, 1);
|
||||
glScalef(s, s, 1);
|
||||
draw_texture_p(0, 0, p->tex);
|
||||
glPopMatrix();
|
||||
|
||||
glUseProgramObjectARB(0);
|
||||
_ProjDraw(p, t);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void DeathShrink(Projectile *p, int t) {
|
||||
glPushMatrix();
|
||||
float s = 2.0-t/p->args[0]*2;
|
||||
glTranslatef(creal(p->pos), cimag(p->pos), 0);
|
||||
glRotatef(p->angle, 0, 0, 1);
|
||||
glScalef(s, 1, 1);
|
||||
|
||||
_ProjDraw(p, t);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
int bullet_flare_move(Projectile *p, int t) {
|
||||
|
@ -241,7 +257,7 @@ int bullet_flare_move(Projectile *p, int t) {
|
|||
|
||||
void Fade(Projectile *p, int t) {
|
||||
glColor4f(1,1,1, 1.0 - (float)t/p->args[0]);
|
||||
draw_texture_p(creal(p->pos), cimag(p->pos), p->tex);
|
||||
ProjDraw(p, t);
|
||||
glColor4f(1,1,1,1);
|
||||
}
|
||||
|
||||
|
@ -250,4 +266,12 @@ int timeout(Projectile *p, int t) {
|
|||
return ACTION_DESTROY;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int timeout_linear(Projectile *p, int t) {
|
||||
if(t >= creal(p->args[0]))
|
||||
return ACTION_DESTROY;
|
||||
|
||||
p->angle = carg(p->args[1]);
|
||||
p->pos = p->pos0 + p->args[1]*t;
|
||||
}
|
|
@ -24,6 +24,13 @@ struct Projectile;
|
|||
typedef int (*ProjRule)(struct Projectile *p, int t);
|
||||
typedef void (*ProjDRule)(struct Projectile *p, int t);
|
||||
|
||||
#define Pr (&global.projs)
|
||||
#define Pa (&global.particles)
|
||||
|
||||
enum {
|
||||
RULE_ARGC = 4
|
||||
};
|
||||
|
||||
typedef struct Projectile {
|
||||
struct Projectile *next;
|
||||
struct Projectile *prev;
|
||||
|
@ -40,22 +47,23 @@ typedef struct Projectile {
|
|||
ProjDRule draw;
|
||||
Texture *tex;
|
||||
|
||||
enum { PlrProj, FairyProj, DeadProj } type;
|
||||
enum { PlrProj, FairyProj, DeadProj, Particle } type;
|
||||
|
||||
Color *clr;
|
||||
|
||||
complex args[4];
|
||||
complex args[RULE_ARGC];
|
||||
} Projectile;
|
||||
|
||||
void load_projectiles();
|
||||
|
||||
Color *rgba(float r, float g, float b, float a);
|
||||
|
||||
inline complex *rarg(complex arg0, ...);
|
||||
inline Color *rgb(float r, float g, float b);
|
||||
|
||||
Projectile *create_particle(char *name, complex pos, Color *clr, ProjDRule draw, ProjRule rule, complex arg1, ...);
|
||||
Projectile *create_projectile(char *name, complex pos, Color *clr, ProjRule rule, complex arg1, ...);
|
||||
Projectile *create_projectile_dv(Projectile **dest, char *name, complex pos, Color *clr, ProjDRule draw, ProjRule rule, complex *args);
|
||||
Projectile *create_particle(char *name, complex pos, Color *clr, ProjDRule draw, ProjRule rule, complex *a);
|
||||
Projectile *create_projectile(char *name, complex pos, Color *clr, ProjRule rule, complex *a);
|
||||
Projectile *create_projectile_p(Projectile **dest, Texture *tex, complex pos, Color *clr, ProjDRule draw, ProjRule rule, complex *args);
|
||||
void delete_projectile(Projectile **dest, Projectile *proj);
|
||||
void delete_projectiles(Projectile **dest);
|
||||
void draw_projectiles(Projectile *projs);
|
||||
|
@ -72,4 +80,8 @@ int bullet_flare_move(Projectile *p, int t);
|
|||
|
||||
void Fade(Projectile *p, int t);
|
||||
int timeout(Projectile *p, int t);
|
||||
|
||||
void DeathShrink(Projectile *p, int t);
|
||||
int timeout_linear(Projectile *p, int t);
|
||||
|
||||
#endif
|
|
@ -20,7 +20,7 @@ void simpleEnemy(Enemy *e, int t) {
|
|||
}
|
||||
|
||||
if(!(t % 50))
|
||||
create_projectile("ball", e->pos, rgb(0,0,1), linear,3 + 2I);
|
||||
create_projectile("ball", e->pos, rgb(0,0,1), linear,rarg(3 + 2I));
|
||||
|
||||
e->moving = 1;
|
||||
e->dir = creal(e->args[0]) < 0;
|
||||
|
@ -164,11 +164,17 @@ void cirno_perfect_freeze(Boss *c, int time) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(time > 10 && time < 80)
|
||||
create_projectile("ball", c->pos, rgb(rand()/(float)RAND_MAX, rand()/(float)RAND_MAX, rand()/(float)RAND_MAX), cirno_pfreeze_frogs, 4*cexp(I*rand()))->parent=&global.boss;
|
||||
if(time > 10 && time < 80) {
|
||||
float r = rand()/(float)RAND_MAX;
|
||||
float g = rand()/(float)RAND_MAX;
|
||||
float b = rand()/(float)RAND_MAX;
|
||||
|
||||
create_projectile("ball", c->pos, rgb(r, g, b), cirno_pfreeze_frogs, rarg(4*cexp(I*rand())))->parent=&global.boss;
|
||||
}
|
||||
|
||||
if(time > 160 && time < 220 && !(time % 7)) {
|
||||
create_projectile("rice", c->pos + 60, rgb(0.3, 0.4, 0.9), linear, 5*cexp(I*carg(global.plr.pos - c->pos)));
|
||||
create_projectile("rice", c->pos - 60, rgb(0.3, 0.4, 0.9), linear, 5*cexp(I*carg(global.plr.pos - c->pos)));
|
||||
create_projectile("rice", c->pos + 60, rgb(0.3, 0.4, 0.9), linear, rarg(5*cexp(I*carg(global.plr.pos - c->pos))));
|
||||
create_projectile("rice", c->pos - 60, rgb(0.3, 0.4, 0.9), linear, rarg(5*cexp(I*carg(global.plr.pos - c->pos))));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue