mirror of
				https://github.com/zenorogue/hyperrogue.git
				synced 2025-10-31 14:02:59 +00:00 
			
		
		
		
	bouncing off trampolines and returning to surface
This commit is contained in:
		| @@ -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", ¤t)); | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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)); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Zeno Rogue
					Zeno Rogue