我在做一款类似于漫画制作的游戏时遇到了一个问题如何让世界环境来控制地方使用的计时器的问题,经过一定的研究我通过上一篇c#实现ref的功能得到的灵感,不知道的可以去看看我上一篇文章的介绍;,在这里就不多赘述了,请看下面的代码部分。
代码语言:txt复制using System.Collections.Generic;
using System.Threading;
using System;
public class TimerManager
{
private static TimerManager _instance;
private readonly Dictionary<string, TimerData> _timers = new Dictionary<string, TimerData>();
private readonly object _lock = new object(); // 锁对象,用于同步访问_timers字典
private bool _allTimersStarted = false; // 标记所有计时器是否应该启动
// 用于存储计时器名称、回调和周期的辅助类
private class TimerData
{
public Timer Timer { get; set; }
public int Interval { get; set; }
public Action Callback { get; set; }
public TimerData(Timer timer, int interval, Action callback)
{
Timer = timer;
Interval = interval;
Callback = callback;
}
}
private TimerManager() { }
public static TimerManager Instance
{
get
{
if (_instance == null)
{
lock (typeof(TimerManager))
{
if (_instance == null)
{
_instance = new TimerManager();
}
}
}
return _instance;
}
}
// 注册计时器
public void RegisterTimer(string timerName, int interval, Action callback)
{
lock (_lock)
{
if (_timers.ContainsKey(timerName))
{
Console.WriteLine($"计时器 {timerName} 已经存在。");
return;
}
var timer = new Timer(ExecuteCallback, new TimerState(timerName, callback), Timeout.Infinite, Timeout.Infinite);
var timerData = new TimerData(timer, interval, callback);
_timers[timerName] = timerData;
// 如果所有计时器都应该启动,则启动新注册的计时器
if (_allTimersStarted)
{
timerData.Timer.Change(0, timerData.Interval);
Console.WriteLine($"计时器 {timerName} 注册后立即启动。");
}
else
{
Console.WriteLine($"计时器 {timerName} 注册成功。");
}
}
}
// 移除计时器
public void UnregisterTimer(string timerName)
{
lock (_lock)
{
if (_timers.TryGetValue(timerName, out TimerData timerData))
{
timerData.Timer.Dispose();
_timers.Remove(timerName);
Console.WriteLine($"计时器 {timerName} 已移除。");
}
else
{
Console.WriteLine($"计时器 {timerName} 不存在。");
}
}
}
// 启动所有计时器
public void StartAllTimers()
{
lock (_lock)
{
_allTimersStarted = true; // 设置标志位
foreach (var timerData in _timers.Values)
{
timerData.Timer.Change(0, timerData.Interval);
}
Console.WriteLine("所有计时器已启动。");
}
}
// 停止所有计时器
public void StopAllTimers()
{
lock (_lock)
{
_allTimersStarted = false; // 清除标志位
List<string> keysToRemove = new List<string>(_timers.Keys); // 复制键列表,以防并发修改异常
foreach (string key in keysToRemove)
{
if (_timers.TryGetValue(key, out TimerData timerData))
{
timerData.Timer.Change(Timeout.Infinite, Timeout.Infinite);
Console.WriteLine($"计时器 {key} 已停止。");
}
}
Console.WriteLine("所有计时器已停止。");
}
}
// 启动单个计时器
public void StartTimer(string timerName)
{
lock (_lock)
{
if (_timers.TryGetValue(timerName, out TimerData timerData))
{
timerData.Timer.Change(0, timerData.Interval);
Console.WriteLine($"计时器 {timerName} 已启动。");
}
else
{
Console.WriteLine($"计时器 {timerName} 不存在。");
}
}
}
// 停止单个计时器
public void StopTimer(string timerName)
{
lock (_lock)
{
if (_timers.TryGetValue(timerName, out TimerData timerData))
{
timerData.Timer.Change(Timeout.Infinite, Timeout.Infinite);
Console.WriteLine($"计时器 {timerName} 已停止。");
}
else
{
Console.WriteLine($"计时器 {timerName} 不存在。");
}
}
}
// 执行回调
private void ExecuteCallback(object state)
{
var timerState = (TimerState)state;
timerState.Callback?.Invoke();
}
// 用于存储计时器名称和回调的辅助类
private class TimerState
{
public string TimerName { get; set; }
public Action Callback { get; set; }
public TimerState(string timerName, Action callback)
{
TimerName = timerName;
Callback = callback;
}
}
}
使用的方法: 如果你有一个控制世界时间的控制器你可以对这个控制器注册一个计时器,而暂停和开始你可以分别使用StopAllTimers
,StartAllTimers来进行对游戏全局的注册的计时器控制,当你只使用单个的或者说时局部的计时器只需要注册一个计时器轴通过StartTimer和StopTimer进行控制就行了,你可以看到你们给的参数就是timerName,这个参数时你注册计时器时的名字,中文我没有试过我不知道什么情况但是英文是没有任何问题的,有了这个函数之后你想怎么控制时间就怎么控制。