You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现轮盘(幸运大转盘)的平滑减速调度

实现幸运大转盘的平滑减速效果

我明白你现在的痛点——分段配置tick-duration虽然能实现减速,但每段之间的转速突变太明显,体验很生硬。咱们可以用连续的数学缓动函数来替代分段配置,让轮盘的转速随着转动次数增加自然、平滑地降低,完全没有突兀的变化。

核心思路

我们的目标是:从第0次转动到第maxRuns次转动,让轮盘的转动间隔(也就是你的tick-duration)从最快的50ms(对应tick-duration=1)平滑增加到一个最慢间隔(比如500ms,对应tick-duration=10)。这里推荐用**二次缓出(Ease Out Quad)**函数,它的特点是前期减速平缓,后期减速越来越快,完美贴合现实中转盘的物理减速规律。

对应的计算公式很简单:

// 计算当前转动进度(0到1之间)
double progress = runs / (double) runData.getMaxRuns();
// 二次缓出处理,让后期减速更明显
double easedProgress = Math.pow(progress, 2);
// 计算当前的tick-duration,从MIN到MAX平滑过渡
int currentTickDuration = MIN_TICK_DURATION + (int) Math.round((MAX_TICK_DURATION - MIN_TICK_DURATION) * easedProgress);

其中:

  • MIN_TICK_DURATION:最快转速对应的间隔次数,设为1(对应每50ms转一次)
  • MAX_TICK_DURATION:最慢转速对应的间隔次数,你可以根据需求调整(比如10就是500ms转一次)
  • runs:当前已经完成的转动次数

修改后的完整代码

我帮你重构了原来的HologramWheelTask,去掉了生硬的分段查找逻辑,换成了平滑的数学计算:

package com.dbsoftwares.dangerwheel.wheel.hologram;

import com.dbsoftwares.dangerwheel.utils.objects.CircleColor;
import com.dbsoftwares.dangerwheel.utils.objects.WheelRunData;
import com.dbsoftwares.dangerwheel.wheel.WheelCircle;
import com.dbsoftwares.dangerwheel.wheel.WheelManager;
import com.gmail.filoghost.holographicdisplays.api.Hologram;
import lombok.RequiredArgsConstructor;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.List;

@RequiredArgsConstructor
public class HologramWheelTask extends BukkitRunnable {
    private final WheelManager manager;
    private final Hologram hologram;
    private final WheelCircle circle;
    private final WheelRunData runData;
    private final int startIdx;

    private int ticks = 0;
    private int runs = 0;

    // 可配置的减速参数:建议放到WheelRunData里让外部配置
    private static final int MIN_TICK_DURATION = 1; // 最快:每50ms转动一次
    private static final int MAX_TICK_DURATION = 10; // 最慢:每500ms转动一次

    @Override
    public void run() {
        final int currentTickDuration = calculateCurrentTickDuration();
        
        if (ticks < currentTickDuration) {
            ticks++;
            return;
        }
        ticks = 0;
        runs++;
        
        // 执行轮盘转动的核心逻辑(更新全息显示等)
        updateWheelDisplay();
        
        if (runs >= runData.getMaxRuns()) {
            cancel();
            // 这里可以添加轮盘停止后的逻辑,比如触发奖励、通知玩家等
        }
    }

    private int calculateCurrentTickDuration() {
        final int maxRuns = runData.getMaxRuns();
        if (maxRuns == 0) {
            return MIN_TICK_DURATION;
        }
        
        // 二次缓出公式,实现平滑减速
        final double progress = runs / (double) maxRuns;
        final double easedProgress = Math.pow(progress, 2);
        
        // 计算当前的tick间隔,取整保证整数类型
        return MIN_TICK_DURATION + (int) Math.round((MAX_TICK_DURATION - MIN_TICK_DURATION) * easedProgress);
    }

    private void updateWheelDisplay() {
        // 根据当前转动次数更新全息显示的内容
        final List<CircleColor> currentColors = circle.getColorsForRotation(startIdx + runs);
        hologram.clearLines();
        hologram.appendTextLine(buildLine(currentColors));
    }

    private String buildLine(final List<CircleColor> colors) {
        final StringBuilder line = new StringBuilder();
        colors.forEach(color -> line.append(color.getAsText()));
        return line.toString();
    }
}

关键改进说明

  1. 去掉生硬的分段逻辑:不再需要WheelRun的分段配置,用一行数学计算就能实现完全平滑的减速曲线
  2. 缓动函数可选:如果你觉得二次缓出的效果不符合预期,可以换其他缓动函数:
    • 线性缓动:easedProgress = progress,减速匀速,效果比较平淡
    • 三次缓出:Math.pow(progress, 3),后期减速比二次更明显
    • 对数缓动:1 - Math.log10(9*progress +1)/Math.log10(10),前期几乎不减速,后期快速减速
  3. 可配置化:把MIN_TICK_DURATION和MAX_TICK_DURATION移到WheelRunData中,让你可以在外部配置不同的减速参数,适配不同场景
  4. 代码更简洁高效:原来的流式查找逻辑被替换成简单的数学运算,性能更好,也更容易维护

额外优化提示

如果想要更贴近真实物理的转盘效果,可以考虑加入目标位置校准:比如计算出需要转动到目标位置的准确次数,然后调整减速曲线,确保最终刚好停在正确的位置,而不是严格按照maxRuns停止(这需要额外的逻辑来计算目标位置和剩余转动次数)。

内容的提问来源于stack exchange,提问作者Dieter Blancke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:00:27