3 const int PHYSICS_TRACE_PLANE_MAX = 5;
5 // NOTE: currently unsuitable for players
6 void sys_phys_update(entity this, float dt)
8 // x: { 60: 0.5, 45: ~0.7, 30: ~0.9 }, from: 'vec2(0, 1) * vec2(cos(90 - x), sin(90 - x))'
9 // read as 'within x degrees'
10 float maxgrounddot = 0.5;
11 float maxstepdot = 0.7;
12 vector upvec = '0 0 1';
14 bool jump = this.com_in_jump;
17 vector mn = this.mins;
18 vector mx = this.maxs;
20 vector acc = this.com_phys_acc;
21 vector vel = this.com_phys_vel;
22 vector pos = this.com_phys_pos_prev = this.com_phys_pos;
23 bool onground = this.com_phys_grounded;
25 bool nogravityonground = this.com_phys_nogravityonground;
26 float stepheight = this.com_phys_stepheight;
27 float stepdownheight = -stepheight;
28 float jumpvel = this.com_phys_jumpvel;
29 float bounce = this.com_phys_bounce;
30 float friction = this.com_phys_friction;
31 float gravity = this.com_phys_gravity;
32 bool noclip = this.com_phys_noclip;
35 nogravityonground = false;
38 vector g = upvec * -gravity;
40 // apply accelaration in two steps: https://www.niksula.hut.fi/~hkankaan/Homepages/gravity.html
41 // alternatives: rk4, verlet, euler
42 vel += (acc + g) * dt / 2;
44 if (onground || noclip)
46 if (nogravityonground)
49 if (vel * upvec < 0) vel = vec_reflect(vel, upvec, 0); // kill downward velocity
53 vel += upvec * jumpvel;
55 else // the first landing frame is free
58 vector slide = noclip ? vel : vec_reflect(vel, upvec, 0);
59 vector push = vel - slide;
61 slide *= 1 - friction * dt;
65 vector step = vel * dt;
67 bool foundground = false; // assume until proven otherwise
68 if (nogravityonground) foundground = true; // override
70 if (noclip) pass = true; else
71 for (int i = 0; i < PHYSICS_TRACE_PLANE_MAX; ++i)
74 vector p1 = p0 + step;
75 tracebox(p0, mn, mx, p1, MOVE_NORMAL, this);
76 float frac = trace_fraction;
77 vector norm = trace_plane_normal;
81 if (steplimit > 0 && onground && vel * upvec <= 0)
84 tracebox(p1, mn, mx, p1 + upvec * stepdownheight, MOVE_NORMAL, this);
85 if (trace_fraction == 1)
89 else if (trace_plane_normal * upvec >= maxstepdot)
92 step += upvec * (stepdownheight * trace_fraction);
99 if (norm * upvec >= maxgrounddot) foundground = true;
100 if (steplimit > 0 && (jumpstep || onground)) // try: vel * upvec >= 0
103 vector slide = vec_reflect(step, upvec, 0); // remove fall component
104 vector p1 = p0 + slide; // step is here
105 tracebox(p1 + upvec * stepheight, mn, mx, p1, MOVE_NORMAL, this);
106 if (trace_fraction < 1 && trace_plane_normal * upvec >= maxstepdot)
108 // there is a step in front of us, get above it
109 // TODO: not if it's slippery (slick)
110 vector stepup = upvec * (1 - trace_fraction) * stepheight;
111 tracebox(p0, mn, mx, p0 + stepup, MOVE_NORMAL, this);
112 if (trace_fraction == 1)
115 tracebox(p0 + stepup, mn, mx, p1 + stepup, MOVE_NORMAL, this);
116 if (trace_fraction == 1)
121 if (vel * upvec < 0) vel = vec_reflect(vel, upvec, 0); // kill downward velocity
131 vel = vec_reflect(vel, norm, bounce);
132 step = (1 - frac) * vel * dt;
135 if (nogravityonground)
137 vector p1 = pos + step;
138 tracebox(p1, mn, mx, p1 - groundsnap * upvec, MOVE_NORMAL, this);
139 foundground = trace_plane_normal * upvec >= maxgrounddot;
146 if (onground) emit(phys_stepfall, this);
150 if (!onground) emit(phys_stepland, this);
152 onground = foundground;
155 vel += (acc + g) * dt / 2;
157 this.com_phys_acc = acc;
158 this.com_phys_vel = vel;
159 this.com_phys_pos = pos;
160 this.com_phys_grounded = onground;