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

如何用PHP配置游戏循环倒计时数据库?解决页面刷新重置问题

如何通过数据库实现全局同步的循环倒计时?

我想给游戏做一套倒计时逻辑,核心要求是所有进入页面的用户看到的倒计时数值完全同步。流程是25秒下注阶段,结束后进入10秒的中奖结果公布阶段,整个过程循环进行。现在用的JavaScript代码每次进入页面都会从25秒开始,想问怎么配置数据库来实现这种全局同步的循环倒计时?

原客户端代码:

var interval = 25000;
var interval1 = 10000;
var endTime;

function millisToMinutesAndSeconds(millis) {
    // Use floor instead of toFixed
    var seconds = Math.floor((millis % 60000) / 1000);
    return (seconds < 10 ? "0" : "") + seconds;
}

function reset() {
    // Use Date.now() instead of +new Date()
    // And create a cycle length that covers both intervals
    endTime = Date.now() + interval + interval1;
}

reset();
setInterval(function () {
    var remaining = endTime - Date.now();
    if (remaining >= 0) {
        // Adjust the time to display 
        // depending on where in the total interval we are:
        if (remaining >= interval1) remaining -= interval1;
        document.getElementById("timer").innerText =
            millisToMinutesAndSeconds(remaining);
    } else {
        reset()
    }
}, 100);

解决方案:依赖服务端数据库的全局时间基准

核心问题是你的代码完全依赖客户端本地时间,每个用户进入页面时都会从自己的本地时间开始计算,自然无法同步。要实现全局同步,必须用数据库存储一个固定的循环起始基准时间,所有客户端都基于这个基准计算当前阶段和剩余时间。

1. 数据库表设计

创建一张专门存储循环基准时间的表(以MySQL为例),只需要保存循环的初始启动时间:

CREATE TABLE game_cycle (
    id INT PRIMARY KEY AUTO_INCREMENT,
    cycle_start_time BIGINT NOT NULL COMMENT '第一轮循环的起始毫秒时间戳',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

初始化时插入一条数据,比如设置一个过去的时间点(确保循环已经在运行),或者服务端启动时用当前时间作为起始值:

-- 示例:插入2024-01-01 00:00:00的毫秒时间戳
INSERT INTO game_cycle (cycle_start_time) VALUES (1704067200000);

2. 服务端接口实现

写一个接口(比如/api/get-cycle-status),从数据库读取基准时间,用服务端的当前时间计算当前循环阶段和剩余时间,返回给客户端:

// 服务端示例(Node.js)
app.get('/api/get-cycle-status', async (req, res) => {
    const BET_DURATION = 25000;
    const RESULT_DURATION = 10000;
    const TOTAL_CYCLE = BET_DURATION + RESULT_DURATION;

    // 从数据库读取基准时间
    const cycleRecord = await db.query('SELECT cycle_start_time FROM game_cycle LIMIT 1');
    const cycleStartTime = cycleRecord[0].cycle_start_time;
    // 用服务端当前时间计算,避免客户端时间篡改
    const serverNow = Date.now();
    const elapsed = serverNow - cycleStartTime;
    const currentOffset = elapsed % TOTAL_CYCLE;

    let remainingTime, stage;
    if (currentOffset < BET_DURATION) {
        // 下注阶段
        remainingTime = BET_DURATION - currentOffset;
        stage = 'bet';
    } else {
        // 结果公布阶段
        remainingTime = TOTAL_CYCLE - currentOffset;
        stage = 'result';
    }

    res.json({ remainingTime, stage });
});

3. 客户端代码改造

客户端不再自己计算起始时间,而是从服务端获取同步状态,同时定期校准避免时间漂移:

const BET_DURATION = 25000;
const RESULT_DURATION = 10000;
const TOTAL_CYCLE = BET_DURATION + RESULT_DURATION;
let timerInterval;
let currentRemaining;

// 从服务端获取同步时间
async function fetchCycleStatus() {
    try {
        const response = await fetch('/api/get-cycle-status');
        const data = await response.json();
        currentRemaining = data.remainingTime;
        updateTimer();
        // 每5秒校准一次,抵消客户端时间偏差
        setTimeout(fetchCycleStatus, 5000);
    } catch (err) {
        console.error('同步倒计时失败:', err);
    }
}

// 更新倒计时显示
function updateTimer() {
    const seconds = Math.floor(currentRemaining / 1000);
    document.getElementById("timer").innerText = seconds < 10 ? `0${seconds}` : `${seconds}`;
    
    if (currentRemaining <= 0) {
        // 阶段结束后重新获取服务端状态
        fetchCycleStatus();
        return;
    }
    
    currentRemaining -= 100;
    timerInterval = setTimeout(updateTimer, 100);
}

// 页面加载时初始化
window.addEventListener('load', fetchCycleStatus);

4. 优化建议

  • 高并发场景下,把cycle_start_time缓存到Redis,减少数据库查询次数。
  • 禁止客户端直接修改倒计时数值,所有关键逻辑(比如下注截止判断)必须在服务端完成,避免作弊。
  • 如果需要重置整个循环,只需要更新数据库里的cycle_start_time即可,所有客户端会自动同步到新的循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:35:32