如何用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
相关产品推荐
相关产品推荐

