Physics
Everybody Edits includes a physics engine to manage the movement of its players and interactions with player inputs and world blocks.
Source code files
Inside Everybody Edits Offline source:
| Config.as | constants used in the physics engine (such as drag values, jump height, gravity values, delayed block queue, etc.) |
| Me.as | touchBlock function (handles most non-solid collisions, such as interactions with coins, reset block, sound blocks, crown, switches, invisible gravity, diamond/cake/hologram, checkpoint, win, god enable, minimap enable, keys, effects, lava) |
| Player.as | tick function (handles most of the physics logic) |
| World.as | overlaps function (handles collision with solid blocks, including doors/gates, half blocks, one-way, and secret blocks) |
Timing
EE physics runs at 100tps (100 ticks per second), meaning that each physics tick takes 0.01 seconds.
Inputs
On each tick, the arrow/WASD keys and space keys are evaluated. The arrow/WASD inputs are converted into horizontal and vertical components of -1, 0, or 1, in which left+right and up+down inputs cancel out to 0. Space may be pressed independently of other keys.
Coordinates
Player's coordinates are represented in double precision floating point. The position [0, 0] corresponds to the top left block, and increases to the right and downwards in pixels (16 pixels per block on both axes). The bottom right position is [(width-1)*16, (height-1)*16].
Current and delayed blocks
The current block is determined by dividing player's position by 16 and rounding it (round to nearest, halfway values round up), except for down half or right half block, which decrement vertical or horizontal position of current block respectively.
The delayed block corresponds to current block from second previous tick (therefore delayed by 2 ticks from current block), unless the current block is a gravity dot or climbable/slow dot, in which case the current block is pushed to the queue a second time (effectively making delayed block only delayed by 1 tick), resulting in dots having a slightly faster reaction than other gravities.
Slippery field
First, the current_below block is determined (only used for computing slippery value). It follows the gravity direction inside the current block (following player's gravity if current is not a gravity arrow) and offsets by 1 from the current block to determine the current_below block. However, invisible right arrow (413), down arrow (1518, 1519), and invisible dot (414) are ignored, dot (4) is interpreted as a down offset, and neutral gravity (flipGravity==4) is interpreted as a right offset.
The slippery value is initialized to 0. It is set to 2 if current_below is an ice block and current is not a dot or climbable/slow dot. Otherwise, it is set to 0 if current_below is solid. Otherwise, it is set to 0.2 less than previous slippery value.
In case of slippery>0, jump height is multiplied by 0.88, it also affects drag computation.
Drag values
Drag values are used for multiplicative deceleration of player's speed.
| name | definition | floating point result |
|---|---|---|
| physics_ms_per_tick | 10 | 10 |
| physics_base_drag | Math.pow(.9981,physics_ms_per_tick) * 1.00016093 | 0.9813195279915707 |
| physics_ice_no_mod_drag | Math.pow(.9993,physics_ms_per_tick) * 1.00016093 | 0.9931818159222691 |
| physics_ice_drag | Math.pow(.9998,physics_ms_per_tick) * 1.00016093 | 0.9981624074698557 |
| physics_no_modifier_drag | Math.pow(.9900,physics_ms_per_tick) * 1.00016093 | 0.9045276172161356 |
| physics_water_drag | Math.pow(.9950,physics_ms_per_tick) * 1.00016093 | 0.9512631926190678 |
| physics_mud_drag | Math.pow(.9750,physics_ms_per_tick) * 1.00016093 | 0.7764545555823221 |
| physics_lava_drag | Math.pow(.9800,physics_ms_per_tick) * 1.00016093 | 0.8172042984143593 |
| physics_toxic_drag | Math.pow(.9900,physics_ms_per_tick) * 1.00016093 | 0.9045276172161356 |
The speed is added with the sum of lateral acceleration (performed with player's horizontal/vertical movements, ignoring movements along the axis of gravity), and gravitational acceleration (performed by current arrow or world gravity).
Then, using the drag constants, drag is applied on each axis as follows (first true condition applies):
| case | resulting speed |
|---|---|
| used if current block is climbable/slow dot (except god mode) not used if slippery<=0 (unless in god mode) used if lateral acceleration along the axis is 0 and gravity is on perpendicular axis used if speed and lateral acceleration along the axis are non-zero and of opposite signs |
speed*physics_base_drag*physics_no_modifier_drag |
| used if current block is water | speed*physics_base_drag*physics_water_drag |
| used if current block is mud | speed*physics_base_drag*physics_mud_drag |
| used if current block is lava | speed*physics_base_drag*physics_lava_drag |
| used if current block is toxic | speed*physics_base_drag*physics_toxic_drag |
| used if slippery>0 (except god mode), lateral acceleration along the axis is non-zero, and speed along the axis is zero or same sign as lateral movement | speed*physics_base_drag |
| used if slippery>0 (except god mode), lateral acceleration along the axis is 0 | speed*physics_ice_no_mod_drag |
| used if slippery>0 (except god mode), speed and lateral acceleration along the axis are non-zero and of opposite signs | speed*physics_ice_no_mod_drag*physics_ice_drag |
| used if none of the above | speed*physics_base_drag |
After computing drag on each axis, the speed is capped to a minimum of -16 and maximum of 16.
Speeds less than 0.0001 and greater than -0.0001 are set to 0. That's when the player will start falling on hovers if not moving (prior to that, it can stay in hover if within 0.2 pixels of block due to auto-align), or will be able to jump on a Tight-fit (which is why it takes more time to perform an Ice Tight-fit due to the ice drag being closer to 1).
Boosts force the speed to be -16 or 16 on the axis they apply to, though the other axis still follows the usual computations.