LOADING

加载过慢请开启缓存 浏览器默认开启

Revethere's Blog

分享一些超级有用的芝士

Could it be MAGIC~

『博客日志 & 大事祭』

2025/6/1

25.6.1 emm 好久好久没写博客了删了点东西就当重新开始吧 😉

25.10.11 压缩了博客的大部分图片,提高响应速度

25.11.9

  • permalinks 更新,由 :year/:month/:day/:title 转为 posts/:title
  • per_page 由每页 8 篇变为每页 5 篇文章

25.12.21 提前 R.I.P. 预计 12.28 电脑被收www

26.3.2 短暂复活,上传了部分 23 年写的文章(至于原来稀烂的排版将就看吧)

26.3.3 ☠️

MORE

『Minecraft 实体运动公式拓展推导』

理论 2025/12/14

前言

本文内容包含大量数学与物理公式,需要具备一定的数理基础阅读。

因为一些客观因素博客中的部分公式并不完全,建议下载 PDF 版本(见附件)食用更佳。

实体基本运动公式

一些必要参数及定义

  • 速度:$v_H$、$v_Y$,表示实体在水平、垂直上的速度。
  • 初始垂直速度:$v_{Y, 1}$,取决于跳跃速度或服务器垂直击退参数。
  • 方块滑度系数:$f_S$。
  • 移动乘数:$k_M$。
  • 效果乘数:$k_E$。
  • 速度阈值:$v_{th} = 0.005 \text{ m/tick}$,当实体在某条轴上的速度经衰减后小于该值时,对应轴上的速度归零,仅保留加速度(1.9 及以上版本阈值变为 $0.003 \text{ m/tick}$)。

水平运动递推公式

  • 水平地面速度公式:$$v_{H, t} = \underbrace{v_{H, t-1} \times f_{s, t-1} \times 0.91} _ \text{动量保留} + \underbrace{0.1 \times \left( \frac{0.6}{f_{s, t}}\right)^3 \times k_M \times k_E} _ \text{加速度}\tag{1.2.1}$$
  • 水平空中速度公式:$$v_{H, t} = \underbrace{v_{H, t-1} \times 0.91} _ \text{动量保留} + \underbrace{0.02 \times k_M} _\text{加速度} \tag{1.2.2}$$
  • 水平空中飞行公式:$$v_{H, t} = \underbrace{v_{H, t-1} \times 0.91} _ \text{动量保留} + \underbrace{0.05 \times k_{M-fly}}_\text{加速度} \tag{1.2.3}$$

垂直运动递推公式

  • 垂直速度公式:$$v_{Y, t} = \left( v_{Y, t-1} - \mathop{0.08} \limits_\text{重力} \right) \times \mathop{0.98}\limits_\text{阻力} \tag{1.3.1}$$

为了方便表示,后文中设公式 (1.2.1)、公式 (.2.2)、公式 (1.2.3) 中所有动量保留项的系数为 $\alpha$,加速度项为 $\beta$。公式 (1.3.1) 展开后同理。

稳态(渐进)速度推导

经典力学下的运动

$$\frac{dv}{dt} = a - fv \tag{2.1.1}$$

$$v = v_0 e^{-ft} + \frac{a}{f} (1 - e^{-ft})\tag{2.1.2}$$

$$\frac{v}{v_0} = \lim\limits_{t_0 \to 0} (1 - f t_0)^{\frac{t}{t_0}}, a = \tag{2.1.3}$$

其余见 『低版本 pvp 中玩家最优 kb 的点击频率下限分析』 中 『经典力学下的运动』小结,这里不过多阐述。

水平稳态(渐进)速度

假设实体在运动过程中所有状态不变($f_S$ 为常数),原递推式为一阶线性差分方程:$$v_t = \alpha , v_{t-1} + \beta \tag{2.2.1}$$

齐次方程 $v_t^{(h)} = \alpha v_{t-1}^{(h)}$ 的解为 $v_t^{(h)} = C \alpha^t$。由于非齐次项 $\beta$ 为常数,设其特解为 $K$,代入原方程 (2.2.1) 得:$$K = \alpha K + \beta$$

即 $K = \frac{\beta}{1 - \alpha}, \ \alpha \neq 1$,特解为:$$v_t^{(p)} = \frac{\beta}{1 - \alpha}$$

方程 (2.2.1) 的通解为齐次解与特解之和:$$v_t = C \alpha^t + \frac{\beta}{1 - \alpha}$$

当 $t = 0$:$$v_0 = C + \frac{\beta}{1 - \alpha}$$

将 $C = v_0 - \frac{\beta}{1 - \alpha}$ 代入通解得:$$v_t = \left( v_0 - \frac{\beta}{1 - \alpha} \right) \alpha^t + \frac{\beta}{1 - \alpha} = v_0 \alpha^t + \beta \frac{1 - \alpha^t}{1 - \alpha} \tag{2.2.2}$$

由于 $|\alpha| < 1$ 恒成立,该方程收敛。当 $t \to \infty$,稳态速度:$$v_{\infty} = \frac{\beta}{1 - \alpha}$$

代入 $\alpha = 0.91 f_s$ 和 $\beta = 0.1 \left( \frac{0.6}{f_s} \right)^3 k_M k_E$ 得:$$\boxed{v_{\infty} = \frac{0.1 \left( \frac{0.6}{f_s} \right)^3 k_M k_E}{1 - 0.91 f_s}} \tag{2.2.3}$$

水平飞行稳态(渐进)速度

这里提供另一种的推导方法。

已知每刻(tick)的时间长度 $\Delta t = 0.05s$,对于连续的时间 $t$ 与刻数 $n$:$$t = n \Delta t, \ v(t) \approx v_n$$

将原递推方程移项得到:$$v_n - v_{n - 1} = (\alpha - 1) v_{n - 1} + \beta$$

同时除以 $\Delta t$:$$\frac{v_n - v_{n - 1}}{\Delta t} = \frac{(\alpha - 1) v_{n - 1}}{\Delta t} + \frac{\beta}{\Delta t}$$

令:$$f = \frac{1 - \alpha}{\Delta t}, \ a = \frac{\beta}{\Delta t}$$

得到微分方程 (2.1.2),其积分因子 $\mu(t) = e^{ft}$。两边同时乘以 $\mu(t)$:

$$e^{ft} \frac{dv}{dt} + f e^{ft} v = a e^{ft}$$

$$\frac{d}{dt} \left( e^{ft} v \right) = a e^{ft}$$

对 $t$ 积分:$$e^{ft} v = \int a e^{ft} , dt = \frac{a}{f} e^{ft} + C$$

两边除以 $e^{ft}$,得到:$$v = \frac{a}{f} + C e^{-ft}$$

初始时 $v(0) = v_0$,则将常数 $C = v_0 - \frac{a}{f}$ 代入通解得到公式 (2.1.2)。当 $t \to \infty$,稳态速度:$$v_{\infty} = \frac{a}{f} = \frac{\beta}{1 - \alpha}$$

代入 $\alpha = 0.91$ 和 $\beta = 0.05 k_{M-fly}$ 得:$$\boxed{v_{\infty} = \frac{0.05 k_{M-fly}}{0.09}} \tag{2.2.4}$$

部分状态下的稳态速度

状态 $k_M$ $k_{M-fly}$ $k_E$ $f_S$ $v_{\infty} \ (\text{m/s})$
地面正常移动 $1.0 \times 0.98$ / $1.0 \times 1.0$ $0.6$ $4.317$
地面正常疾跑 $1.3 \times 0.98$ / $1.0 \times 1.0$ $0.6$ $5.612$
地面斜 $45°$ 疾跑 $1.3 \times 1.0$ / $1.0 \times 1.0$ $0.6$ $5.727$
地面正常疾跑(速度 II) $1.3 \times 0.98$ / $1.4 \times 1.0$ $0.6$ $7.857$
地面斜 $45°$ 疾跑(速度 II) $1.3 \times 1.0$ / $1.4 \times 1.0$ $0.6$ $8.018$
空中正常移动飞行 / $1$ / / $10.889$
空中正常疾跑飞行 / $2$ / / $21.778$

垂直稳态(渐进)速度

自由落体终端速度

前文的推导过程已经很详细了,因此这部分只给出结论。

根据公式 (1.3.1) 得到终端速度:$$\boxed{v_{\infty} = -3.920 \text{ m/tick} = -78.400 \text{ m/s}}\tag{2.4.1}$$

位移相关公式推导

单一方向位移与时间关系推导

位移 $s(t)$ 为前 $t$ 个速度之和:$$s(t) = \sum_{i=0}^{t-1} v_i$$

根据位移与速度关系式 (2.2.2),代入 $v_i$:$$s(t) = \sum_{i = 0}^{t - 1} \left( \alpha^i v_0 + \beta \frac{1 - \alpha^i}{1 - \alpha} \right) = v_0 \sum_{i = 0}^{t - 1} \alpha^i + \frac{\beta}{1 - \alpha} \sum_{i = 0}^{t-1} (1 - \alpha^i)$$

分别计算两个求和:

$$\sum_{i = 0}^{t-1} \alpha^i = \frac{1 - \alpha^t}{1 - \alpha}$$

$$\sum_{i = 0}^{t - 1} (1 - \alpha^i) =\sum_{i = 0}^{t - 1} 1 - \sum_{i = 0}^{t - 1} \alpha^i = t - \frac{1 - \alpha^t}{1 - \alpha}$$

即:$$s(t) = v_0 \frac{1 - \alpha^t}{1 - \alpha} + \frac{\beta}{1 - \alpha} \left( t - \frac{1 - \alpha^t}{1 - \alpha} \right)$$

整理并化简:$$\boxed{s(t) = \left( \frac{v_0}{1 - \alpha} - \frac{\beta}{(1 - \alpha)^2} \right) (1 - \alpha^t) + \frac{\beta}{1 - \alpha} t}\tag{3.1.1}$$

跳跃过程中水平与垂直位移关系函数推导

疾跑跳跃时水平速度会增加 0.2,但在这里不讨论初速度的问题。

将公式 (1.3.1) 中对应的 $\alpha$ 和 $\beta$ 代入公式 (3.1.1) 中:$$y(t) = \left( \frac{v_0}{1 - 0.98} - \frac{0.0784}{(1 - 0.98) ^ 2}\right) (1 - 0.98^t) + \frac{0.0784}{1 - 0.98} t$$

化简后得到:$$y(t) = \left( \frac{v_0}{0.98} + 4 \right) 0.98^t - 3.92$$

令 $K = \frac{v_0}{0.98} + 4,\ i = 0.98^t$:

$$y = K i - 3.92$$

则:$$i = \frac{y + 3.92}{K}$$

$$t = \log_{0.98} i = \frac{\ln i}{\ln 0.98}$$

若公式 (3.1.1) 表示水平移动的速度与时间关系,令:$$\gamma =\frac{v_0}{1 - \alpha} - \frac{\beta}{(1 - \alpha)^2},\ \delta = \frac{\beta}{1 - \alpha}$$

则:$$x(t) = \gamma (1 - \alpha^t) + \delta t \tag{3.2.1}$$

将 $\alpha^t$ 用 $i$ 表示:$$\alpha^t = e^{t \ln \alpha} = e^{\frac{\ln i \ln \alpha}{\ln 0.98}} = i^{\frac{\ln \alpha}{\ln 0.98}}$$

将 $\alpha^t$ 代入公式 (3.2.1) 得:$$x = \gamma (1 - i^{\frac{\ln \alpha}{\ln 0.98}}) + \delta \frac{\ln i}{\ln 0.98}$$

再代入 $i$:$$x = \gamma\left( 1 - \left( \frac{y + 3.92}{K} \right)^{\frac{\ln \alpha}{\ln 0.98}}\right) + \delta \frac{\ln \left(\frac{y + 3.92}{K} \right)}{\ln 0.98} \tag{3.2.2}$$

将 $\gamma = \frac{v_0}{1 - \alpha} - \frac{\beta}{(1 - \alpha)^2},\ \delta = \frac{\beta}{1 - \alpha}, \ \alpha = 0.91, \ \beta = 0.02 k_M, \ K = \frac{v_0}{0.98} + 4 $ 代入公式 (3.2.2) 得:$$x = \left( \frac{v_0}{0.09} - \frac{0.02 k_M}{0.0081} \right) \left[ 1 - \left( \frac{y + 3.92}{\frac{v_0}{0.98} + 4}\right) ^ {\frac{\ln 0.91}{\ln 0.98}} \right] + \frac{0.02 k_M}{0.09 \ln 0.98} \ln \left( \frac{y + 3.92}{\frac{v_0}{0.98} + 4} \right) $$

再略微化简一下:$$\boxed{x = \frac{100}{81}(9v_0 - 2k_M) \left[ 1 - 0.91 \left( \frac{y + 3.92}{v_0 + 3.92} \right)^ {\frac{\ln 0.91}{\ln 0.98}} \right] + \frac{2k_M}{9} \left( 1 + \log_{0.98} \left( \frac{y + 3.92}{v_0 + 3.92} \right) \right) } \tag{3.2.3}$$

附件

Minecraft 实体运动公式拓展推导.pdf

更新日志

25.12.14 $\LaTeX$ 写完 PDF 附件

25.12.21 抽空复制粘贴稍微改了一下文章同步到博客

持续更新

MORE

『低版本 pvp 中玩家最优 kb 的点击频率下限分析』

理论 2025/10/18

前言

⚠️硬核警告⚠️

英译版见『Minimum KB Click Frequency Lower Bound Analysis』.

本文包含大量数学公式和代码分析,建议具备一定理论基础阅读。

欢迎各位大佬指正🥰。

嗯……AI 帮了点小忙,还是挺好看出来的,对吧。


物理学框架下的 Minecraft 实体运动

经典力学下的运动

$$\frac{dv}{dt} = a - fv \tag{1.1.1}$$

$$v = v_0 e^{-ft} + \frac{a}{f} (1 - e^{-ft}) \tag{1.1.2}$$

$$\frac{v}{v_0} = \lim\limits_{t_0 \to 0} (1 - f t_0)^{\frac{t}{t_0}}, a = 0 \tag{1.1.3}$$

公式 (1.1.1) 描述了物体在恒定驱动力和正比于速度的阻力共同作用下,速度从变化逐渐达到稳定平衡的动态过程。这也是后续所有公式推导的基础。

公式 (1.1.2) 是通过求解公式 (1.1.1) 得到的精确解(通解)。其描述了在任何初始速度 $v_0$ 和任何驱动力 $a$ 的情况下,速度随时间变化的完整规律。

公式 (1.1.3) 则是将驱动力 $a=0$ 时的特殊情况代入公式 (1.1.2) 得到的结果。表明物体仅在阻力作用下,速度从初值 $v_0$ 开始指数衰减到零的过程。

其中,$f$ 为阻力系数。

但是,Minecraft 是以 tick(后续将称为 gt)为单位进行离散更新,即 $dt$ 和 $t_0$ 的最小值为 1gt,不能无限趋近于 0。因此这一规则在游戏中不能精确实现。

Mojang 对于实体运动的实现

以下是实体在水平和空中运动源代码简化版。已删去不必要和不相关的代码。

  • net/minecraft/entity/EntityLivingBase.java 中:

    public void moveEntityWithHeading(float strafe, float forward) {
        /**
         * 环境检测与移动类型判断
         * isInWater()、isInLava()、isFlying
         * 水、岩浆、梯子等特殊状态移动处理(else if)
         */
        
        float f4 = 0.91F; // 惯性系数
        
        if (this.onGround) {
            f4 = this.worldObj.getBlockState(
                new BlockPos(
                    MathHelper.floor_double(this.posX),
                    MathHelper.floor_double(this.getEntityBoundingBox().minY) - 1,
                    MathHelper.floor_double(this.posZ)
                )
            )
            .getBlock()
            .slipperiness * 0.91F;
        } // 获取下方方块滑度(后续将 slipperiness 称为滑度系数)
        
        float f = 0.16277136F / (f4 * f4 * f4);
        /**
         * (0.6*0.91)^3 = 0.16277136
         * 移动系数
         */
        float f5;
        
        if (this.onGround) f5 = this.getAIMoveSpeed() * f;
        /**
         * f5 = this.landMovementFactor * f;
         * landMovementFactor 基础情况下为 0.1,疾跑时*1.3,受药水效果影响
         */
        else f5 = this.jumpMovementFactor;
        /**
         * jumpMovementFactor = 0.02;
         * 疾跑时*1.3,与药水效果无关
         */
        this.moveFlying(strafe, forward, f5); // 速度计算
        
        // 重新计算 f4
        // 嗯···屎山代码这一块(
        
        this.moveEntity(this.motionX, this.motionY, this.motionZ); // 实体移动
        
        // 未加载区块重力处理
        
        this.motionY -= 0.08D; // 重力
        this.motionY *= 0.9800000190734863D; // 空气阻力
        this.motionX *= (double)f4; this.motionZ *= (double)f4; // 摩擦力(水平)
        
        // 玩家肢体动画更新
    }
    
  • 方块的滑度系数在 net/minecraft/block/Block.java 等文件中定义:

    // Block.java
    public class Block {
        // 其它方块属性
        public float slipperiness;
        public Block(Material blockMaterialIn, MapColor blockMapColorIn) {
            // 其它属性初始化
            this.slipperiness = 0.6F;
        }
    }
    
    // BlockIce.java
    public class BlockIce extends BlockBreakable {
        public BlockIce() {
            this.slipperiness = 0.98F;
        }
    } // 冰
    
    //BlockPackedIce.java
    public class BlockPackedIce extends Block {
        public BlockPackedIce() {
            this.slipperiness = 0.98F;
        }
    } // 浮冰
    
    // BlockSlime.java
    public class BlockSlime extends BlockBreakable {
        public BlockSlime() {
            this.slipperiness = 0.8F;
        }
    } // 史莱姆块
    

    滑度系数将用 $f_s$ 在后续的公式推导中来表示。

    特别地,蓝冰在 1.13 被加入,滑度为 0.989。此处仅作补充。

  • 实体在地面的移速(通过 getAIMoveSpeed() 函数返回,本质上是变量 landMovementFactor 的值)在文件 net/minecraft/entity/EntityLivingBase.java 定义:

    public abstract class EntityLivingBase extends Entity {
        private float landMovementFactor;
        public float getAIMoveSpeed() {
            return this.landMovementFactor;
        }
    }
    

    其基本值在 net/minecraft/entity/player/PlayerCapabilities.java 给出:

    public class PlayerCapabilities {
        private float walkSpeed = 0.1F;
    }
    

    疾跑状态的修饰在 net/minecraft/entity/EntityLivingBase.java 中定义:

    public abstract class EntityLivingBase extends Entity {
        private static final AttributeModifier sprintingSpeedBoostModifier = 
            (new AttributeModifier(
                sprintingSpeedBoostModifierUUID,
                "Sprinting speed boost",
                0.30000001192092896D,
                2
            )).setSaved(false);
    }
    

    疾跑速度则是通过 net/minecraft/entity/ai/attributes/ModifiableAttributeInstance.java 中的方法实现:

    private double computeValue() {
        double d0 = this.getBaseValue(); // 属性基本值获取
        
        for (AttributeModifier attributemodifier : this.func_180375_b(0)) {
            d0 += attributemodifier.getAmount();
        }
        double d1 = d0;
        for (AttributeModifier attributemodifier1 : this.func_180375_b(1)) {
            d1 += d0 * attributemodifier1.getAmount();
        }
        for (AttributeModifier attributemodifier2 : this.func_180375_b(2)) {
            d1 *= 1.0D + attributemodifier2.getAmount();
        }
        // 三种类型修饰叠加
        
        return this.genericAttribute.clampValue(d1);
    }
    

    实体在空中的移速(jumpMovementFactor)在 net/minecraft/entity/EntityLivingBase.java 中定义:

    public abstract class EntityLivingBase extends Entity {
        public float jumpMovementFactor = 0.02F;
    }
    

    疾跑时在 net/minecraft/entity/player/EntityPlayer.java 中更新:

    public abstract class EntityPlayer extends EntityLivingBase {
        public void onLivingUpdate() {
            if (this.isSprinting()) {
                this.jumpMovementFactor = (float)(
                    (double)this.jumpMovementFactor +
                    (double)this.speedInAir * 0.3D
                );
            }
        }
    }
    

    屎山代码这两种运动实现还不一样 ):

  • 实体的「motion」在 net/minecraft/entity/Entity.java 中更新:

    public void moveFlying(float strafe, float forward, float friction) {
        float f = strafe * strafe + forward * forward;
        
        if (f >= 1.0E-4F) {
            f = MathHelper.sqrt_float(f); // 模长为 1 的单位向量
            if (f < 1.0F) {
                f = 1.0F; // 避免斜向速度异常
            }
            
            f = friction / f;
            strafe = strafe * f;
            forward = forward * f;
            // 摩擦系数应用
            
            float f1 = MathHelper.sin(this.rotationYaw * (float)Math.PI / 180.0F);
            float f2 = MathHelper.cos(this.rotationYaw * (float)Math.PI / 180.0F);
            
            this.motionX += (double)(strafe * f2 - forward * f1);
            this.motionZ += (double)(forward * f2 + strafe * f1);
            // 2D 旋转矩阵
        }
    }
    

    strafeforward 变量在 net/minecraft/util/MovementInputFromOptions.java 中获取按键输入更新:

    public void updatePlayerMoveState() {
        this.moveStrafe = 0.0F;
        this.moveForward = 0.0F;
    
        if (this.gameSettings.keyBindForward.isKeyDown()) {
            ++this.moveForward;
        }
        if (this.gameSettings.keyBindBack.isKeyDown()) {
            --this.moveForward;
        }
        if (this.gameSettings.keyBindLeft.isKeyDown()) {
            ++this.moveStrafe;
        }
        if (this.gameSettings.keyBindRight.isKeyDown()) {
            --this.moveStrafe;
        }
        
        // 其它按键事件
        
        /**
         * 潜行事件
         * moveStrafe 和 moveForward 乘以 0.3
         */
    }
    

通过分析上述代码实现可以得知:

实体在水平方向上的「motion 属性」,在数值上等于当前速度向量在各坐标轴的分量乘以对应的阻力系数(垂直方向上的「motion」计算略有不同)。

若将 $t_0$ 时间内的「motion」视为平均速度 $M$,那么「motion」与阻力系数的乘积在物理意义上表示在该时间段内阻力对实体产生的冲量

实体的「motion 属性」本质上是实体运动计算过程中的中间量,仅在游戏执行 moveFlying() 函数计算后,「motion 属性」可被视为实体的速度(或该时间段内的平均速度近似值)。

线性运动公式推导

为了方便理解公式,在这里定义一些必要参数:

  • 速度:$v_H$、$v_Y$,实体在水平与垂直上的速度。
  • 初始垂直速度:$v_{Y,1}$,取决于跳跃速度或服务器垂直击退参数。
  • 滑度系数:$f_s = 0.6$(空气中不受该阻力影响)。
  • 移动乘数:$k_M = 1.3 \times 0.98 = 1.274$(停止状态下为 0)。
  • 效果乘数:$k_E = 1 \times 1 = 1$.
  • 动量阈值:$v_{th} = 0.005$,当实体在某条轴上的速度经衰减后小于该值时,对应轴上的速度归零。

由此推导得到实体运动的递推关系(主要参考 Minecraft Parkour Wiki):

  • 地面水平速度公式:$$v_{H,t} = \underbrace{v_{H,t-1} \times f_{s, t-1} \times 0.91} _ \text{动量保留} + \underbrace{0.1 \times \left( \frac{0.6}{f_{s,t}}\right)^3 \times k_M \times k_E} _ \text{加速度} \tag{1.3.1}$$

  • 空中水平速度公式:$$v_{H,t} = \underbrace{v_{H,t-1} \times 0.91} _ \text{动量保留} + \underbrace{0.02 \times k_M} _ \text{加速度} \tag{1.3.2}$$

  • 垂直速度公式:$$v_{Y,t} = ( v_{Y,t-1} - \mathop{0.08}\limits_\text{重力} ) \times \mathop{0.98}\limits_\text{阻力} \tag{1.3.3}$$

考虑到实际应用场景,上述推导中大部分系数或乘数均使用特殊值。

在后续『最优 kb 的点击频率下限分析』章节中,将加入点击行为对速度的影响机制。


鼠标点击分析

双击延迟

经测试,鼠标双击的触发延迟主要分布在 $[16, 27]\ \mathrm{ms}$ 区间范围内,受硬件性能、驱动程序、系统环境等影响,在不同的测试环境下略有差异。

若两次点击分别落在相邻的 tick 中,则称为「有效双击」。

有效双击的概率计算

设第一次点击的时间为 $T$,服从区间 $[0,50]$ 上的均匀分布:$$T \sim \mathcal{U}(0,50)$$

双击延迟为 $D$,服从区间 $[16,27]$ 上的均匀分布:$$D \sim \mathcal{U}(16,27)$$

则「有效双击」的概率:$$P(T + D \geq 50)$$

$T$ 和 $D$ 相互独立,其联合概率密度函数为:

$$f_{T,D}(t,d) = \frac{1}{50} \times \frac{1}{11} = \frac{1}{550},\ t \in [0,50],\ d \in [16,27]$$

展开积分并计算所求概率:

$$P(T + D \geq 50) = \iint\limits_{t + d \geq 50} f_{T,D}(t, d)\ dt\ dd = \int_{16}^{27} \int_{50 - d}^{50} \frac{1}{550}\ dt\ dd = \frac{473}{1100} = \frac{43}{100}$$

即「有效双击」的触发概率为 43%.

如果你不想阅读这部分略微令人头皮发麻的积分还可以通过条件期望来推导该概率:

$$P(T + D \geq 50) = P(T \geq 50 - D) = E[P(T \geq 50 - D \mid D)]$$

对于固定的 $D,\ T \sim \mathcal{U}(0, 50)$,且 $50 - D \in [23, 34] \subseteq [0, 50]$,有:

$$P(T \geq 50 - D \mid D) = \frac{50 - (50 - D)}{50} = \frac{D}{50}$$

得到:

$$P(T + D \geq 50) = E\left[\frac{D}{50}\right] = \frac{1}{50} E[D] = \frac{1}{50} \times \frac{16 + 27}{2} = \frac{43}{100}$$

与积分计算的结果一致。

🧠☠️


击退算法杂谈

原版击退算法

当玩家攻击时调用 net/minecraft/entity/player/EntityPlayer.java 文件中的 attackTargetEntityWithCurrentItem() 函数处理该过程:

public abstract class EntityPlayer extends EntityLivingBase {
    public void attackTargetEntityWithCurrentItem(Entity targetEntity) { 
        /**
         * 可攻击检查
         * 基础伤害计算
         * 附魔伤害计算
         */
        
        int i = 0;
        i = i + EnchantmentHelper.getKnockbackModifier(this);
        if (this.isSprinting()) {
            ++i;
        }
        // 击退效果计算
             
        /** 
         * 伤害有效性检查
         * 暴击判断
         * 火焰附加
         */
        
        double d0 = targetEntity.motionX;
        double d1 = targetEntity.motionY;
        double d2 = targetEntity.motionZ;
        boolean flag2 = targetEntity.attackEntityFrom(DamageSource.causePlayerDamage(this), f);
        // 伤害应用
        
        if (flag2) {
            if (i > 0) {
                targetEntity.addVelocity(
                    (double)(-MathHelper.sin(
                            this.rotationYaw * (float)Math.PI / 180.0F) * (float)i * 0.5F),
                            0.1D,
                    (double)(MathHelper.cos(
                            this.rotationYaw * (float)Math.PI / 180.0F) * (float)i * 0.5F)
                    ); // 第二阶段击退计算
                
                this.motionX *= 0.6D;
                this.motionZ *= 0.6D;
                this.setSprinting(false);
                // 攻击者减速并取消疾跑状态
            }
            
            if (targetEntity instanceof EntityPlayerMP && targetEntity.velocityChanged) {
                ((EntityPlayerMP)targetEntity).playerNetServerHandler.sendPacket(
                    new S12PacketEntityVelocity(targetEntity)
                );
                targetEntity.velocityChanged = false;
                targetEntity.motionX = d0;
                targetEntity.motionY = d1;
                targetEntity.motionZ = d2;
            } // 避免重复叠加击退
        
        /**
         * 伤害成功后续处理
         * 攻击失败处理
         */
    }
}
// net/minecraft/entity/EntityLivingBase.java
public abstract class EntityLivingBase extends Entity {
    public boolean attackEntityFrom(DamageSource source, float amount) {
        /**
         * 检查实体是否对特定伤害源免疫
         * 客户端检查
         * 死亡检查
         * 特殊伤害免疫(抗火)
         * 装备减伤
         * 伤害刻(特别地,该时间段内更高的伤害会覆盖原有伤害)
         * 攻击者判断
         * 视觉更新(伤害动画)
         */
    
        double d1 = entity.posX - this.posX;
        double d0;
        for(d0 = entity.posZ - this.posZ;
            d1 * d1 + d0 * d0 < 1.0E-4D;
            d0 = (Math.random() - Math.random()) * 0.01D) {
            d1 = (Math.random() - Math.random()) * 0.01D;
        } // 距离过近的随机击退

        this.attackedAtYaw = (float)(
            MathHelper.atan2(d0, d1) * 180.0D / Math.PI 
            - (double)this.rotationYaw
        );
        
        this.knockBack(entity, amount, d1, d0);  // 执行击退
        
        // 其它操作
    }
    
    public void knockBack(Entity entityIn, float amount, double d0, double d1) {
        if (this.rand.nextDouble() >= this.getEntityAttribute(
            SharedMonsterAttributes.knockbackResistance).getAttributeValue()) {
            this.isAirBorne = true;
            float f = MathHelper.sqrt_double(d0 * d0 + d1 * d1);
            float f1 = 0.4F;

            this.motionX /= 2.0D;
            this.motionY /= 2.0D;
            this.motionZ /= 2.0D;
            // 受击者速度衰减

            this.motionX -= d0 / (double)f * (double)f1;
            this.motionY += (double)f1;
            this.motionZ -= d1 / (double)f * (double)f1;
            // 第一阶段击退计算

            if (this.motionY > 0.4000000059604645D) {
                this.motionY = 0.4000000059604645D;
            } // 垂直击退上限
        }
    }
}
// net/minecraft/entity/Entity.java
public abstract class Entity implements ICommandSender {
    protected void setBeenAttacked() {
        this.velocityChanged = true;
    }
    public boolean attackEntityFrom(DamageSource source, float amount) {
        if (this.isEntityInvulnerable(source)) {
            return false;
        } else {
            this.setBeenAttacked();
            return false;
        }
    }
}

为了更清晰地理解击退机制,在这里定义以下参数:

  • horizontal:基础水平击退。对应 knockBack() 函数中的 f1 变量,默认值为 0.4
  • vertical:基础垂直击退。其数值与基础水平击退相同,为 0.4
  • horizontalExtra:额外水平击退。仅考虑疾跑的因素,即 i = 1,值为 0.5
  • verticalExtra:额外垂直击退。addVelocity() 函数中的叠加固定额外垂直击退,默认值为 0.1
  • verticalLimit:垂直击退上限。motionY 的最大值 0.4
  • friction:暂无合适的译法。表示玩家受击时各轴的速度衰减(区别于方块的 friction),默认值为 2.0

基于上述代码分析可知玩家受到的击退效果主要分为两个阶段:

  • 击退的第一阶段:仅与双方在 XZ 轴上的相对位置相关。
  • 击退的第二阶段:仅与攻击者的偏航角(yaw)和攻击者的状态(本文只考虑疾跑)相关。

MMC 击退算法

本小节重点讨论与原版击退算法不同之处。

详细实现见 How MMC Knockback Actually Works.

MMC 引入了以下新的或修改的参数:

totalHorizontal = 0.8835d    // 总水平击退
totalVertical = 0.9055d      // 总垂直击退
rangeFactor = 0.035d         // 距离影响系数
maxReduction = 0.4d          // 最大距离减免
startRange = 3.0d            // 距离减免起始计算距离
idleReduction = 0.6d         // 基础击退倍率
attackBuffer = 1             // 攻击缓存

// 计算后的实际值
horizontal = totalHorizontal * idleReduction             // 基础水平击退
horizontalExtra = totalHorizontal * (1 - idleReduction)  // 额外水平击退
vertical = totalVertical * 0.4d                          // 基础垂直击退
verticalExtra = 0.0d                                     // 额外垂直击退
verticalLimit = 0.4d                                     // 垂直击退上限
attackerSlowdown = 0.6d
friction = 0.0d

不难看出:

  • idleReduction 决定了基础水平击退和额外水平击退的大小,并与 totalHorizontal 的值紧密相关。
  • verticalExtra 的值归零,即玩家的垂直击退固定。
  • attackBuffer 提供伤害刻结束前的攻击窗口。
  • 增加了 rangeFactormaxReductionstartRange 参数用于减免由于延迟造成的远距离攻击注册的击退。

特别地,当 friction = 0.0 时,受击者的动量归零,即击退完全覆盖原速度。

第一阶段击退算法:

void firstStage(EntityLiving attacker, EntityLiving victim) {
    // 省略部分伪代码
    
    double distance = Math.sqrt(distanceX * distanceX + distanceZ * distanceZ);
    double rangeReduction = calculateRangeReduction(distance)
    double modifiedHorizontal = horizontal - rangeReduction // 远距离击退衰减
    
    double magnitude = Math.sqrt(distanceX * distanceX + distanceZ * distanceZ)
    
    victim.motX -= (distanceX / magnitude) * (modifiedHorizontal * 0.5d)
    victim.motZ -= (distanceZ / magnitude) * (modifiedHorizontal * 0.5d)
    
    double yaw = Math.toRadians(attacker.yaw)
    victim.motX += -Math.sin(yaw) * (modifiedHorizontal * 0.5d)
    victim.motZ += Math.cos(yaw) * (modifiedHorizontal * 0.5d)
}

与原版不同的是,MMC 算法中第一阶段的击退同时与玩家的相对位置和攻击者的偏航角相关(占比各 50%)。并增加了 calculateRangeReduction() 函数用于减免远距离击退。

第二阶段击退算法与第一阶段相似:

void secondStage(EntityLiving attacker, EntityLiving victim, int knockbackEnchantLevel) {
    // 省略部分伪代码
    
    if (extraKBMult > 0) {
        double distanceX = attacker.locX - victim.locX
        double distanceZ = attacker.locZ - victim.locZ
        double distance = Math.sqrt(distanceX * distanceX + distanceZ * distanceZ)
        double modifiedExtraHorizontal = horizontalExtra * extraKBMult // 额外击退
        
        double magnitude = Math.sqrt(distanceX * distanceX + distanceZ * distanceZ)
        
        victim.motX -= (distanceX / magnitude) * (modifiedExtraHorizontal * 0.5d)
        victim.motZ -= (distanceZ / magnitude) * (modifiedExtraHorizontal * 0.5d)
        
        double yaw = Math.toRadians(attacker.yaw)  
        victim.motX += -Math.sin(yaw) * (modifiedExtraHorizontal * 0.5d)
        victim.motZ += Math.cos(yaw) * (modifiedExtraHorizontal * 0.5d)
    }
}

额外水平击退由 horizontalExtra 参数和 extraKBMult 共同决定。并保持与第一阶段相同的 50/50 分配。


最优 kb 的点击频率下限分析


一起来品鉴赤石 Mojang 的代码


参考资料

运动公式 - Minecraft Parkour Wiki

How MMC Knockback Actually Works

对我的世界中PVP击退的研究报告 - LSeng, CarmJos

关于修正并改进 xwj 的 MC 实体运动公式 —— 适用于MC中所有实体 - Bio-Hazard

Minecraft 实体运动研究与应用 - lovexyn0827

The ULTIMATE Guide to PING - sceyna

MCP-919 ( Fully decompiled )

NachoSpigot

致谢

蔚蓝天空Azure_Sky

时代地产

附件

更新日志

25.11.30 - 发布已基本写完的三章

MORE

『这个 mod 将重新定义视频录制...』

介绍 2025/9/28

前言

之前写过一篇『录制 & 渲染配置分享(OBS & Blur)』

后来调录制参数一直没调好过(

120fps 下的素材跑 blur 之后就会变得非常非常糊 🤬,但是提高帧速率会带来更高的占用、游戏的卡顿以及可能卡炸的素材

很难去找到一个平衡点

Lunar 最近更新的新模组 Rewind,一定程度上解决了上述的问题:

HOW TO USE REWIND ON LUNAR CLIENT

Lunar Client | Introducing Rewind

不要在意上面这张图左上角的 logo 为什么这么奇怪,扒不到高清的图拿 AI 跑的超清像素

Rewind 简介

Rewind 是一款功能全面的剪辑、录制和编辑软件,并完全集成于 Lunar Client。无需任何外部软件即可录制 Minecraft 游戏内容

Rewind 提供广泛的功能。与大多数编辑软件一样,可以导入视频媒体,并进行组织和修剪。该 mod 专为 Minecraft 和 Lunar Client 量身定制

如何导出

Rewind 设置

启动界面进入 Rewind Editor:

选择你刚才的 Recording,创建项目

分辨率(Resolution)建议选择你玩游戏时的分辨率,不然 ui 大小会变,非常难受 ):):):

帧率(framerate)建议直接拉满,毕竟后续还要变速

进入后在 Properties 功能区中将 Speed 选项拉到 0.25(根据情况而定,拉的越低后续渲染会更舒服,但是导出时间也会更长)

时间对比

电脑配置:

  • CPU : Intel(R) Core(TM) Ultra 9 285H
  • GPU : NVIDIA GeForce RTX 5080 Laptop GPU

开启性能模式

相同 15s 素材,1440p

时间线帧率 慢放倍数 时间
120fps 0.2 1 : 42
240fps 0.4 1 : 38
240fps 0.25 2 : 55

120fps 与 240fps 导出时间的误差可以忽略不计

Blur 设置

output timescale 根据你原素材慢放倍数进行调整

注意需要一条没有变速的素材的音频轨道

动态模糊渲染对比

左 960 -> 60,右 600 -> 60

渲染效果 Render Test #7 ( Recorded by Rewind ) - Revethere

其它功能

自己摸索摸索吧,这次更新的这个 mod 真的挺好 $\phantom{其实是懒(}$

甚至能做绿幕❗

MORE

『sumo 打法教学 & 浅层理论分析 & 心理博弈』

教程 2025/8/7

阅读文章前,你需要知道的…

  • 文章中所有的定义(以及一些生僻概念)仅为了规范与统一文章的内容,不代表圈内叫法👌🏼

  • 文章中所有涉及的操作均通过 dbc 点击方式实现,同时您也需要熟练使用间隔点

  • 大部分技巧讲简述原理,少数从底层机制分析

  • 部分技巧因适用于多个场景会重复出现

  • 为了方便表示,大部分 click 都用单数

  • gt(game tick)和 tick 是一样的,文中没有统一叫法

  • 原本想试试图文的但是图片太难做了,受限于样式这种做视频其实会好点

本文内容仅代表个人观点❗❗❗

Early Game - 基本技巧原理简述 & 部分技巧的细分与重定义

基本技巧

  • wtap / 重置疾跑

    很早以前刷视频说分为进攻型 wtap 和防守型 wtap,但在这里不作区别(因为我觉得没区别😶‍🌫️)

    需注意:wtap 在增大对方的 kb 同时由于自己松开 w 的间隙导致在击退的过程中向前的移动量减少(可以理解为自己的 kb 也会变大),因此不要一味地叠 wtap,根据情况 hold w 也可以获得非常优秀的 kb

  • stap

    分为 s-tap 和 ws-tap,s-tap 是松开 w 按 s(会有较明显的后退),ws-tap 则是 hold w 并 tap s(有点类似急停)

    s-tap 适用于完全预判对手 hitselect,ws-tap 则相对保守,更多见『End Game』章节

    据说打的时候下落阶段按 s 可以更快下落但是我真没研究明白(按理来说不应该啊

  • hitselect ( hs )

    分为 light hs 和 hard hs,在这里将 light hs 定义为玩家收到上升 kb 的时间内(大约达到最大高度的 60% ~ 80%)进行 hs,hard hs 则是在上述时间之后到下次受到击退前

    建议在距离 3.5blocks 的时候开始点击,这样你就会在攻击被注册之前受到击退,wtap 的节奏会好把控一点

    先手也没关系,只要对方不是长后手第二下 trade 回来就没问题

    hard hs 一般称为长后手,更适合打一个出其不意

  • midtrade ( mt )

    典中典啊,可以说这个技巧是 sumo 的必修课

    在这里定义玩家进行 midtrade 时上次结束到下次攻击被注册为一个 trade

    同样分为 light mt 和 hard mt,对于时机的区别与上述 hs 的相同。light mt 对于较依赖 wtap 节奏的玩家作用不言而喻(主要为了保持对刀节奏),hard mt 的作用则与 hard hs 相似

    掌握 midtrade 需大量练习,难以言传,多打即可 o.O

    关于 mt 时机及更多 mt 相关技巧详见『Early Game』- 『衍生技巧』与『End Game』-『mt 节奏』章节

  • jumpreset ( jr )

    虽然这是作为萌新相较于 wtap 更先听说的技巧,但对于我来说 jr 更贴近被动技巧。一般是用来脱离 combo,或是拥有良好 timing 把控在 mt 被创飞的一瞬间 jr 重置 kb 继续对刀(被创飞的第一刀落地再 tap space会有较高的成功率)

    当然也有将其作为主要技巧的且打得也非常厉害的玩家,至少我不行(

  • run

    是的,就是当 runner

    不过也需要注意一下与台边的距离别逃的时候掉了

    建议是在与台边比较远的时候被 combo 再逃,一般距离还是 jr 算了

    不过我个人认为哪怕离台边较远也不适合 run

  • strafe

    很多 sumo 玩家往往专注与去拼体重而忘记了走位发挥的作用。除了偏移击退以外,还可以干扰瞄准减少对方注册的点击

    一般建议在距离对方 3.5blocks 的时候走位或是贴近后在自己受到击退前开始走位

    很恶心

衍生技巧(后续应该会补很多)

  • 负 kb

    仅仅依靠间隔点实现的极小 kb + 间隔期间(相对更多)向前的位移实现的负 kb

    一般适用于对方 wtap 频率不高,或者一直卡 3blocks 的对刀有一定的效果

  • mt 偏移

    指在玩家之间相互 midtrade 的间隙通过走位干扰对方瞄准并在下次攻击时改变对方击退方向,一般是在本次攻击之后玩家之间距离拉近或是穿身时使用(这个就需要多打打判断了)

    尤其是在 boxing 模式中瞄准难度加大容易被 combo

  • 移动修正

    不知道取个什么名字暂且这样叫吧

    这个技巧归类到心里博弈会好点,这里单独提一下稍微有点累赘但是问题不大。

    在玩家之间相互 midtrade 时判断本次攻击之后会穿身因此在本次攻击时松开 w 或按下 s 并在对方的攻击注册后重新 wtap(在平台边缘并且处于优势位置效果最佳,但如果没处理好穿身自己就会被创飞了)

    一般对方会以为穿身往后瞄准(但事实上并没有)被创下台或者进入 combo,另一种就是避免自己进入劣势局面

    当然这个也一定程度上能够反制

  • midtrade 反制(mt cm)

    不会。

    会了再补 o.O

    其实也不算完全会

    反制手段要么就是 trade 回去,相互保持 trade(对于不会直接创下台的情况);或者是 spam click(trade 节奏较长的时候)

    那什么高低位,不懂(

    sumo 的尽头是抓对面失误

  • air jump

    非常猎奇的我觉得应该不能称之为技巧的技巧,我一般对其解释为在服务端玩家被判定为 onGround 但在客户端玩家视角是在空中进行跳跃重置。非常有用,但是很吃 timing(似乎 1.8 更容易触发?)

    mmc 这个赛季(Season 9) air jump 触发的手感挺奇怪的,tap space 到触发 air jump 之间有延迟而且成功概率挺大,感觉 combo 时只要 3combos 没问题基本对面逃不了

  • backtrack

    此 backtrack 非彼此 backtrack,其实就是 misplace

    当你和对手的 ping 处于一个暧昧的关系时,你 / 对手会莫名其妙在推开之后老远再摸到一刀

    总之当你能触发就能恶心对面,对面触发容易被打红温(

    而且一旦能够触发那大概率一长段时间内都能恶心对面(

    😱

关于 dbc 间隔点

将两指分别敲击一次鼠标(一般为 4cps)的操作称为 1tc;一般地,8cps 间隔点简称为 2tc,12cps 为 3tc

这只是一种叫法,与有没有触发双倍点无关

如果能够做到在短时间内的 4tc 点击,那你的 kb 将会进化到下一个 level

2tc 和 3tc 的点击建议放长一点,不然点击之间间隙太大容易创飞

一般来说对于主流服务器的水平击退参数只要 4clicks(1click / tick)并按住 w 就能抵消击退,在加上一些容错的话 2tc 在大部分情况下够用

一些奇妙的想法

  • (不太合法的)减 kb 的新思路

    一些助于理解的理论补充见这里

    若不考虑击退刻的问题,假设玩家的伤害刻时长为 20tick(当然实际情况不是这样)

    对于分布均匀的 dbc 20cps,放到时间轴上大概长这样(左键可放大):

    玩家的 double click 每次只落在了一个 gt 上

    其 motion 受到阻力作用的时间(只考虑点击阻力)只有 10gt

    如果将点击偏移一下(大概半个 gt 左右):

    double click 的第一下落在上一 gt 末,第二下落在下一 gt 的开始,两次 click 分别落在了两个 gt 上。这样玩家在 1s(20gt)内都能受到阻力的作用

    恭喜你成为了胖子🥳

    当然在现实中你的点击肯定不会这么均匀

    真实的点击大概长这样:

    注意到 16cps 时受到阻力作用的时间只有 8gt(情况好点可以到 9gt)

    20cps 基本可以稳定 10gt(同样,情况好点能到 11gt 或更多)

    24cps(在上述片段中)阻力作用时间为 13gt(实际情况下应该是在 12gt 到 14gt 之间)

    显然,16cps 的体重与 24cps 的体重完全不在一个水平线上

    但我们讨论的重点不在这里,而是:

    我们是否能写一个 mod,在客户端接收到 double click 时候,自动将点击修正到两个 2gt 之间?

    虽然说 Minecraft 每秒只有 20gt,也就是说我们的修正操作只能按 gt 进行。但是我们完全可以判断当前 gt 是否存在 double click,若存在则将 double click 的第二下在下一 gt 开始的时候发包出去(我这里写的可能不是很清楚,我没做过 mod,客户端与服务端之间的通信了解的也不多,这里只是提供一个思路,不保证完全可以实现

    修正后的点击:

    但是修正后点击太均匀可能会触发反作弊检测(再塞个随机算法)

    注意在模拟的 24cps 点击图中第 6gt 末的点击是在第 7gt 才触发。最后一个 gt 中较后的点击将会移到下一秒(即在点击之后处理)

    逻辑有点乱,大概思路是这样

Mid Game - 从长久计的打法习惯养

关于默认打法

毫无疑问有一个默认打法然后基于此打法进行衍生是极其重要的(听君一席话,如听一席话😶‍🌫️

建议你的默认打法满足以下几点:

  1. 尽可能地简洁
  2. 对于第一刀有针对性优化(不管先后手都能保证一定的优势)
  3. 适合长时间 queue(点击优化)

比如我现在的默认打法就是接近时(大于 3blocks)开始点击(3tc),如果是先手第二下 mt,之后的对刀 wtap + 2tc / 3tc(根据情况交替)

当然这只是一个参考,第一刀同样可以 wstap 进行试探再根据对手打法调整

特定场景下的打法优化 & 实例分析(或许会有图文)

阅前提醒:对于「特定场景」显然无法全覆盖,所以在这里仅举例一些(或许算是)典型的场景(慢慢填)

  • 在默认打法下,对方比自己重(kb 相对较小),且无其它转换先后手的技巧(或此类技巧极少)

    增加间隔点频率,尽可能多的 3tc 点击,在保证自己 kb 不会乱飘的同时适当增加 3tc 点击密度(尽量保持 3tc 本身的点击次数)

    根据距离选择性 wtap,离得近就 wtap 增加对方受到的 kb,反之亦然

  • 对手打法上总体偏向后手,先手刀较少

    尝试比对面更长的后手(出其不意的后手),预判后手穿身或者 stap。在 kb 上势均力敌那就抓推开后第一刀的失误

    面对这类玩家第一刀十分重要

  • 对手点击间隙较短(或大部分是 spam click),不要尝试放长 hs 或是长 mt,因为在第三刀后你大概率会莫名其妙空刀然后被推飞

    慢节奏的 3tc 或 4tc 的点击去拼 kb 就行,spam click 的体重一般是拼不过间隔点的

  • 面对 lowping 的对手一定要 first hit + spam click,不然那距离太抽象了

  • 如果对方开局就是 wa 或者 wd 那大概率是短后手(ping 也是要考虑的因素),wstap + spam click 基本可以保证开局不被推飞,并且能够在接近 3blocks 的距离下有较好的先后手转换容错

    如果对方是接近时 strafe 那就顺着对方的方向按 a / d,预判错了页面也没关系,spam click 可以保证第二下不会推太远

  • 如果感觉对面的 kb 突然变小或是垂直 kb 突然变高那大概可以推断对方 jr,可以尝试放短 mt

  • 对方特别重并且 holdw 能够获得负 kb,可以 wtap 硬推或者对刀按 ad 飘对面

  • 关于 mt 技巧的推测见下一 part 『End Game』-『mt 节奏』

一些畸形打法

  • only hs

    几乎每一刀都是 hs,这对于稍微有些经验的对手很容易识别并 stap 反制

  • 预判型 jr

    此处指的是将 jr 作为主要技巧并且预判 jr 的占比比较大的玩家

    mt 预判失败直接就飞了

  • pinger ( over 130ms )

    在有加速 ip 或者加速器的情况下请不要用高 ping 玩❗❗❗虽然高延迟玩的少但是据我了解第一刀打法主要就是侧身 + 长 hs 很容易反制,同时这样的 ping 在对刀中节奏非常不好把控

    130ms 左右的延迟都还算可以接受(比如 boxing 圈有 BBDL 这样非常强势的 130ms 玩家),再高真的不行了

    其实 90ms 以上的延迟打起来就已经很难受了

    更多关于延迟的讲解见下一部分『关于延迟』

  • trader

    对刀严重依赖 mt,具体表现为每一刀的攻击节奏慢于正常节奏 $\phantom{比如某个lowA Tier}$

    很难说这个习惯是好是坏,trade 节奏不好很容易失误(但是又很难定义「不好的 trade 节奏」,大概就是你和对面相互 trade 但是先后手基本没变或是同时,然后你 spam click 不再 trade 拼几刀后对面会被推走,对面就是「不好的 trade 节奏」)

    瞄准不好的话被对面 mt 偏移直接被创飞

关于延迟

有空再填这个坑(🤐

The ULTIMATE Guide to PING - sceyna

现在好讨厌打 lowping 的对局,尤其是在 wihar,小的 kb 拼不过,技巧在 lowping 的作用很小😕 $\phantom{kb 还很猎奇}$

但是 wihar 新赛季(Season 4)的水平 kb 好像变小了,可以直接推了(

End Game - 心理博弈

如何心平气和地打 ranked sumo

众所周知 ranked sumo 是 ft3,因此在第一局中判断对手打法以及在比分 2 : 2 时稳定心态十分重要

如何心平气和地打 ranked sumo如何快速破防红温💀:

  • 被黑客飘

  • 吃满 misplace / 延迟刀

  • 遇上 elo 核弹

  • 开局预判对手先后手失败直接创飞,0 : 1(微红❗

    开局预判对手先后手失败直接创飞,2 : 2(破防❗❗

    开局预判对手先后手失败直接创飞,2 : 3(虾波❗❗❗

    🤬🤬🤬

但是说真的,ranked 打多了还真不太容易被整红温😗

建议整个不在意数据的小号打打

嗯很好地水了一小章

mt 节奏

根据对手的习惯一般分为两类 trade 节奏:持续性 trade 和反 trade

  • 持续性 trade 节奏

    双方保持相互 trade,即很少情况 spam click 转变对刀节奏

    经典的反制手段是在三次 trade 后 spam click 加快对刀节奏,对手点击间隔长的话会直接被创飞(更多时候需要根据 trade 间隔时间判断)

    另一种是叠 4tc 点击拼体重(对于体重较重的)

  • 反 trade 节奏

    本质上是对手为了转变先后手而进行 mt,可以理解为间歇性 mt

    要么就是你 trade 一下我 trade 一下看谁先失误

    要么就让着对面后手拼体重

    最好的办法是推开之后抓第一刀失误

其它博弈

待补

其它

观赏性 sumo

在高手玩家对局中想要得到以下两类观赏性的 sumo clip 几乎不可能(偏向于技巧上的观赏,但是对于圈外显然无法 get 到其观赏性),所以更多会是演员或者有点技术但不多的小趴菜 o.O

不保证说法完全正确,大概意思没问题就行(

  • circle combo ( + style )

    关于环绕 combo,国外有非常高质的创作者,见 iusehuzuni 的频道(这家伙一年没更新了www~)

    combo style 则是在环绕 combo 的过程中进行 style,大致可以理解为 boxing style,但相比于 boxing style,sumo 的 style 对瞄准、控距要求更高,节奏也与 boxing 差异很大

  • trade style

    在对刀中的 style,对瞄准及注册到的点击要求较高(此处注册到的点击指的是你的 hits 注册到实体的数量),需要对方较低的 wtap 率和几乎没有的技巧

    特别适合跟那些没脑子的 ac 晃悠

建议在尝试观赏性 sumo 之前,多打打 boxing,当你的 boxing style 观赏性足够高的时候 sumo 的观赏性也不会差🥰

国内目前几乎没有观赏性较高的 sumo 玩家,尤其是 trade style。嗯对除了我 QAQ

部分圈内玩家打法分析(不代表最新)

原本是想把这个放到打法优化那个 part 写的,在这里单独列出来

很久以后再补吧 QAQ - 25.10

嗯很久很久以后再补吧 QAQ - 26.4.4

一些奇妙的东西

HitDelayFixMod

MouseDelayFix

Weave Manager

Weave Mod

更新日志

25.10.6 -(主体)完结撒花🥰🥳🎉

26.4.4 - 修正 / 删除了部分理论,补充 / 添加了一些不知道有没有用的内容,删掉了参考资料(因为根本没用上😗)

MORE
avatar
Revethere₂₀₂₄

INTP-A
好想谈恋爱😳