在 Manus 中运行任何 Skill
一键导入
一键导入
一键在 Manus 中运行任何 Skill
开始使用game-loop
Server-side game loop implementation with fixed timestep, physics simulation, and tick rate optimization
星标1
分支1
更新时间2025年12月30日 11:46
文件资源管理器
7 个文件SKILL.md
readonly菜单
Server-side game loop implementation with fixed timestep, physics simulation, and tick rate optimization
Asynchronous programming models including coroutines, async/await, and reactive patterns
Game server communication protocols including gRPC, REST, and custom binary protocols
Efficient data serialization for game networking including Protobuf, FlatBuffers, and custom binary
Game data persistence with player profiles, leaderboards, inventory systems using Redis and PostgreSQL
Game server deployment with Docker, Kubernetes, and global distribution strategies
Game server design patterns including ECS, command pattern, and event sourcing
| name | game-loop |
| description | Server-side game loop implementation with fixed timestep, physics simulation, and tick rate optimization |
| sasmp_version | 1.3.0 |
| version | 2.0.0 |
| bonded_agent | 05-game-loop-developer |
| bond_type | PRIMARY_BOND |
| parameters | {"required":["tick_rate"],"optional":["physics_enabled","max_tick_catchup"],"validation":{"tick_rate":{"type":"integer","min":1,"max":128},"physics_enabled":{"type":"boolean","default":true},"max_tick_catchup":{"type":"integer","min":1,"max":10,"default":5}}} |
| retry_config | {"max_attempts":1,"fallback":"skip_frame"} |
| observability | {"logging":{"level":"info","fields":["tick_number","tick_time_ms","entity_count"]},"metrics":[{"name":"game_tick_duration_seconds","type":"histogram"},{"name":"game_tick_count","type":"counter"},{"name":"game_entity_count","type":"gauge"}]} |
Implement deterministic game loops with fixed timestep for consistent gameplay.
class GameLoop {
constructor(tickRate = 60) {
this.tickRate = tickRate;
this.tickMs = 1000 / tickRate;
this.tick = 0;
this.running = false;
}
start() {
this.running = true;
this.lastTime = process.hrtime.bigint();
this.accumulator = 0n;
this.loop();
}
loop() {
if (!this.running) return;
const now = process.hrtime.bigint();
const deltaNs = now - this.lastTime;
this.lastTime = now;
this.accumulator += deltaNs;
const tickNs = BigInt(Math.round(this.tickMs * 1_000_000));
let ticksProcessed = 0;
while (this.accumulator >= tickNs && ticksProcessed < 5) {
this.update(this.tickMs);
this.tick++;
this.accumulator -= tickNs;
ticksProcessed++;
}
// Prevent spiral of death
if (ticksProcessed === 5) {
this.accumulator = 0n;
console.warn('Tick catchup limit reached');
}
const sleepMs = Math.max(1, this.tickMs - Number(this.accumulator) / 1_000_000);
setTimeout(() => this.loop(), sleepMs);
}
update(dt) {
this.processInputs();
this.updatePhysics(dt);
this.updateEntities(dt);
this.checkGameState();
this.broadcastState();
}
}
| Game Type | Rate | Budget | Rationale |
|---|---|---|---|
| FPS | 60-128 Hz | 8-16ms | Hit precision |
| MOBA | 30-60 Hz | 16-33ms | Balance |
| BR | 20-30 Hz | 33-50ms | Scale |
| MMO | 10-20 Hz | 50-100ms | Massive |
class TickMetrics {
constructor(size = 100) {
this.samples = [];
this.size = size;
}
record(ms) {
this.samples.push(ms);
if (this.samples.length > this.size) this.samples.shift();
}
stats() {
const sorted = [...this.samples].sort((a, b) => a - b);
return {
avg: this.samples.reduce((a, b) => a + b, 0) / this.samples.length,
p50: sorted[Math.floor(sorted.length * 0.5)],
p99: sorted[Math.floor(sorted.length * 0.99)]
};
}
}
| Error | Root Cause | Solution |
|---|---|---|
| Tick spikes | GC pauses | Object pooling |
| Drift | Float precision | Fixed-point math |
| Explosion | Large dt | Cap dt value |
| Stuttering | Variable tick | Fixed timestep |
const stats = metrics.stats();
console.log(`Avg: ${stats.avg.toFixed(2)}ms`);
console.log(`P99: ${stats.p99.toFixed(2)}ms`);
console.log(`Budget: ${(stats.avg / tickBudget * 100).toFixed(1)}%`);
describe('GameLoop', () => {
test('maintains tick rate', async () => {
const loop = new GameLoop(60);
const ticks = [];
loop.update = () => ticks.push(Date.now());
loop.start();
await new Promise(r => setTimeout(r, 100));
loop.running = false;
expect(ticks.length).toBeGreaterThan(4);
});
});
assets/ - Loop templatesreferences/ - Optimization guides