Sandbox: Difference between revisions
Content added Content deleted
mNo edit summary |
mNo edit summary |
||
(10 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
<languages /> |
|||
[[File:0t sprintjump graph.png|thumb|600x600px|Movement formulas applied to a 3b jump.]] |
|||
<translate><!--T:2--> paragraph 1</translate> |
|||
The player's movement can be accurately calculated with [https://en.wikipedia.org/wiki/Sequence sequences]. |
|||
The following formulas come from analyzing the game's [[SourceCode|source code]]. |
|||
<translate><!--T:3--> paragraph 2</translate> |
|||
Note that these formulas are '''not exact''', due to how [https://en.wikipedia.org/wiki/Floating-point_arithmetic floats] are computed. When used for calculations, only the first 4-6 decimals should be considered accurate. For a completely accurate simulation, you would need to replicate the source code. |
|||
<translate><!--T:4--> [[File:Collision box (player and block).png|left|thumb|image 1]]</translate> |
|||
In this article, we only consider standard movement, and ignore mechanics specific to certain blocks. |
|||
You will find further documentation of movement physics in these articles: |
|||
* [[Soulsand]] |
|||
* [[Ladders and Vines|Ladders and Vines]] |
|||
* [[Slime Block|Slime Blocks]] |
|||
* [[Cobweb|Cobwebs]] |
|||
'''Note:''' Minecraft's coordinate system is oriented differently: 0° points towards "positive Z", and 90° points towards "negative X". We choose to work in the standard coordinate system to make calculations more intuitive. If need be, we can simply invert the X axis to match Minecraft's coordinate system. |
|||
<translate><!--T:5--> paragraph 3</translate> |
|||
<br /> |
|||
== Vertical Movement == |
|||
===Jump Formula=== |
|||
*<math>V\displaystyle _{Y,1} = 0.42</math> |
|||
* <math>V\displaystyle _{Y,t} = \left (V_{Y,t-1} - \underset{gravity}{0.08} \right ) \times \underset{drag}{0.98}</math> |
|||
:If <math display="inline"> \left | V\displaystyle _{Y,t} \right | < 0.005 </math>, <math display="inline">V\displaystyle _{Y,t}</math> is set to 0 instead (the player's height doesn't change for that tick) |
|||
:In 1.9+, it's compared to 0.003 instead. |
|||
'''Notes''' |
|||
*<math display="inline"> V\displaystyle _{Y,0}</math> isn't assigned a value because it has no importance. By convention, the 0<sup>th</sup> tick corresponds to the player's initial velocity before jumping. |
|||
*<math display="inline"> V\displaystyle _{Y,1}</math> corresponds to the initial jump motion. It is increased by 0.1 per level of [[Status Effects|Jump Boost]] |
|||
*Terminal velocity is -3.92 m/t |
|||
*When the player collides vertically with a block, vertical momentum is cancelled and only the acceleration is left. |
|||
===Vertical Position=== |
|||
: To get the position on a given tick, you simply need to sum <math display="inline">V\displaystyle _{Y}</math> |
|||
:<math display="inline">Y(n) = \sum_{t=1}^{n} V_{Y,t}</math> |
|||
===Jump duration=== |
|||
:The '''duration''' of a jump is the number of ticks between jumping and landing. |
|||
:It also corresponds to the period of that jump's cycle when performed repeatedly. |
|||
:This notion is linked to the notion of [[Tiers]]. |
|||
:{| class="wikitable" |
|||
!Description |
|||
!Duration |
|||
|- |
|||
|Flat Jump |
|||
|12 t |
|||
|- |
|||
|3bc Jump |
|||
|11 t |
|||
|- |
|||
|<nowiki>+0.5 Jump</nowiki> |
|||
|10 t |
|||
|- |
|||
| +1 Jump |
|||
|9 t |
|||
|- |
|||
|2.5bc Jump |
|||
|6 t |
|||
|- |
|||
|2bc Jump |
|||
|3 t |
|||
|- |
|||
|1.8125bc Jump |
|||
|2 t |
|||
|} |
|||
=== Source code === |
|||
'''from [[SourceCode:EntityLivingBase|EntityLivingBase]]''' |
|||
: <syntaxhighlight lang="java"> |
|||
/* Code unrelated to vertical movement is cut out */ |
|||
protected float getJumpUpwardsMotion(){ |
|||
return 0.42F; |
|||
} |
|||
protected void jump() |
|||
{ |
|||
this.motionY = this.getJumpUpwardsMotion(); |
|||
if (this.isPotionActive(Potion.jump)) |
|||
{ |
|||
this.motionY += (this.getActivePotionEffect(Potion.jump).getAmplifier() + 1) * 0.1F; |
|||
} |
|||
this.isAirBorne = true; |
|||
} |
|||
public void moveEntityWithHeading(float strafe, float forward) |
|||
{ |
|||
... /* also moves the player horizontally */ |
|||
this.motionY -= 0.08; |
|||
this.motionY *= 0.98; |
|||
} |
|||
public void onLivingUpdate() |
|||
{ |
|||
if (this.jumpTicks > 0) |
|||
--this.jumpTicks; |
|||
if (Math.abs(this.motionY) < 0.005D) |
|||
this.motionY = 0.0D; |
|||
if (this.isJumping) |
|||
{ |
|||
... /* different if in water or lava */ |
|||
if (this.onGround && this.jumpTicks == 0) |
|||
{ |
|||
this.jump(); |
|||
this.jumpTicks = 10; //activate autojump cooldown (0.5s) |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
this.jumpTicks = 0; //reset autojump cooldown |
|||
} |
|||
... |
|||
this.moveEntityWithHeading(this.moveStrafing, this.moveForward); |
|||
} |
|||
</syntaxhighlight> |
|||
== Horizontal Movement == |
|||
Horizontal Movement is a bit more complex than Vertical Movement, as it relies on many more factors: player actions, direction, and ground slipperiness. |
|||
On every tick, the game does these three steps: |
|||
# Acceleration is added to the player's velocity. |
|||
# The player is moved (new position = position + velocity). |
|||
# The player's velocity is reduced to simulate drag. |
|||
We'll start by introducing Multipliers in an effort to make formulas more readable. |
|||
=== Multipliers === |
|||
: '''Movement Multiplier''' (See [[45 Strafe|45° Strafe]]) |
|||
:: <math>M_{t} = \begin{Bmatrix}1.3 & \textrm{Sprinting} \\ 1.0 & \textrm{Walking}\\ 0.3 & \textrm{Sneaking}\\ 0.0 & \textrm{Stopping} \end{Bmatrix} \times \begin{Bmatrix}0.98 & \textrm{Default}\\ 1.0 & \textrm{45° Strafe} \\ 0.98 \sqrt{2} & \textrm{45° Sneak} \end{Bmatrix}</math> |
|||
: '''Effects Multiplier''' (See [[Status Effects]]) |
|||
:: <math>E_{t} = (\underset{Decreases \; by \; 15\% \; per \; level \; of \; Slowness}{\underset{Increases \; by \; 20\% \; per \; level \; of \; Speed}{\underbrace{\left ( 1 + 0.2\times Speed \right ) \: \times\: \left ( 1 - 0.15\times Slowness \right )}}} \geq 0</math> |
|||
: '''Slipperiness Multiplier''' (See [[Slipperiness]]) |
|||
:: <math>S_{t} = \begin{Bmatrix}0.6 & \textrm{Default}\\ 0.8 & \textrm{Slime}\\ 0.98& \textrm{Ice} \\ 1.0 & \textrm{Airborne} \end{Bmatrix}</math> |
|||
: |
|||
<br /> |
|||
=== Linear Formulas === |
|||
: These simplified formulas only apply to linear movement (no change in direction). |
|||
:While this condition might seem very restrictive, these formulas are very useful to analyze conventional jumps and momentum |
|||
:We'll later expand on these formulas by including angles. |
|||
:<br />'''Definition''': |
|||
:* <math>V_{H,0}</math> is the player's initial speed (default = 0). |
|||
:* <math display="inline">V_{H,t}</math> is the player's speed on tick <math display="inline">t</math>. |
|||
: '''Ground Speed''': |
|||
::<math>V_{H,t} = \underset{Momentum}{\underbrace{\underset{ }{V_{H,t-1} \times S_{t-1} \times 0.91 }}} \: + \: \underset{Acceleration}{\underbrace{0.1 \times M_{t} \times E_{t} \times \left (\frac{0.6}{S_{t}} \right )^{3}}} </math> |
|||
: '''Jump Speed''': |
|||
::<math>V_{H,t} = \underset{Momentum}{\underbrace{\underset{ }{V_{H,t-1} \times S_{t-1} \times 0.91 }}} \: + \: \underset{Acceleration}{\underbrace{0.1 \times M_{t} \times E_{t} \times \left (\frac{0.6}{S_{t}} \right )^{3}}} + \underset{Sprintjump \; Boost}{\underbrace{\begin{Bmatrix}0.2 & \textrm{Sprinting}\\ 0.0 & \textrm{Else}\end{Bmatrix} }}</math> |
|||
: '''Air Speed''': |
|||
::<math>V_{H,t} = \underset{Momentum}{\underbrace{\underset{ }{V_{H,t-1} \times S_{t-1} \times 0.91 }}} \: + \: \underset{Acceleration}{\underbrace{\underset{ }{0.02 \times M_{t}}}} </math> |
|||
=== Complete Formulas === |
|||
: Let's introduce two more variables: |
|||
:*<math display="inline"> D_{t} </math> , The player's Direction in degrees (defined by their inputs and rotation) |
|||
:* <math display="inline"> F_{t} </math> , The player's Facing in degrees (defined by their rotation only) |
|||
In reality, angles aren't as simple as that, as there are a limited number of significant angles (see [[Facing and Angles]]). |
|||
For the purpose of simplicity, we'll ignore this fact. |
|||
: '''Definition''': |
|||
:* <math display="inline">V_{X,0}</math> and <math display="inline">V_{Z,0}</math> correspond to the player's initial velocity. |
|||
:* <math display="inline">V_{X,t}</math> and <math display="inline">V_{Z,t}</math> correspond to the player's velocity on tick <math display="inline">t</math> <br /> '''Ground Velocity''': |
|||
::<math>V\displaystyle _{X,t} = \underset{ }{V\displaystyle _{X,t-1} \times S_{t-1} \times 0.91 } \: + \: 0.1 \times M_{t} \times E_{t} \times \left (\frac{0.6}{S_{t}} \right )^{3} \times \sin (D_{t}) </math> |
|||
::<math>V\displaystyle _{Z,t} = \underset{Momentum}{\underbrace{\underset{ }{V\displaystyle _{Z,t-1} \times S_{t-1} \times 0.91 }}} \: + \: \underset{Acceleration}{\underbrace{0.1 \times M_{t} \times E_{t} \times \left (\frac{0.6}{S_{t}} \right )^{3}}} \times \cos (D_{t}) </math> |
|||
: '''Jump Velocity''': |
|||
::<math>V\displaystyle _{X,t} = \underset{ }{V\displaystyle _{X,t-1} \times S_{t-1} \times 0.91 } \: + \: 0.1 \times M_{t} \times E_{t} \times \left (\frac{0.6}{S_{t}} \right )^{3} \times \sin (D_{t}) + \begin{Bmatrix} 0.2 & \textrm{Sprinting}\\ 0.0 & \textrm{Else}\end{Bmatrix} \times \sin (F_{t}) </math> |
|||
::<math>V\displaystyle _{Z,t} = \underset{Momentum}{\underbrace{\underset{ }{V\displaystyle _{Z,t-1} \times S_{t-1} \times 0.91 }}} \: + \: \underset{Acceleration}{\underbrace{0.1 \times M_{t} \times E_{t} \times \left (\frac{0.6}{S_{t}} \right )^{3}}} \times \cos (D_{t}) + \underset{Sprintjump \; Boost }{\underbrace{\begin{Bmatrix} 0.2 & \textrm{Sprinting}\\ 0.0 & \textrm{Else}\end{Bmatrix} \times \cos (F_{t})}} </math> |
|||
: '''Air Velocity''': |
|||
::<math>V\displaystyle _{X,t} = \underset{ }{V\displaystyle _{X,t-1} \times S_{t-1} \times 0.91 } \: + \: 0.02 \times M_{t} \times \sin (D_{t}) </math> |
|||
::<math>V\displaystyle _{Z,t} = \underset{Momentum}{\underbrace{\underset{ }{V\displaystyle _{Z,t-1} \times S_{t-1} \times 0.91 }}} \: + \: \underset{Acceleration}{\underbrace{\underset{}{0.02 \times M_{t}}}} \times \cos (D_{t}) </math> |
|||
=== Stopping Conditions === |
|||
: Horizontal speed is set to 0 if the player hits a wall, or if the speed is considered to be negligible. |
|||
: '''Wall Collision''': |
|||
:: If the player hits a X-facing wall, then <math display="inline">V\displaystyle _{X,t}</math> is set to 0 and the player is placed against the wall. |
|||
:: If the player hits a Z-facing wall, then <math display="inline">V\displaystyle _{Z,t}</math> is set to 0 and the player is placed against the wall. |
|||
: '''Negligible Speed Threshold''': |
|||
:: If <math display="inline"> \left | V\displaystyle _{X,t} \times S_{t} \times 0.91 \right | < 0.005 </math> , momentum is cancelled and only the acceleration is left. |
|||
:: If <math display="inline"> \left | V\displaystyle _{Z,t} \times S_{t} \times 0.91 \right | < 0.005 </math> , momentum is cancelled and only the acceleration is left. |
|||
:: In 1.9+, they are compared to 0.003 instead. |
|||
=== Source Code === |
|||
[...] |
|||
<br /> |
|||
== Non-Recursive Formulas == |
|||
Since [https://en.wikipedia.org/wiki/Arithmetico%E2%80%93geometric_sequence arithmetico-geometric sequences] have explicit formulas, we can build non-recursive formulas to calculate simple but useful results, such as the height of the player on any given tick, or the distance of a jump in terms of the initial speed and duration. |
|||
Numeric approximations are given with 6 digits of precision. |
|||
'''Definitions:''' |
|||
* <math display="inline">v_0</math> is the player's initial speed (speed on <math>t_0</math>, before jumping) |
|||
* <math display="inline">t</math> is the number of ticks considered (ex: t=12 on flat ground, see '''Jump Duration''') |
|||
*<math display="inline">J</math> is the "jump bonus" (0.3274 for sprintjump, 0.291924 for strafed sprintjump, 0.1 for 45° no-sprint jump...) |
|||
*<math display="inline">M</math> is the movement multiplier after jumping (1.3 for 45° sprint, 1.274 for normal sprint, 1.0 for no-sprint 45°...) |
|||
=== Vertical Movement (jump) [1.8] === |
|||
Vertical speed after jumping (<math>t \geq 6</math>) |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{V}_Y(t) = 4 \times 0.98^{t-5} - 3.92</math> |
|||
|} |
|||
Relative height after jumping (<math>t \geq 6</math>) |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{Y}_{rel}(t) = \underset{\textrm{jump peak}}{\underbrace{197.4 - 217 \times 0.98^5}} + 200 (0.98-0.98^{t-4}) - 3.92 (t-5)</math> |
|||
|- |
|||
|num. approx: <math>\textrm{Y}_{rel}(t) \approx 216.849187 - 216.833157 \times 0.98^t - 3.92t</math> |
|||
|} |
|||
For <math display="inline">t<6</math>, see below. |
|||
=== Vertical Movement (jump) [1.9+] === |
|||
Vertical speed after jumping (<math>t \geq 1</math>) |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{V}_Y(t) = 0.42 \times 0.98^{t-1} + 4 \times 0.98^t - 3.92</math> |
|||
|- |
|||
|num. approx: <math>\textrm{V}_Y(t) \approx 4.428571 \times 0.98^t - 3.92</math> |
|||
|} |
|||
Relative height after jumping (<math>t \geq 0</math>) |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{Y}_{rel}(t) = 217 \times (1 - 0.98^t) - 3.92 t</math> |
|||
|} |
|||
=== Horizontal Movement (instant jump) === |
|||
Assuming the player was airborne before jumping. |
|||
Horizontal speed after sprintjumping (<math>t \geq 2</math>) |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{V}_H(v_0,t) = \frac{0.02 M}{0.09} + 0.6 \times 0.91^t \times \left ( v_0 + \frac{J}{0.91} - \frac{0.02 M}{0.6 \times 0.91 \times 0.09} \right )</math> |
|||
|- |
|||
|45° sprint: <math>\textrm{V}_H(v_0,t) \approx 0.288889 + 0.6 \times 0.91^t \times \left ( v_0 - 0.169320 \right )</math> |
|||
|- |
|||
|reg. sprint: <math display="inline">\textrm{V}_H(v_0,t) \approx 0.283111 + 0.6 \times 0.91^t \times \left ( v_0 - 0.158738 \right )</math> |
|||
|} |
|||
Sprintjump distance (<math>t \geq 2</math>) |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{Dist}(v_0,t) = 1.91 v_0 + J + \frac{0.02 M}{0.09} (t-2) + \frac{0.6 \times 0.91^2}{0.09} \times (1 - 0.91^{t-2}) \times \left ( v_0 + \frac{J}{0.91} - \frac{0.02 M}{0.6 \times 0.91 \times 0.09} \right )</math> |
|||
|- |
|||
|45° sprint: <math display="inline">\textrm{Dist}(v_0,t) \approx 7.430667 v_0 + 0.288889 t -1.185138 - 6.666667 \times 0.91^t \left ( v_0 - 0.169320 \right )</math> |
|||
|- |
|||
|reg. sprint: <math display="inline">\textrm{Dist}(v_0,t) \approx 7.430667 v_0 + 0.283111 t -1.115163 - 6.666667 \times 0.91^t \left ( v_0 - 0.158738 \right )</math> |
|||
|} |
|||
'''Note:''' These formulas are accurate for most values of <math>v_0</math>, but some negative values can wind up activating the speed threshold and reset the player's speed at some point, thus rendering these formulas inaccurate. |
|||
=== Horizontal Movement (delayed jump) === |
|||
Assuming the player is on ground before jumping (at least 1 tick since landing). |
|||
Horizontal speed after sprintjumping (<math>t \geq 2</math>) |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{V}^*_H(v_0,t) = \frac{0.02 M}{0.09} + 0.6 \times 0.91^t \times \left ( 0.6 v_0 + \frac{J}{0.91} - \frac{0.02 M}{0.6 \times 0.91 \times 0.09} \right )</math> |
|||
|- |
|||
|45° sprint: <math>\textrm{V}^*_H(v_0,t) \approx 0.288889 + 0.36 \times 0.91^t \times \left ( v_0 -0.282201 \right )</math> |
|||
|- |
|||
|reg. sprint: <math display="inline">\textrm{V}^*_H(v_0,t) \approx 0.283111 + 0.36 \times 0.91^t \times \left ( v_0 - 0.264563 \right )</math> |
|||
|} |
|||
Sprintjump distance (<math>t \geq 2</math>) |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{Dist}^*(v_0,t) = 1.546 v_0 + J + \frac{0.02 M}{0.09} (t-2) + \frac{0.6 \times 0.91^2}{0.09} \times (1 - 0.91^{t-2}) \times \left ( 0.6v_0 + \frac{J}{0.91} - \frac{0.02 M}{0.6 \times 0.91 \times 0.09} \right )</math> |
|||
|- |
|||
|45° sprint: <math display="inline">\textrm{Dist}^*(v_0,t) \approx 4.8584 v_0 + 0.288889t -1.185138 + 4 \times 0.91^t (v_0 - 0.169320)</math> |
|||
|- |
|||
|reg. sprint: <math display="inline">\textrm{Dist}^*(v_0,t) \approx 4.8584 v_0 + 0.283111t -1.115163 + 4 \times 0.91^t (v_0 - 0.158738)</math> |
|||
|} |
|||
=== Advanced Formulas === |
|||
Horizontal speed after <math>n</math> consecutive sprintjumps on a momentum of period <math display="inline">T</math> (<math>n \geq 0</math>, <math>T \geq 2</math>). |
|||
If the first sprintjump is delayed, multiply <math display="inline">v_0</math> by 0.6 |
|||
{| class="wikitable" |
|||
!<math display="inline">\textrm{V}^{\,n}_H(v_0,T,n) = \left ( 0.6 \times 0.91^T \right )^n v_0 + \left ( 0.6 \times 0.91^{T-1} J + 0.02M \frac{1 - 0.91^{T-1}}{0.09} \right ) \frac{1- (0.6 \times 0.91^T)^n}{1 - 0.6 \times 0.91^T} </math> |
|||
|} |
|||
=== Examples === |
|||
*<math>Y_{rel}(60) </math> gives the relative height of the player 3 seconds (60 ticks) after jumping. |
|||
*<math>\textrm{Dist}(0,12)</math> gives the jump distance on flat ground with no initial speed. |
|||
*<math>\textrm{Dist}( V_H(0,12) ,9)</math> gives the distance of a +1 jump with one sprintjump of flat momentum as initial speed. |
|||
*<math>\textrm{Dist}(V^{10}_H(0,2), 12) </math> gives the jump distance with 10 sprintjumps of momentum under a trapdoor-headhitter. |
Latest revision as of 04:37, 19 August 2021
paragraph 1
paragraph 2
paragraph 3