651 lines
18 KiB
Markdown
651 lines
18 KiB
Markdown
|
|
# 定时器系统使用指南
|
|||
|
|
|
|||
|
|
定时器系统是游戏开发中的重要工具,用于处理延迟执行、重复任务、倒计时等功能。本指南详细介绍如何使用ECS框架的定时器系统。
|
|||
|
|
|
|||
|
|
## 定时器基础概念
|
|||
|
|
|
|||
|
|
### 什么是定时器?
|
|||
|
|
|
|||
|
|
定时器允许你:
|
|||
|
|
- ⏰ **延迟执行** - 在指定时间后执行某个操作
|
|||
|
|
- 🔄 **重复执行** - 定期重复执行某个操作
|
|||
|
|
- 🛑 **取消执行** - 在执行前取消定时器
|
|||
|
|
- 🎯 **精确控制** - 精确控制执行时机
|
|||
|
|
|
|||
|
|
### 定时器的优势
|
|||
|
|
|
|||
|
|
相比直接在游戏循环中计时,定时器系统提供:
|
|||
|
|
- 🧹 **自动管理** - 自动处理定时器的生命周期
|
|||
|
|
- 🎮 **游戏时间控制** - 支持游戏暂停、时间缩放
|
|||
|
|
- 💾 **内存优化** - 自动回收完成的定时器
|
|||
|
|
- 🔧 **易于使用** - 简单的API调用
|
|||
|
|
|
|||
|
|
## 基础定时器使用
|
|||
|
|
|
|||
|
|
### 1. 简单延迟执行
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import { Core, Timer } from '@esengine/ecs-framework';
|
|||
|
|
|
|||
|
|
// 3秒后执行一次
|
|||
|
|
Core.schedule(3.0, false, this, (timer) => {
|
|||
|
|
console.log("3秒钟到了!");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 实际游戏例子:延迟显示提示
|
|||
|
|
class GameTutorial {
|
|||
|
|
startTutorial() {
|
|||
|
|
// 2秒后显示第一个提示
|
|||
|
|
Core.schedule(2.0, false, this, () => {
|
|||
|
|
this.showTip("欢迎来到游戏世界!");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 5秒后显示移动提示
|
|||
|
|
Core.schedule(5.0, false, this, () => {
|
|||
|
|
this.showTip("使用WASD键移动角色");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 8秒后显示攻击提示
|
|||
|
|
Core.schedule(8.0, false, this, () => {
|
|||
|
|
this.showTip("按空格键攻击敌人");
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private showTip(message: string) {
|
|||
|
|
// 显示提示的逻辑
|
|||
|
|
console.log(`提示: ${message}`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 重复执行
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 每1秒执行一次,持续执行
|
|||
|
|
const repeatTimer = Core.schedule(1.0, true, this, (timer) => {
|
|||
|
|
console.log("每秒执行一次");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 实际游戏例子:生命值恢复
|
|||
|
|
class HealthRegeneration {
|
|||
|
|
private regenTimer: ITimer;
|
|||
|
|
|
|||
|
|
startRegeneration(entity: Entity) {
|
|||
|
|
const health = entity.getComponent(HealthComponent);
|
|||
|
|
|
|||
|
|
// 每2秒恢复5点生命值
|
|||
|
|
this.regenTimer = Core.schedule(2.0, true, this, () => {
|
|||
|
|
if (health.currentHealth < health.maxHealth) {
|
|||
|
|
health.currentHealth += 5;
|
|||
|
|
health.currentHealth = Math.min(health.currentHealth, health.maxHealth);
|
|||
|
|
|
|||
|
|
console.log(`生命值恢复:${health.currentHealth}/${health.maxHealth}`);
|
|||
|
|
|
|||
|
|
// 满血时停止恢复
|
|||
|
|
if (health.currentHealth >= health.maxHealth) {
|
|||
|
|
this.stopRegeneration();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
stopRegeneration() {
|
|||
|
|
if (this.regenTimer) {
|
|||
|
|
this.regenTimer.stop();
|
|||
|
|
this.regenTimer = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 获取定时器引用进行控制
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
import { ITimer } from '@esengine/ecs-framework';
|
|||
|
|
|
|||
|
|
class BombTimer {
|
|||
|
|
private bombTimer: ITimer;
|
|||
|
|
private explosionTime: number = 5.0;
|
|||
|
|
|
|||
|
|
startBomb(position: { x: number; y: number }) {
|
|||
|
|
console.log("炸弹已放置!5秒后爆炸...");
|
|||
|
|
|
|||
|
|
// 创建定时器并保存引用
|
|||
|
|
this.bombTimer = Core.schedule(this.explosionTime, false, this, () => {
|
|||
|
|
this.explode(position);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
defuseBomb() {
|
|||
|
|
if (this.bombTimer && !this.bombTimer.isDone) {
|
|||
|
|
// 拆除炸弹
|
|||
|
|
this.bombTimer.stop();
|
|||
|
|
console.log("炸弹已被拆除!");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
getRemainingTime(): number {
|
|||
|
|
if (this.bombTimer && !this.bombTimer.isDone) {
|
|||
|
|
return this.explosionTime - this.bombTimer.elapsedTime;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private explode(position: { x: number; y: number }) {
|
|||
|
|
console.log("💥 炸弹爆炸了!");
|
|||
|
|
// 爆炸效果逻辑...
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 高级定时器功能
|
|||
|
|
|
|||
|
|
### 1. 定时器链 - 顺序执行多个任务
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class CutsceneManager {
|
|||
|
|
playCutscene() {
|
|||
|
|
// 第一个镜头:2秒
|
|||
|
|
Core.schedule(2.0, false, this, () => {
|
|||
|
|
this.showScene("开场镜头");
|
|||
|
|
|
|||
|
|
// 第二个镜头:3秒后
|
|||
|
|
Core.schedule(3.0, false, this, () => {
|
|||
|
|
this.showScene("角色登场");
|
|||
|
|
|
|||
|
|
// 第三个镜头:2秒后
|
|||
|
|
Core.schedule(2.0, false, this, () => {
|
|||
|
|
this.showScene("背景介绍");
|
|||
|
|
|
|||
|
|
// 结束:1秒后
|
|||
|
|
Core.schedule(1.0, false, this, () => {
|
|||
|
|
this.endCutscene();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private showScene(sceneName: string) {
|
|||
|
|
console.log(`播放场景: ${sceneName}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private endCutscene() {
|
|||
|
|
console.log("过场动画结束,开始游戏!");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更优雅的链式写法
|
|||
|
|
class ImprovedCutsceneManager {
|
|||
|
|
playCutscene() {
|
|||
|
|
this.scheduleSequence([
|
|||
|
|
{ delay: 2.0, action: () => this.showScene("开场镜头") },
|
|||
|
|
{ delay: 3.0, action: () => this.showScene("角色登场") },
|
|||
|
|
{ delay: 2.0, action: () => this.showScene("背景介绍") },
|
|||
|
|
{ delay: 1.0, action: () => this.endCutscene() }
|
|||
|
|
]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private scheduleSequence(sequence: Array<{delay: number, action: () => void}>) {
|
|||
|
|
let currentDelay = 0;
|
|||
|
|
|
|||
|
|
sequence.forEach(step => {
|
|||
|
|
currentDelay += step.delay;
|
|||
|
|
Core.schedule(currentDelay, false, this, step.action);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 条件定时器 - 满足条件时执行
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class ConditionalTimer {
|
|||
|
|
waitForCondition(
|
|||
|
|
condition: () => boolean,
|
|||
|
|
action: () => void,
|
|||
|
|
checkInterval: number = 0.1,
|
|||
|
|
timeout: number = 10.0
|
|||
|
|
) {
|
|||
|
|
let timeElapsed = 0;
|
|||
|
|
|
|||
|
|
const checkTimer = Core.schedule(checkInterval, true, this, () => {
|
|||
|
|
timeElapsed += checkInterval;
|
|||
|
|
|
|||
|
|
if (condition()) {
|
|||
|
|
// 条件满足,执行动作并停止检查
|
|||
|
|
checkTimer.stop();
|
|||
|
|
action();
|
|||
|
|
} else if (timeElapsed >= timeout) {
|
|||
|
|
// 超时,停止检查
|
|||
|
|
checkTimer.stop();
|
|||
|
|
console.log("等待条件超时");
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 使用例子
|
|||
|
|
class WaitForPlayerExample {
|
|||
|
|
waitForPlayerToReachGoal() {
|
|||
|
|
const player = this.getPlayer();
|
|||
|
|
const goalPosition = { x: 500, y: 300 };
|
|||
|
|
|
|||
|
|
this.waitForCondition(
|
|||
|
|
// 条件:玩家到达目标位置
|
|||
|
|
() => {
|
|||
|
|
const playerPos = player.getComponent(PositionComponent);
|
|||
|
|
return playerPos.distanceTo(goalPosition) < 50;
|
|||
|
|
},
|
|||
|
|
// 动作:触发下一关
|
|||
|
|
() => {
|
|||
|
|
console.log("玩家到达目标!开始下一关");
|
|||
|
|
this.loadNextLevel();
|
|||
|
|
},
|
|||
|
|
0.1, // 每0.1秒检查一次
|
|||
|
|
30.0 // 30秒后超时
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 可暂停的定时器
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class PausableTimer {
|
|||
|
|
private timers: ITimer[] = [];
|
|||
|
|
private isPaused: boolean = false;
|
|||
|
|
|
|||
|
|
schedule(delay: number, repeat: boolean, callback: () => void): ITimer {
|
|||
|
|
const timer = Core.schedule(delay, repeat, this, callback);
|
|||
|
|
this.timers.push(timer);
|
|||
|
|
return timer;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
pauseAll() {
|
|||
|
|
this.isPaused = true;
|
|||
|
|
this.timers.forEach(timer => {
|
|||
|
|
if (!timer.isDone) {
|
|||
|
|
timer.stop();
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
resumeAll() {
|
|||
|
|
if (!this.isPaused) return;
|
|||
|
|
|
|||
|
|
this.isPaused = false;
|
|||
|
|
// 重新启动所有未完成的定时器
|
|||
|
|
// 注意:这是简化实现,实际需要保存剩余时间
|
|||
|
|
this.timers = this.timers.filter(timer => !timer.isDone);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
clearAll() {
|
|||
|
|
this.timers.forEach(timer => timer.stop());
|
|||
|
|
this.timers = [];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 游戏暂停系统
|
|||
|
|
class GamePauseSystem {
|
|||
|
|
private gameTimers: PausableTimer = new PausableTimer();
|
|||
|
|
private isGamePaused: boolean = false;
|
|||
|
|
|
|||
|
|
pauseGame() {
|
|||
|
|
if (this.isGamePaused) return;
|
|||
|
|
|
|||
|
|
this.isGamePaused = true;
|
|||
|
|
this.gameTimers.pauseAll();
|
|||
|
|
|
|||
|
|
// 显示暂停菜单
|
|||
|
|
this.showPauseMenu();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
resumeGame() {
|
|||
|
|
if (!this.isGamePaused) return;
|
|||
|
|
|
|||
|
|
this.isGamePaused = false;
|
|||
|
|
this.gameTimers.resumeAll();
|
|||
|
|
|
|||
|
|
// 隐藏暂停菜单
|
|||
|
|
this.hidePauseMenu();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
scheduleGameTimer(delay: number, repeat: boolean, callback: () => void) {
|
|||
|
|
return this.gameTimers.schedule(delay, repeat, callback);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 实际游戏应用示例
|
|||
|
|
|
|||
|
|
### 1. Buff/Debuff 系统
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class BuffSystem {
|
|||
|
|
applyBuff(entity: Entity, buffType: string, duration: number) {
|
|||
|
|
const buff = new BuffComponent(buffType, duration);
|
|||
|
|
entity.addComponent(buff);
|
|||
|
|
|
|||
|
|
// 应用Buff效果
|
|||
|
|
this.applyBuffEffect(entity, buffType);
|
|||
|
|
|
|||
|
|
// 设置定时器移除Buff
|
|||
|
|
Core.schedule(duration, false, this, () => {
|
|||
|
|
if (!entity.isDestroyed && entity.hasComponent(BuffComponent)) {
|
|||
|
|
this.removeBuff(entity, buffType);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
console.log(`应用了 ${buffType} Buff,持续时间 ${duration} 秒`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private applyBuffEffect(entity: Entity, buffType: string) {
|
|||
|
|
const stats = entity.getComponent(StatsComponent);
|
|||
|
|
|
|||
|
|
switch (buffType) {
|
|||
|
|
case 'speed_boost':
|
|||
|
|
stats.moveSpeed *= 1.5;
|
|||
|
|
break;
|
|||
|
|
case 'damage_boost':
|
|||
|
|
stats.damage *= 2.0;
|
|||
|
|
break;
|
|||
|
|
case 'invincible':
|
|||
|
|
entity.addComponent(new InvincibleComponent());
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private removeBuff(entity: Entity, buffType: string) {
|
|||
|
|
const buff = entity.getComponent(BuffComponent);
|
|||
|
|
if (buff && buff.buffType === buffType) {
|
|||
|
|
entity.removeComponent(buff);
|
|||
|
|
this.removeBuffEffect(entity, buffType);
|
|||
|
|
console.log(`${buffType} Buff 已过期`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 技能冷却系统
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class SkillSystem {
|
|||
|
|
private cooldowns: Map<string, number> = new Map();
|
|||
|
|
|
|||
|
|
useSkill(player: Entity, skillName: string): boolean {
|
|||
|
|
// 检查冷却
|
|||
|
|
if (this.isOnCooldown(skillName)) {
|
|||
|
|
const remainingTime = this.getCooldownRemaining(skillName);
|
|||
|
|
console.log(`技能冷却中,还需 ${remainingTime.toFixed(1)} 秒`);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 执行技能
|
|||
|
|
this.executeSkill(player, skillName);
|
|||
|
|
|
|||
|
|
// 启动冷却
|
|||
|
|
const cooldownTime = this.getSkillCooldown(skillName);
|
|||
|
|
this.startCooldown(skillName, cooldownTime);
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private startCooldown(skillName: string, duration: number) {
|
|||
|
|
const endTime = Time.totalTime + duration;
|
|||
|
|
this.cooldowns.set(skillName, endTime);
|
|||
|
|
|
|||
|
|
// 设置定时器清理冷却
|
|||
|
|
Core.schedule(duration, false, this, () => {
|
|||
|
|
this.cooldowns.delete(skillName);
|
|||
|
|
console.log(`技能 ${skillName} 冷却完成!`);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private isOnCooldown(skillName: string): boolean {
|
|||
|
|
const endTime = this.cooldowns.get(skillName);
|
|||
|
|
return endTime !== undefined && Time.totalTime < endTime;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private getCooldownRemaining(skillName: string): number {
|
|||
|
|
const endTime = this.cooldowns.get(skillName);
|
|||
|
|
return endTime ? Math.max(0, endTime - Time.totalTime) : 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private executeSkill(player: Entity, skillName: string) {
|
|||
|
|
switch (skillName) {
|
|||
|
|
case 'fireball':
|
|||
|
|
this.castFireball(player);
|
|||
|
|
break;
|
|||
|
|
case 'heal':
|
|||
|
|
this.castHeal(player);
|
|||
|
|
break;
|
|||
|
|
case 'dash':
|
|||
|
|
this.performDash(player);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private getSkillCooldown(skillName: string): number {
|
|||
|
|
const cooldowns = {
|
|||
|
|
'fireball': 3.0,
|
|||
|
|
'heal': 10.0,
|
|||
|
|
'dash': 5.0
|
|||
|
|
};
|
|||
|
|
return cooldowns[skillName] || 1.0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 关卡时间限制
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class LevelTimer {
|
|||
|
|
private timeLimit: number;
|
|||
|
|
private timeRemaining: number;
|
|||
|
|
private timerActive: boolean = false;
|
|||
|
|
private updateTimer: ITimer;
|
|||
|
|
|
|||
|
|
startLevel(timeLimitSeconds: number) {
|
|||
|
|
this.timeLimit = timeLimitSeconds;
|
|||
|
|
this.timeRemaining = timeLimitSeconds;
|
|||
|
|
this.timerActive = true;
|
|||
|
|
|
|||
|
|
// 每秒更新倒计时
|
|||
|
|
this.updateTimer = Core.schedule(1.0, true, this, () => {
|
|||
|
|
this.updateCountdown();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
console.log(`关卡开始!时间限制:${timeLimitSeconds} 秒`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private updateCountdown() {
|
|||
|
|
if (!this.timerActive) return;
|
|||
|
|
|
|||
|
|
this.timeRemaining--;
|
|||
|
|
|
|||
|
|
// 更新UI显示
|
|||
|
|
this.updateTimerUI(this.timeRemaining);
|
|||
|
|
|
|||
|
|
// 时间警告
|
|||
|
|
if (this.timeRemaining === 30) {
|
|||
|
|
console.log("⚠️ 警告:还剩30秒!");
|
|||
|
|
this.playWarningSound();
|
|||
|
|
} else if (this.timeRemaining === 10) {
|
|||
|
|
console.log("🚨 紧急:还剩10秒!");
|
|||
|
|
this.playUrgentSound();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 时间到
|
|||
|
|
if (this.timeRemaining <= 0) {
|
|||
|
|
this.timeUp();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private timeUp() {
|
|||
|
|
this.timerActive = false;
|
|||
|
|
this.updateTimer.stop();
|
|||
|
|
|
|||
|
|
console.log("⏰ 时间到!游戏结束");
|
|||
|
|
|
|||
|
|
// 触发游戏结束
|
|||
|
|
Core.emitter.emit('level:timeout');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
completeLevel() {
|
|||
|
|
if (this.timerActive) {
|
|||
|
|
this.timerActive = false;
|
|||
|
|
this.updateTimer.stop();
|
|||
|
|
|
|||
|
|
const completionTime = this.timeLimit - this.timeRemaining;
|
|||
|
|
console.log(`🎉 关卡完成!用时:${completionTime} 秒`);
|
|||
|
|
|
|||
|
|
// 根据剩余时间给予奖励
|
|||
|
|
this.calculateTimeBonus(this.timeRemaining);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private calculateTimeBonus(timeLeft: number) {
|
|||
|
|
const bonus = Math.floor(timeLeft * 10); // 每秒剩余10分
|
|||
|
|
if (bonus > 0) {
|
|||
|
|
console.log(`时间奖励:${bonus} 分`);
|
|||
|
|
Core.emitter.emit('score:time_bonus', { bonus });
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
getTimeRemaining(): number {
|
|||
|
|
return this.timeRemaining;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
getTimeRemainingFormatted(): string {
|
|||
|
|
const minutes = Math.floor(this.timeRemaining / 60);
|
|||
|
|
const seconds = this.timeRemaining % 60;
|
|||
|
|
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 定时器性能优化
|
|||
|
|
|
|||
|
|
### 1. 定时器池化
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class TimerPool {
|
|||
|
|
private static instance: TimerPool;
|
|||
|
|
private timerPool: ITimer[] = [];
|
|||
|
|
|
|||
|
|
static getInstance(): TimerPool {
|
|||
|
|
if (!this.instance) {
|
|||
|
|
this.instance = new TimerPool();
|
|||
|
|
}
|
|||
|
|
return this.instance;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
getTimer(): ITimer {
|
|||
|
|
return this.timerPool.pop() || this.createTimer();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
releaseTimer(timer: ITimer) {
|
|||
|
|
timer.stop();
|
|||
|
|
this.timerPool.push(timer);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private createTimer(): ITimer {
|
|||
|
|
// 创建新定时器的逻辑
|
|||
|
|
return new Timer();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 批量定时器管理
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class BatchTimerManager {
|
|||
|
|
private timers: Set<ITimer> = new Set();
|
|||
|
|
|
|||
|
|
scheduleMany(configs: Array<{delay: number, repeat: boolean, callback: () => void}>) {
|
|||
|
|
return configs.map(config => {
|
|||
|
|
const timer = Core.schedule(config.delay, config.repeat, this, config.callback);
|
|||
|
|
this.timers.add(timer);
|
|||
|
|
return timer;
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
stopAll() {
|
|||
|
|
this.timers.forEach(timer => timer.stop());
|
|||
|
|
this.timers.clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cleanup() {
|
|||
|
|
// 清理已完成的定时器
|
|||
|
|
this.timers.forEach(timer => {
|
|||
|
|
if (timer.isDone) {
|
|||
|
|
this.timers.delete(timer);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 常见问题和最佳实践
|
|||
|
|
|
|||
|
|
### Q: 定时器会自动清理吗?
|
|||
|
|
|
|||
|
|
A: 是的,完成的定时器会自动清理。但如果需要提前停止,记得调用 `timer.stop()`。
|
|||
|
|
|
|||
|
|
### Q: 定时器会受到游戏暂停影响吗?
|
|||
|
|
|
|||
|
|
A: 定时器使用游戏时间,如果实现了时间缩放功能,定时器会相应调整。
|
|||
|
|
|
|||
|
|
### Q: 如何实现精确的帧同步定时器?
|
|||
|
|
|
|||
|
|
A: 使用帧计数而不是时间:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class FrameTimer {
|
|||
|
|
private frameCount: number = 0;
|
|||
|
|
private targetFrame: number;
|
|||
|
|
|
|||
|
|
scheduleFrames(frames: number, callback: () => void) {
|
|||
|
|
this.targetFrame = this.frameCount + frames;
|
|||
|
|
|
|||
|
|
const checkFrame = () => {
|
|||
|
|
this.frameCount++;
|
|||
|
|
if (this.frameCount >= this.targetFrame) {
|
|||
|
|
callback();
|
|||
|
|
} else {
|
|||
|
|
requestAnimationFrame(checkFrame);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
requestAnimationFrame(checkFrame);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Q: 如何避免定时器内存泄漏?
|
|||
|
|
|
|||
|
|
A:
|
|||
|
|
1. 及时停止不需要的定时器
|
|||
|
|
2. 在对象销毁时清理所有定时器
|
|||
|
|
3. 使用弱引用避免循环引用
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
class SafeTimerUser {
|
|||
|
|
private timers: ITimer[] = [];
|
|||
|
|
|
|||
|
|
scheduleTimer(delay: number, callback: () => void) {
|
|||
|
|
const timer = Core.schedule(delay, false, this, callback);
|
|||
|
|
this.timers.push(timer);
|
|||
|
|
return timer;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
destroy() {
|
|||
|
|
// 清理所有定时器
|
|||
|
|
this.timers.forEach(timer => timer.stop());
|
|||
|
|
this.timers = [];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
定时器是游戏开发中非常有用的工具,合理使用可以让你的游戏逻辑更加优雅和高效!
|