Various laser changes
* More lenient collision detection * More rounded corners * Add a task for laser charging (not used yet) * Make snow halation lasers not use the logic rule - Logic rules to be removed in favor of tasks
This commit is contained in:
parent
60741cc5b0
commit
b49e518a27
6 changed files with 125 additions and 68 deletions
|
@ -15,13 +15,16 @@ vec2 pos_rule(float t);
|
|||
#include "vertex_pos.glslh"
|
||||
|
||||
void main(void) {
|
||||
vec2 p = pos_rule(gl_InstanceID * 0.5 + timeshift);
|
||||
vec2 d = p - pos_rule(gl_InstanceID * 0.5 + timeshift - 0.1);
|
||||
float instance = gl_InstanceID;
|
||||
float t = instance * 0.5 + timeshift;
|
||||
|
||||
float t1 = gl_InstanceID - span / 2;
|
||||
float tail = span / 1.9;
|
||||
float s = -0.75 / pow(tail, 2) * (t1 - tail) * (t1 + tail);
|
||||
s = pow(s, width_exponent);
|
||||
vec2 p = pos_rule(t);
|
||||
vec2 d = p - pos_rule(t - 0.1);
|
||||
|
||||
float tail = span / 1.6;
|
||||
float mid_ofs = instance - span * 0.5;
|
||||
float s = -1 / (tail * tail) * (mid_ofs - tail) * (mid_ofs + tail);
|
||||
s = 0.75 * pow(s, width_exponent);
|
||||
|
||||
vec2 pos = laser_vertex_pos(p, d, s);
|
||||
gl_Position = r_projectionMatrix * r_modelViewMatrix * vec4(pos, 0.0, 1.0);
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_stages_dialog_interface_h
|
||||
#define IGUARD_stages_dialog_interface_h
|
||||
#ifndef IGUARD_dialog_dialog_interface_h
|
||||
#define IGUARD_dialog_dialog_interface_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
|
@ -76,4 +76,4 @@ typedef struct PlayerDialogProcs {
|
|||
void (*stage6_pre_final)(Dialog *d);
|
||||
} PlayerDialogProcs;
|
||||
|
||||
#endif // IGUARD_stages_dialog_interface_h
|
||||
#endif // IGUARD_dialog_dialog_interface_h
|
||||
|
|
109
src/laser.c
109
src/laser.c
|
@ -27,6 +27,7 @@ static struct {
|
|||
Framebuffer *render_fb;
|
||||
FBPair blur_fb_pair;
|
||||
ManagedFramebufferGroup *mfb_group;
|
||||
bool force_generic;
|
||||
} lasers;
|
||||
|
||||
typedef struct LaserInstancedAttribs {
|
||||
|
@ -124,6 +125,8 @@ void lasers_preload(void) {
|
|||
lasers.quad_generic.vertex_array = lasers.varr;
|
||||
|
||||
lasers.shader_generic = r_shader_get("laser_generic");
|
||||
|
||||
lasers.force_generic = env_get_int("TAISEI_FORCE_GENERIC_LASER_SHADER", false);
|
||||
}
|
||||
|
||||
void lasers_free(void) {
|
||||
|
@ -162,6 +165,7 @@ Laser *create_laser(cmplx pos, float time, float deathtime, const Color *color,
|
|||
l->next_graze = 0;
|
||||
l->clear_flags = 0;
|
||||
l->unclearable = false;
|
||||
l->collision_active = true;
|
||||
|
||||
l->ent.draw_layer = LAYER_LASER_HIGH;
|
||||
l->ent.draw_func = ent_draw_laser;
|
||||
|
@ -185,9 +189,9 @@ Laser *create_laserline_ab(cmplx a, cmplx b, float width, float charge, float du
|
|||
return create_laser(a, 200, dur, clr, las_linear, static_laser, m, charge + I*width, 0, 0);
|
||||
}
|
||||
|
||||
static double laser_graze_width(Laser *l, double *exponent) {
|
||||
*exponent = 0; // l->width_exponent * 0.5;
|
||||
return 5 * sqrt(l->width) + 15;
|
||||
static float laser_graze_width(Laser *l, float *exponent) {
|
||||
*exponent = 0; // l->width_exponent * 0.5f;
|
||||
return 5.0f * sqrtf(l->width) + 15.0f;
|
||||
}
|
||||
|
||||
static bool draw_laser_instanced_prepare(Laser *l, uint *out_instances, float *out_timeshift) {
|
||||
|
@ -220,6 +224,8 @@ static void draw_laser_curve_specialized(Laser *l) {
|
|||
float timeshift;
|
||||
uint instances;
|
||||
|
||||
assert(!lasers.force_generic);
|
||||
|
||||
if(!draw_laser_instanced_prepare(l, &instances, ×hift)) {
|
||||
return;
|
||||
}
|
||||
|
@ -272,22 +278,22 @@ static void draw_laser_curve_generic(Laser *l) {
|
|||
SDL_RWops *stream = r_vertex_buffer_get_stream(lasers.vbuf);
|
||||
r_vertex_buffer_invalidate(lasers.vbuf);
|
||||
|
||||
float tail = instances / 1.9;
|
||||
float tail_factor = -0.75 / (tail * tail);
|
||||
float tail = instances / 1.6;
|
||||
float width_factor = -1 / (tail * tail);
|
||||
|
||||
for(uint i = 0; i < instances; ++i) {
|
||||
cmplx pos = l->prule(l, i * 0.5 + timeshift);
|
||||
cmplx delta = pos - l->prule(l, i * 0.5 + timeshift - 0.1);
|
||||
|
||||
float t1 = i - instances / 2.0;
|
||||
float s = powf(tail_factor * (t1 - tail) * (t1 + tail), l->width_exponent);
|
||||
float mid_ofs = i - instances * 0.5;
|
||||
float w = 0.75f * powf(width_factor * (mid_ofs - tail) * (mid_ofs + tail), l->width_exponent);
|
||||
|
||||
LaserInstancedAttribs attr;
|
||||
attr.pos[0] = creal(pos);
|
||||
attr.pos[1] = cimag(pos);
|
||||
attr.delta[0] = creal(delta);
|
||||
attr.delta[1] = cimag(delta);
|
||||
attr.fragment_width = s;
|
||||
attr.fragment_width = w;
|
||||
|
||||
SDL_RWwrite(stream, &attr, sizeof(attr), 1);
|
||||
}
|
||||
|
@ -298,7 +304,7 @@ static void draw_laser_curve_generic(Laser *l) {
|
|||
static void ent_draw_laser(EntityInterface *ent) {
|
||||
Laser *laser = ENT_CAST(ent, Laser);
|
||||
|
||||
if(laser->shader) {
|
||||
if(laser->shader && !lasers.force_generic) {
|
||||
draw_laser_curve_specialized(laser);
|
||||
} else {
|
||||
draw_laser_curve_generic(laser);
|
||||
|
@ -412,7 +418,8 @@ void delete_lasers(void) {
|
|||
}
|
||||
|
||||
bool laser_is_active(Laser *l) {
|
||||
return l->width > 3.0;
|
||||
// return l->width > 3.0;
|
||||
return l->collision_active;
|
||||
}
|
||||
|
||||
bool laser_is_clearable(Laser *l) {
|
||||
|
@ -485,21 +492,20 @@ void process_lasers(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool laser_collision_segment(Laser *l, LineSegment *segment, Circle *collision_area, float t, float width_tail_factor, float tail) {
|
||||
float t1 = t - l->timespan / 2;
|
||||
float widthfac_orig = width_tail_factor * (t1 - tail) * (t1 + tail);
|
||||
float widthfac = max(0.25, pow(widthfac_orig, l->width_exponent));
|
||||
static inline bool laser_collision_segment(Laser *l, LineSegment *segment, Circle *collision_area, float t, float segment_width_factor, float tail) {
|
||||
float mid_ofs = t - l->timespan * 0.5f;
|
||||
float widthfac_orig = segment_width_factor * (mid_ofs - tail) * (mid_ofs + tail);
|
||||
float widthfac = 0.75f * 0.5f * powf(widthfac_orig, l->width_exponent);
|
||||
|
||||
segment->b = l->prule(l, t);
|
||||
collision_area->radius = widthfac * l->width * 0.5 + 1;
|
||||
collision_area->radius = fmaxf(widthfac * l->width - 4.0f, 2.0f);
|
||||
|
||||
if(lineseg_circle_intersect(*segment, *collision_area) >= 0) {
|
||||
if(lineseg_circle_intersect(*segment, *collision_area) >= 0.0f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(global.frames >= l->next_graze && global.frames - abs(global.plr.recovery) > 0) {
|
||||
double exponent;
|
||||
collision_area->radius = laser_graze_width(l, &exponent) * max(0.25, pow(widthfac_orig, exponent));
|
||||
if(global.frames >= l->next_graze && global.frames - abs(global.plr.recovery) > 0.0f) {
|
||||
float exponent;
|
||||
collision_area->radius = laser_graze_width(l, &exponent) * fmaxf(0.25f, powf(widthfac_orig, exponent));
|
||||
assert(collision_area->radius > 0);
|
||||
float f = lineseg_circle_intersect(*segment, *collision_area);
|
||||
|
||||
|
@ -509,7 +515,6 @@ static inline bool laser_collision_segment(Laser *l, LineSegment *segment, Circl
|
|||
}
|
||||
}
|
||||
|
||||
segment->a = segment->b;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -530,16 +535,20 @@ static bool laser_collision(Laser *l) {
|
|||
LineSegment segment = { .a = l->prule(l,t) };
|
||||
Circle collision_area = { .origin = global.plr.pos };
|
||||
|
||||
float tail = l->timespan / 1.9;
|
||||
float width_tail_factor = -0.75 / (tail * tail);
|
||||
float tail = l->timespan / 1.6f;
|
||||
float width_factor = -1.0f / (tail * tail);
|
||||
|
||||
for(t += l->collision_step; t <= t_end; t += l->collision_step) {
|
||||
if(laser_collision_segment(l, &segment, &collision_area, t, width_tail_factor, tail)) {
|
||||
segment.b = l->prule(l, t);
|
||||
|
||||
if(laser_collision_segment(l, &segment, &collision_area, t, width_factor, tail)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
segment.a = segment.b;
|
||||
}
|
||||
|
||||
return laser_collision_segment(l, &segment, &collision_area, t_end, width_tail_factor, tail);
|
||||
return laser_collision_segment(l, &segment, &collision_area, t_end, width_factor, tail);
|
||||
}
|
||||
|
||||
bool laser_intersects_ellipse(Laser *l, Ellipse ellipse) {
|
||||
|
@ -685,31 +694,51 @@ cmplx las_circle(Laser *l, float t) {
|
|||
return l->pos + radius * cexp(I * (t + time_ofs) * turn_speed);
|
||||
}
|
||||
|
||||
float laser_charge(Laser *l, int t, float charge, float width) {
|
||||
void laser_charge(Laser *l, int t, float charge, float width) {
|
||||
float new_width;
|
||||
|
||||
if(t < charge - 10) {
|
||||
return min(2, 2 * t / min(30, charge - 10));
|
||||
new_width = fminf(2.0f, 2.0f * t / fminf(30.0f, charge - 10.0f));
|
||||
} else if(t >= charge - 10.0f && t < l->deathtime - 20.0f) {
|
||||
new_width = fminf(width, 1.7f + width / 20.0f * (t - charge + 10.0f));
|
||||
} else if(t >= l->deathtime - 20.0f) {
|
||||
new_width = fmaxf(0.0f, width - width / 20.0f * (t - l->deathtime + 20.0f));
|
||||
} else {
|
||||
new_width = width;
|
||||
}
|
||||
|
||||
if(t >= charge - 10 && t < l->deathtime - 20) {
|
||||
float w = 1.7 + width/20*(t-charge+10);
|
||||
return w < width ? w : width;
|
||||
}
|
||||
l->width = new_width;
|
||||
l->collision_active = (new_width > width * 0.6f);
|
||||
}
|
||||
|
||||
if(t >= l->deathtime - 20) {
|
||||
float w = width - width/20*(t-l->deathtime+20);
|
||||
return w > 0 ? w : 0;
|
||||
}
|
||||
|
||||
return width;
|
||||
void laser_make_static(Laser *l) {
|
||||
l->speed = 0;
|
||||
l->timeshift = l->timespan;
|
||||
}
|
||||
|
||||
void static_laser(Laser *l, int t) {
|
||||
if(t == EVENT_BIRTH) {
|
||||
l->width = 0;
|
||||
l->speed = 0;
|
||||
l->timeshift = l->timespan;
|
||||
l->collision_active = false;
|
||||
laser_make_static(l);
|
||||
return;
|
||||
}
|
||||
|
||||
l->width = laser_charge(l, t, creal(l->args[1]), cimag(l->args[1]));
|
||||
laser_charge(l, t, creal(l->args[1]), cimag(l->args[1]));
|
||||
}
|
||||
|
||||
DEFINE_EXTERN_TASK(laser_charge) {
|
||||
Laser *l = TASK_BIND(ARGS.laser);
|
||||
|
||||
l->width = 0;
|
||||
l->collision_active = false;
|
||||
laser_make_static(l);
|
||||
|
||||
float target_width = ARGS.target_width;
|
||||
float charge_delay = ARGS.charge_delay;
|
||||
|
||||
for(int t = 0;; ++t) {
|
||||
laser_charge(l, t, charge_delay, target_width);
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
|
21
src/laser.h
21
src/laser.h
|
@ -45,7 +45,8 @@ struct Laser {
|
|||
float collision_step;
|
||||
uint clear_flags;
|
||||
|
||||
bool unclearable;
|
||||
uchar unclearable : 1;
|
||||
uchar collision_active : 1;
|
||||
};
|
||||
|
||||
#define create_lasercurve1c(p, time, deathtime, clr, rule, a0) create_laser(p, time, deathtime, clr, rule, 0, a0, 0, 0, 0)
|
||||
|
@ -56,13 +57,13 @@ struct Laser {
|
|||
void lasers_preload(void);
|
||||
void lasers_free(void);
|
||||
|
||||
Laser *create_laserline(cmplx pos, cmplx dir, float charge, float dur, const Color *clr);
|
||||
Laser *create_laserline_ab(cmplx a, cmplx b, float width, float charge, float dur, const Color *clr);
|
||||
|
||||
Laser *create_laser(cmplx pos, float time, float deathtime, const Color *color, LaserPosRule prule, LaserLogicRule lrule, cmplx a0, cmplx a1, cmplx a2, cmplx a3);
|
||||
void delete_lasers(void);
|
||||
void process_lasers(void);
|
||||
|
||||
Laser *create_laserline(cmplx pos, cmplx dir, float charge, float dur, const Color *clr);
|
||||
Laser *create_laserline_ab(cmplx a, cmplx b, float width, float charge, float dur, const Color *clr);
|
||||
Laser *create_laser(cmplx pos, float time, float deathtime, const Color *color, LaserPosRule prule, LaserLogicRule lrule, cmplx a0, cmplx a1, cmplx a2, cmplx a3);
|
||||
|
||||
bool laser_is_active(Laser *l);
|
||||
bool laser_is_clearable(Laser *l);
|
||||
bool clear_laser(Laser *l, uint flags);
|
||||
|
@ -75,10 +76,18 @@ cmplx las_sine_expanding(Laser *l, float t);
|
|||
cmplx las_turning(Laser *l, float t);
|
||||
cmplx las_circle(Laser *l, float t);
|
||||
|
||||
float laser_charge(Laser *l, int t, float charge, float width);
|
||||
void laser_make_static(Laser *l);
|
||||
void laser_charge(Laser *l, int t, float charge, float width);
|
||||
|
||||
void static_laser(Laser *l, int t);
|
||||
|
||||
bool laser_intersects_circle(Laser *l, Circle circle);
|
||||
bool laser_intersects_ellipse(Laser *l, Ellipse ellipse);
|
||||
|
||||
DECLARE_EXTERN_TASK(laser_charge, {
|
||||
BoxedLaser laser;
|
||||
float charge_delay;
|
||||
float target_width;
|
||||
});
|
||||
|
||||
#endif // IGUARD_laser_h
|
||||
|
|
|
@ -369,14 +369,30 @@ static Color *halation_color(Color *out_clr, float phase) {
|
|||
return out_clr;
|
||||
}
|
||||
|
||||
static void halation_laser(Laser *l, int time) {
|
||||
static_laser(l, time);
|
||||
TASK(halation_laser_color, { BoxedLaser laser; float max_width; }) {
|
||||
Laser *l = TASK_BIND(ARGS.laser);
|
||||
float max_width = ARGS.max_width;
|
||||
|
||||
if(time >= 0) {
|
||||
halation_color(&l->color, l->width / cimag(l->args[1]));
|
||||
for(;;) {
|
||||
halation_color(&l->color, l->width / max_width);
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
static Laser *create_halation_laser(cmplx a, cmplx b, float width, float charge, float dur, const Color *clr) {
|
||||
Laser *l;
|
||||
|
||||
if(clr == NULL) {
|
||||
Color c;
|
||||
l = create_laserline_ab(a, b, width, charge, dur, &c);
|
||||
INVOKE_TASK(halation_laser_color, ENT_BOX(l), width);
|
||||
} else {
|
||||
l = create_laserline_ab(a, b, width, charge, dur, clr);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
TASK(halation_orb_trail, { BoxedProjectile orb; }) {
|
||||
Projectile *orb = TASK_BIND(ARGS.orb);
|
||||
|
||||
|
@ -410,23 +426,23 @@ TASK(halation_orb, {
|
|||
// TODO modernize lasers
|
||||
|
||||
WAIT(activation_time);
|
||||
create_laserline_ab(pos[2], pos[3], 15, phase_time * 0.5, phase_time * 2.0, &orb->color);
|
||||
create_laserline_ab(pos[0], pos[2], 15, phase_time, phase_time * 1.5, &orb->color)->lrule = halation_laser;
|
||||
create_halation_laser(pos[2], pos[3], 15, phase_time * 0.5, phase_time * 2.0, &orb->color);
|
||||
create_halation_laser(pos[0], pos[2], 15, phase_time, phase_time * 1.5, NULL);
|
||||
|
||||
WAIT(phase_time / 2);
|
||||
play_sound("laser1");
|
||||
WAIT(phase_time / 2);
|
||||
create_laserline_ab(pos[0], pos[1], 12, phase_time, phase_time * 1.5, &orb->color)->lrule = halation_laser;
|
||||
create_halation_laser(pos[0], pos[1], 12, phase_time, phase_time * 1.5, NULL);
|
||||
|
||||
WAIT(phase_time);
|
||||
play_sound("shot1");
|
||||
create_laserline_ab(pos[0], pos[3], 15, phase_time, phase_time * 1.5, &orb->color)->lrule = halation_laser;
|
||||
create_laserline_ab(pos[1], pos[3], 15, phase_time, phase_time * 1.5, &orb->color)->lrule = halation_laser;
|
||||
create_halation_laser(pos[0], pos[3], 15, phase_time, phase_time * 1.5, NULL);
|
||||
create_halation_laser(pos[1], pos[3], 15, phase_time, phase_time * 1.5, NULL);
|
||||
|
||||
WAIT(phase_time);
|
||||
play_sound("shot1");
|
||||
create_laserline_ab(pos[0], pos[1], 12, phase_time, phase_time * 1.5, &orb->color)->lrule = halation_laser;
|
||||
create_laserline_ab(pos[0], pos[2], 15, phase_time, phase_time * 1.5, &orb->color)->lrule = halation_laser;
|
||||
create_halation_laser(pos[0], pos[1], 12, phase_time, phase_time * 1.5, NULL);
|
||||
create_halation_laser(pos[0], pos[2], 15, phase_time, phase_time * 1.5, NULL);
|
||||
|
||||
WAIT(phase_time);
|
||||
play_sound("shot1");
|
||||
|
|
|
@ -1031,7 +1031,7 @@ static void wriggle_ignite_warnlaser_logic(Laser *l, int time) {
|
|||
play_sound_ex("laser1", 30, false);
|
||||
}
|
||||
|
||||
l->width = laser_charge(l, time, 90, 10);
|
||||
laser_charge(l, time, 90, 10);
|
||||
l->color = *color_lerp(RGBA(0.2, 0.2, 1, 0), RGBA(1, 0.2, 0.2, 0), time / l->deathtime);
|
||||
}
|
||||
|
||||
|
@ -1112,7 +1112,7 @@ static void wriggle_singularity_laser_logic(Laser *l, int time) {
|
|||
play_sound("laser1");
|
||||
}
|
||||
|
||||
l->width = laser_charge(l, time, 150, 10 + 10 * psin(l->args[0] + time / 60.0));
|
||||
laser_charge(l, time, 150, 10 + 10 * psin(l->args[0] + time / 60.0));
|
||||
l->args[3] = time / 10.0;
|
||||
l->args[0] *= cexp(I*(M_PI/500.0) * (0.7 + 0.35 * global.diff));
|
||||
|
||||
|
|
Loading…
Reference in a new issue