1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-23 13:07:16 +00:00

bouncing off trampolines and returning to surface

This commit is contained in:
Zeno Rogue 2024-08-18 15:43:19 +02:00
parent 81ea54746b
commit 25bbd96a72
3 changed files with 110 additions and 15 deletions

View File

@ -391,6 +391,7 @@ void level::init() {
start.timer = 0;
start.on_surface = this;
start.sstime = -100;
start.last_tramp = -100;
current = start;
println(hlog, "start.where = ", start.where);
println(hlog, "current.where = ", current.where, " : ", hr::format("%p", &current));

View File

@ -6,6 +6,9 @@ using namespace rogueviz;
struct level;
/** ticks per second */
inline const ld tps = 1000;
struct timestamp {
hyperpoint where; /**< the current position of the unicycle */
ld heading_angle; /**< the current heading angle */
@ -22,11 +25,16 @@ struct timestamp {
hyperpoint flyvel;/**< velocity vector if we are not on any surface */
ld circvel; /**< how fast the wheel is rotating if we are not on any surface, per second */
ld last_draw; /**< when was gfx_slope computed */
ld last_tramp; /**< time of last trampoline */
ld tramp_head; /**< heading_angle at the moment of last trampoline */
flagtype collected_triangles; /**< a bitset which shows which triangles are collected */
flagtype goals; /**< a bitset which shows which goals are complete */
flagtype failed; /**< a bitset which shows which goals are failed */
bool tick(level*);/**< one tick of the simulation -- returns false if the unicycle has stopped or crashed */
bool tick(level*, ld timeleft = 1. / tps);/**< one tick of the simulation -- returns false if the unicycle has stopped or crashed */
void centerview(level*);
void draw_unilcycle(const shiftmatrix&);
void draw_instruments(level*);
@ -34,6 +42,9 @@ struct timestamp {
bool collect(level*);
bool out_of_surface(level*);
void be_consistent();
bool check_crashes_rec(level*, hyperpoint owhere, hyperpoint oflyvel, ld timeleft);
bool check_crashes(level*, hyperpoint owhere, hyperpoint oflyvel, ld timeleft);
};
struct planpoint {
@ -191,6 +202,8 @@ struct level {
bool handle_planning(int sym, int uni);
void solve();
hyperpoint surface_point(hyperpoint h) { h[2] = surface(h); return h; }
xy_float get_xy_f(hyperpoint h);
xy_int get_xy_i(hyperpoint h) { return pfloor(get_xy_f(h)); }
char mapchar(xy_int p);
@ -198,9 +211,6 @@ struct level {
char mapchar(hyperpoint h) { return mapchar(pfloor(get_xy_f(h))); }
};
/** ticks per second */
inline const ld tps = 1000;
/** wheel radius */
inline ld whrad = 0.05;

View File

@ -147,7 +147,7 @@ void timestamp::be_consistent() {
heading_angle = int_to_heading(heading_to_int(heading_angle));
}
bool timestamp::tick(level *lev) {
bool timestamp::tick(level *lev, ld time_left) {
if(on_surface && !collect(lev)) return false;
const ld eps = slope_eps;
@ -169,48 +169,128 @@ bool timestamp::tick(level *lev) {
}
}
timer += time_left;
if(on_surface) {
auto ovel = vel;
vel -= sin(slope) * gravity / tps;
vel -= sin(slope) * gravity * time_left;
if(vel < 0) {
vel = 0;
if(ovel == 0) return false;
}
auto mvel = (vel + ovel) / 2;
where[0] += cos(heading_angle) * mvel * cos(slope) / tps;
where[1] += sin(heading_angle) * mvel * cos(slope) / tps;
where[0] += cos(heading_angle) * mvel * cos(slope) * time_left;
where[1] += sin(heading_angle) * mvel * cos(slope) * time_left;
where[2] = lev->surface(where);
circvel = mvel / whrad;
}
else {
auto owhere = where;
auto oflyvel = flyvel;
flyvel = rgpushxto0(where) * flyvel;
flyvel[2] -= gravity / tps / 2;
flyvel[2] -= gravity * time_left / 2;
// todo rewrite geodesic_step to take gravity into account into RK4 correctly
flyvel /= tps;
flyvel *= time_left;
nisot::geodesic_step(where, flyvel);
flyvel *= tps;
flyvel /= time_left;
flyvel[2] -= gravity / tps / 2;
flyvel[2] -= gravity * time_left / 2;
auto mflyvel = (flyvel + oflyvel) / 2;
heading_angle = atan2(mflyvel[1], mflyvel[0]);
auto new_heading_angle = atan2(mflyvel[1], mflyvel[0]);
if(timer >= last_tramp + 0.5) heading_angle = new_heading_angle;
else {
while(new_heading_angle < heading_angle - M_PI) new_heading_angle += TAU;
while(new_heading_angle > heading_angle + M_PI) new_heading_angle -= TAU;
auto oh = heading_angle;
heading_angle = lerp(heading_angle, new_heading_angle, ilerp(timer - time_left, last_tramp + 0.5, timer));
println(hlog, oh, " _ ", new_heading_angle, " -> ", heading_angle);
}
flyvel = gpushxto0(where) * flyvel;
mflyvel = gpushxto0(where) * mflyvel;
slope = atan(mflyvel[2] / hypot_d(2, mflyvel));
vel = hypot_d(3, flyvel);
if(check_crashes_rec(lev, owhere, oflyvel, time_left)) return false;
}
circpos += circvel / tps;
circpos += circvel * time_left;
timer += 1. / tps;
return true;
}
bool timestamp::check_crashes(level* lev, hyperpoint owhere, hyperpoint oflyvel, ld time_left) {
ld oz = lev->surface(owhere);
ld z = lev->surface(where);
if(owhere[2] > oz && where[2] < z) {
auto xy = lev->get_xy_i(where);
char ch = lev->mapchar(xy);
if(ch == '!') return false;
string s0 = ""; s0 += ch;
ld part = binsearch(0, 1, [&] (ld p) {
hyperpoint h = lerp(owhere, where, p);
return h[2] < lev->surface(h);
});
println(hlog, "CRASHED INTO ", s0, " AT PART = ", part);
timer -= time_left * (1 - part);
where = lerp(owhere, where, part);
flyvel = lerp(oflyvel, flyvel, part);
/* tangent vectors */
hyperpoint dx = gpushxto0(where) * lev->surface_point(rgpushxto0(where) * point31(slope_eps, 0, 0));
hyperpoint dy = gpushxto0(where) * lev->surface_point(rgpushxto0(where) * point31(0, slope_eps, 0));
hyperpoint dz = point30(0, 0, slope_eps);
/* orthonormalize */
dx = dx / hypot_d(3, dx);
dy = dy - dot_d(3, dx, dy) * dy;
dy = dy / hypot_d(3, dy);
dz = dz - dot_d(3, dx, dz) * dx;
dz = dz - dot_d(3, dy, dz) * dy;
dz = dz / hypot_d(3, dz); dz[3] = 0;
println(hlog, "dx = ", dx);
println(hlog, "dy = ", dy);
println(hlog, "dz = ", dz);
if(ch == 'T') {
/* reflect off the trampoline */
flyvel = flyvel - dot_d(3, flyvel, dz) * dz * 2;
last_tramp = timer;
tramp_head = heading_angle;
}
else {
/* waste some energy */
flyvel = flyvel - dot_d(3, flyvel, dz) * dz;
vel = hypot_d(3, flyvel);
on_surface = lev;
}
tick(lev, time_left * (1 - part));
return true;
}
return false;
}
bool timestamp::check_crashes_rec(level* l, hyperpoint owhere, hyperpoint oflyvel, ld time_left) {
if(check_crashes(l, owhere, oflyvel, time_left)) return true;
for(auto s: l->sublevels) if(check_crashes(s, owhere, oflyvel, time_left)) return true;
return false;
}
void timestamp::centerview(level *lev) {
// static bool once = false; if(once) return; once = true;
@ -233,6 +313,8 @@ void timestamp::centerview(level *lev) {
set_view(w, front, up);
transmatrix T = View;
if(last_draw <= sstime) min_gfx_slope = gfx_slope;
gfx_slope = min_gfx_slope;
if(on_surface) gfx_slope = binsearch(-90*degree, min(slope, min_gfx_slope), [&] (ld slope) {
@ -254,6 +336,8 @@ void timestamp::centerview(level *lev) {
gfx_slope = lerp(chg_slope, gfx_slope, t * t * (3 - 2*t));
}
last_draw = timer;
View = T;
rotate_view(cspin(1, 2, gfx_slope));
shift_view(ztangent(whdist * lev->scale));