Demo
This commit is contained in:
ALEXTANG
2023-05-13 11:57:11 +08:00
parent fd7d8a798b
commit 7bf081269c
313 changed files with 135421 additions and 2 deletions

View File

@@ -0,0 +1,36 @@
# UniFramework.Pooling
一个功能强大的游戏对象池系统。
该系统依赖于YooAsset资源系统支持各类异步编程支持同步接口和异步接口。
```c#
using UnityEngine;
using YooAsset;
using UniFramework.Pooling;
IEnumerator Start()
{
// 初始化游戏对象池系统
UniPooling.Initalize();
// 创建孵化器
var spawner = UniPooling.CreateSpawner("DefaultPackage");
// 创建Cube预制体的对象池
var operation = spawner.CreateGameObjectPoolAsync("Cube.prefab");
yield return operation;
// 孵化Cube游戏对象
SpawnHandle handle = spawner.SpawnAsync("Cube.prefab");
yield return handle;
Debug.Log(handle.GameObj.name);
// 回收游戏对象
handle.Restore();
// 丢弃游戏对象
handle.Discard();
}
```

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7976cbcaa4dcfcc4b932fb01d6c0499a
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5904699460a22064182a5cf9129fc09e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
using YooAsset;
namespace UniFramework.Pooling
{
public class CreatePoolOperation : GameAsyncOperation
{
private enum ESteps
{
None,
Waiting,
Done,
}
private readonly AssetOperationHandle _handle;
private ESteps _steps = ESteps.None;
internal CreatePoolOperation(AssetOperationHandle handle)
{
_handle = handle;
}
protected override void OnStart()
{
_steps = ESteps.Waiting;
}
protected override void OnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.Waiting)
{
if (_handle.IsValid == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle)} is invalid.";
return;
}
if (_handle.IsDone == false)
return;
if (_handle.AssetObject == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(AssetOperationHandle.AssetObject)} is null.";
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
/// <summary>
/// 等待异步实例化结束
/// </summary>
public void WaitForAsyncComplete()
{
if (_handle != null)
{
if (_steps == ESteps.Done)
return;
_handle.WaitForAsyncComplete();
OnUpdate();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a5687620a17f42e4085a0e2243be7561
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,215 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace UniFramework.Pooling
{
internal class GameObjectPool
{
private readonly Transform _poolRoot;
private readonly Queue<InstantiateOperation> _cacheOperations;
private readonly bool _dontDestroy;
private readonly int _initCapacity;
private readonly int _maxCapacity;
private readonly float _destroyTime;
private float _lastRestoreRealTime = -1f;
/// <summary>
/// 资源句柄
/// </summary>
public AssetOperationHandle AssetHandle { private set; get; }
/// <summary>
/// 资源定位地址
/// </summary>
public string Location { private set; get; }
/// <summary>
/// 内部缓存总数
/// </summary>
public int CacheCount
{
get { return _cacheOperations.Count; }
}
/// <summary>
/// 外部使用总数
/// </summary>
public int SpawnCount { private set; get; } = 0;
/// <summary>
/// 是否常驻不销毁
/// </summary>
public bool DontDestroy
{
get { return _dontDestroy; }
}
public GameObjectPool(GameObject poolRoot, string location, bool dontDestroy, int initCapacity, int maxCapacity, float destroyTime)
{
_poolRoot = poolRoot.transform;
Location = location;
_dontDestroy = dontDestroy;
_initCapacity = initCapacity;
_maxCapacity = maxCapacity;
_destroyTime = destroyTime;
// 创建缓存池
_cacheOperations = new Queue<InstantiateOperation>(initCapacity);
}
/// <summary>
/// 创建对象池
/// </summary>
public void CreatePool(ResourcePackage package)
{
// 加载游戏对象
AssetHandle = package.LoadAssetAsync<GameObject>(Location);
// 创建初始对象
for (int i = 0; i < _initCapacity; i++)
{
var operation = AssetHandle.InstantiateAsync(_poolRoot);
_cacheOperations.Enqueue(operation);
}
}
/// <summary>
/// 销毁游戏对象池
/// </summary>
public void DestroyPool()
{
// 卸载资源对象
AssetHandle.Release();
AssetHandle = null;
// 销毁游戏对象
foreach (var operation in _cacheOperations)
{
if (operation.Result != null)
GameObject.Destroy(operation.Result);
}
_cacheOperations.Clear();
SpawnCount = 0;
}
/// <summary>
/// 查询静默时间内是否可以销毁
/// </summary>
public bool CanAutoDestroy()
{
if (_dontDestroy)
return false;
if (_destroyTime < 0)
return false;
if (_lastRestoreRealTime > 0 && SpawnCount <= 0)
return (Time.realtimeSinceStartup - _lastRestoreRealTime) > _destroyTime;
else
return false;
}
/// <summary>
/// 游戏对象池是否已经销毁
/// </summary>
public bool IsDestroyed()
{
return AssetHandle == null;
}
/// <summary>
/// 回收
/// </summary>
public void Restore(InstantiateOperation operation)
{
if (IsDestroyed())
{
DestroyInstantiateOperation(operation);
return;
}
SpawnCount--;
if (SpawnCount <= 0)
_lastRestoreRealTime = Time.realtimeSinceStartup;
// 如果外部逻辑销毁了游戏对象
if (operation.Status == EOperationStatus.Succeed)
{
if (operation.Result == null)
return;
}
// 如果缓存池还未满员
if (_cacheOperations.Count < _maxCapacity)
{
SetRestoreGameObject(operation.Result);
_cacheOperations.Enqueue(operation);
}
else
{
DestroyInstantiateOperation(operation);
}
}
/// <summary>
/// 丢弃
/// </summary>
public void Discard(InstantiateOperation operation)
{
if (IsDestroyed())
{
DestroyInstantiateOperation(operation);
return;
}
SpawnCount--;
if (SpawnCount <= 0)
_lastRestoreRealTime = Time.realtimeSinceStartup;
DestroyInstantiateOperation(operation);
}
/// <summary>
/// 获取一个游戏对象
/// </summary>
public SpawnHandle Spawn(Transform parent, Vector3 position, Quaternion rotation, bool forceClone, params System.Object[] userDatas)
{
InstantiateOperation operation;
if (forceClone == false && _cacheOperations.Count > 0)
operation = _cacheOperations.Dequeue();
else
operation = AssetHandle.InstantiateAsync();
SpawnCount++;
SpawnHandle handle = new SpawnHandle(this, operation, parent, position, rotation, userDatas);
YooAssets.StartOperation(handle);
return handle;
}
private void DestroyInstantiateOperation(InstantiateOperation operation)
{
// 取消异步操作
operation.Cancel();
// 销毁游戏对象
if (operation.Result != null)
{
GameObject.Destroy(operation.Result);
}
}
private void SetRestoreGameObject(GameObject gameObj)
{
if (gameObj != null)
{
gameObj.SetActive(false);
gameObj.transform.SetParent(_poolRoot);
gameObj.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1dd976626eb4ca645b4ec80921f4e8fd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,148 @@
using UnityEngine;
using YooAsset;
namespace UniFramework.Pooling
{
public sealed class SpawnHandle : GameAsyncOperation
{
private enum ESteps
{
None,
Waiting,
Done,
}
private readonly GameObjectPool _pool;
private InstantiateOperation _operation;
private readonly Transform _parent;
private readonly Vector3 _position;
private readonly Quaternion _rotation;
private ESteps _steps = ESteps.None;
/// <summary>
/// 实例化的游戏对象
/// </summary>
public GameObject GameObj
{
get
{
if (_operation == null)
{
UniLogger.Warning("The spawn handle is invalid !");
return null;
}
return _operation.Result;
}
}
/// <summary>
/// 用户自定义数据集
/// </summary>
public System.Object[] UserDatas { private set; get; }
private SpawnHandle()
{
}
internal SpawnHandle(GameObjectPool pool, InstantiateOperation operation, Transform parent, Vector3 position, Quaternion rotation, params System.Object[] userDatas)
{
_pool = pool;
_operation = operation;
_parent = parent;
_position = position;
_rotation = rotation;
UserDatas = userDatas;
}
protected override void OnStart()
{
_steps = ESteps.Waiting;
}
protected override void OnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.Waiting)
{
if (_operation.IsDone == false)
return;
if (_operation.Status != EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _operation.Error;
return;
}
if (_operation.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Clone game object is null.";
return;
}
// 设置参数
_operation.Result.transform.SetParent(_parent);
_operation.Result.transform.SetPositionAndRotation(_position, _rotation);
_operation.Result.SetActive(true);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
/// <summary>
/// 回收
/// </summary>
public void Restore()
{
if (_operation != null)
{
ClearCompletedCallback();
CancelHandle();
_pool.Restore(_operation);
_operation = null;
}
}
/// <summary>
/// 丢弃
/// </summary>
public void Discard()
{
if (_operation != null)
{
ClearCompletedCallback();
CancelHandle();
_pool.Discard(_operation);
_operation = null;
}
}
/// <summary>
/// 等待异步实例化结束
/// </summary>
public void WaitForAsyncComplete()
{
if (_operation != null)
{
if (_steps == ESteps.Done)
return;
_operation.WaitForAsyncComplete();
OnUpdate();
}
}
private void CancelHandle()
{
if (IsDone == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"User cancelled !";
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6350d2984a149b349b9cec658d21b12a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,259 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace UniFramework.Pooling
{
public class Spawner
{
private readonly List<GameObjectPool> _gameObjectPools = new List<GameObjectPool>(100);
private readonly List<GameObjectPool> _removeList = new List<GameObjectPool>(100);
private readonly GameObject _spawnerRoot;
private readonly ResourcePackage _package;
public string PackageName
{
get
{
return _package.PackageName;
}
}
private Spawner()
{
}
internal Spawner(GameObject poolingRoot, ResourcePackage package)
{
_spawnerRoot = new GameObject($"{package.PackageName}");
_spawnerRoot.transform.SetParent(poolingRoot.transform);
_package = package;
}
/// <summary>
/// 更新游戏对象池系统
/// </summary>
internal void Update()
{
_removeList.Clear();
foreach (var pool in _gameObjectPools)
{
if (pool.CanAutoDestroy())
_removeList.Add(pool);
}
foreach (var pool in _removeList)
{
_gameObjectPools.Remove(pool);
pool.DestroyPool();
}
}
/// <summary>
/// 销毁游戏对象池系统
/// </summary>
internal void Destroy()
{
DestroyAll(true);
}
/// <summary>
/// 销毁所有对象池及其资源
/// </summary>
/// <param name="includeAll">销毁所有对象池,包括常驻对象池</param>
public void DestroyAll(bool includeAll)
{
if (includeAll)
{
foreach (var pool in _gameObjectPools)
{
pool.DestroyPool();
}
_gameObjectPools.Clear();
}
else
{
List<GameObjectPool> removeList = new List<GameObjectPool>();
foreach (var pool in _gameObjectPools)
{
if (pool.DontDestroy == false)
removeList.Add(pool);
}
foreach (var pool in removeList)
{
_gameObjectPools.Remove(pool);
pool.DestroyPool();
}
}
}
/// <summary>
/// 异步创建指定资源的游戏对象池
/// </summary>
/// <param name="location">资源定位地址</param>
/// <param name="dontDestroy">资源常驻不销毁</param>
/// <param name="initCapacity">对象池的初始容量</param>
/// <param name="maxCapacity">对象池的最大容量</param>
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)</param>
public CreatePoolOperation CreateGameObjectPoolAsync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
{
return CreateGameObjectPoolInternal(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
}
/// <summary>
/// 同步创建指定资源的游戏对象池
/// </summary>
/// <param name="location">资源定位地址</param>
/// <param name="dontDestroy">资源常驻不销毁</param>
/// <param name="initCapacity">对象池的初始容量</param>
/// <param name="maxCapacity">对象池的最大容量</param>
/// <param name="destroyTime">静默销毁时间(注意:小于零代表不主动销毁)</param>
public CreatePoolOperation CreateGameObjectPoolSync(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
{
var operation = CreateGameObjectPoolInternal(location, dontDestroy, initCapacity, maxCapacity, destroyTime);
operation.WaitForAsyncComplete();
return operation;
}
/// <summary>
/// 创建指定资源的游戏对象池
/// </summary>
private CreatePoolOperation CreateGameObjectPoolInternal(string location, bool dontDestroy = false, int initCapacity = 0, int maxCapacity = int.MaxValue, float destroyTime = -1f)
{
if (maxCapacity < initCapacity)
throw new Exception("The max capacity value must be greater the init capacity value.");
GameObjectPool pool = TryGetGameObjectPool(location);
if (pool != null)
{
UniLogger.Warning($"GameObject pool is already existed : {location}");
var operation = new CreatePoolOperation(pool.AssetHandle);
YooAssets.StartOperation(operation);
return operation;
}
else
{
pool = new GameObjectPool(_spawnerRoot, location, dontDestroy, initCapacity, maxCapacity, destroyTime);
pool.CreatePool(_package);
_gameObjectPools.Add(pool);
var operation = new CreatePoolOperation(pool.AssetHandle);
YooAssets.StartOperation(operation);
return operation;
}
}
/// <summary>
/// 异步实例化一个游戏对象
/// </summary>
/// <param name="location">资源定位地址</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象</param>
/// <param name="userDatas">用户自定义数据</param>
public SpawnHandle SpawnAsync(string location, bool forceClone = false, params System.Object[] userDatas)
{
return SpawnInternal(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
}
/// <summary>
/// 异步实例化一个游戏对象
/// </summary>
/// <param name="location">资源定位地址</param>
/// <param name="parent">父物体</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象</param>
/// <param name="userDatas">用户自定义数据</param>
public SpawnHandle SpawnAsync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
{
return SpawnInternal(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
}
/// <summary>
/// 异步实例化一个游戏对象
/// </summary>
/// <param name="location">资源定位地址</param>
/// <param name="parent">父物体</param>
/// <param name="position">世界坐标</param>
/// <param name="rotation">世界角度</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象</param>
/// <param name="userDatas">用户自定义数据</param>
public SpawnHandle SpawnAsync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
{
return SpawnInternal(location, parent, position, rotation, forceClone, userDatas);
}
/// <summary>
/// 同步实例化一个游戏对象
/// </summary>
/// <param name="location">资源定位地址</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象</param>
/// <param name="userDatas">用户自定义数据</param>
public SpawnHandle SpawnSync(string location, bool forceClone = false, params System.Object[] userDatas)
{
SpawnHandle handle = SpawnInternal(location, null, Vector3.zero, Quaternion.identity, forceClone, userDatas);
handle.WaitForAsyncComplete();
return handle;
}
/// <summary>
/// 同步实例化一个游戏对象
/// </summary>
/// <param name="location">资源定位地址</param>
/// <param name="parent">父物体</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象</param>
/// <param name="userDatas">用户自定义数据</param>
public SpawnHandle SpawnSync(string location, Transform parent, bool forceClone = false, params System.Object[] userDatas)
{
SpawnHandle handle = SpawnInternal(location, parent, Vector3.zero, Quaternion.identity, forceClone, userDatas);
handle.WaitForAsyncComplete();
return handle;
}
/// <summary>
/// 同步实例化一个游戏对象
/// </summary>
/// <param name="location">资源定位地址</param>
/// <param name="parent">父物体</param>
/// <param name="position">世界坐标</param>
/// <param name="rotation">世界角度</param>
/// <param name="forceClone">强制克隆游戏对象,忽略缓存池里的对象</param>
/// <param name="userDatas">用户自定义数据</param>
public SpawnHandle SpawnSync(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone = false, params System.Object[] userDatas)
{
SpawnHandle handle = SpawnInternal(location, parent, position, rotation, forceClone, userDatas);
handle.WaitForAsyncComplete();
return handle;
}
/// <summary>
/// 实例化一个游戏对象
/// </summary>
private SpawnHandle SpawnInternal(string location, Transform parent, Vector3 position, Quaternion rotation, bool forceClone, params System.Object[] userDatas)
{
var pool = TryGetGameObjectPool(location);
if (pool != null)
{
return pool.Spawn(parent, position, rotation, forceClone, userDatas);
}
// 如果不存在创建游戏对象池
pool = new GameObjectPool(_spawnerRoot, location, false, 0, int.MaxValue, -1f);
pool.CreatePool(_package);
_gameObjectPools.Add(pool);
return pool.Spawn(parent, position, rotation, forceClone, userDatas);
}
private GameObjectPool TryGetGameObjectPool(string location)
{
foreach (var pool in _gameObjectPools)
{
if (pool.Location == location)
return pool;
}
return null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c0b7912d44674d47a5b7240670dcc87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
using System.Diagnostics;
namespace UniFramework.Pooling
{
internal static class UniLogger
{
[Conditional("DEBUG")]
public static void Log(string info)
{
UnityEngine.Debug.Log(info);
}
public static void Warning(string info)
{
UnityEngine.Debug.LogWarning(info);
}
public static void Error(string info)
{
UnityEngine.Debug.LogError(info);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 50142a5596fb6c1439dced35faef4d4c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,127 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace UniFramework.Pooling
{
/// <summary>
/// 游戏对象池系统
/// </summary>
public static class UniPooling
{
private static bool _isInitialize = false;
private static GameObject _driver = null;
private static readonly List<Spawner> _spawners = new List<Spawner>();
/// <summary>
/// 初始化游戏对象池系统
/// </summary>
public static void Initalize()
{
if (_isInitialize)
throw new Exception($"{nameof(UniPooling)} is initialized !");
if (_isInitialize == false)
{
// 创建驱动器
_isInitialize = true;
_driver = new UnityEngine.GameObject($"[{nameof(UniPooling)}]");
_driver.AddComponent<UniPoolingDriver>();
UnityEngine.Object.DontDestroyOnLoad(_driver);
UniLogger.Log($"{nameof(UniPooling)} initalize !");
}
}
/// <summary>
/// 销毁游戏对象池系统
/// </summary>
public static void Destroy()
{
if (_isInitialize)
{
foreach (var spawner in _spawners)
{
spawner.Destroy();
}
_spawners.Clear();
_isInitialize = false;
if (_driver != null)
GameObject.Destroy(_driver);
UniLogger.Log($"{nameof(UniPooling)} destroy all !");
}
}
/// <summary>
/// 更新游戏对象池系统
/// </summary>
internal static void Update()
{
if (_isInitialize)
{
foreach (var spawner in _spawners)
{
spawner.Update();
}
}
}
/// <summary>
/// 创建游戏对象生成器
/// </summary>
/// <param name="packageName">资源包名称</param>
public static Spawner CreateSpawner(string packageName)
{
// 获取资源包
var assetPackage = YooAssets.GetPackage(packageName);
if (assetPackage == null)
throw new Exception($"Not found asset package : {packageName}");
// 检测资源包初始化状态
if (assetPackage.InitializeStatus == EOperationStatus.None)
throw new Exception($"Asset package {packageName} not initialize !");
if (assetPackage.InitializeStatus == EOperationStatus.Failed)
throw new Exception($"Asset package {packageName} initialize failed !");
if (HasSpawner(packageName))
return GetSpawner(packageName);
Spawner spawner = new Spawner(_driver, assetPackage);
_spawners.Add(spawner);
return spawner;
}
/// <summary>
/// 获取游戏对象生成器
/// </summary>
/// <param name="packageName">资源包名称</param>
public static Spawner GetSpawner(string packageName)
{
foreach (var spawner in _spawners)
{
if (spawner.PackageName == packageName)
return spawner;
}
UniLogger.Warning($"Not found spawner : {packageName}");
return null;
}
/// <summary>
/// 检测游戏对象生成器是否存在
/// </summary>
/// <param name="packageName">资源包名称</param>
public static bool HasSpawner(string packageName)
{
foreach (var spawner in _spawners)
{
if (spawner.PackageName == packageName)
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04fd1800aa2e61644893fa7893d93db8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace UniFramework.Pooling
{
internal class UniPoolingDriver : MonoBehaviour
{
void Update()
{
UniPooling.Update();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f4112e0723ed46c45927cc3498d62e5a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,199 @@

namespace UniFramework.Utility
{
public sealed class UniTimer
{
/// <summary>
/// 延迟后,触发一次
/// </summary>
public static UniTimer CreateOnceTimer(float delay)
{
return new UniTimer(delay, -1, -1, 1);
}
/// <summary>
/// 延迟后,永久性的间隔触发
/// </summary>
/// <param name="delay">延迟时间</param>
/// <param name="interval">间隔时间</param>
public static UniTimer CreatePepeatTimer(float delay, float interval)
{
return new UniTimer(delay, interval, -1, -1);
}
/// <summary>
/// 延迟后,在一段时间内间隔触发
/// </summary>
/// <param name="delay">延迟时间</param>
/// <param name="interval">间隔时间</param>
/// <param name="duration">触发周期</param>
public static UniTimer CreatePepeatTimer(float delay, float interval, float duration)
{
return new UniTimer(delay, interval, duration, -1);
}
/// <summary>
/// 延迟后,间隔触发一定次数
/// </summary>
/// <param name="delay">延迟时间</param>
/// <param name="interval">间隔时间</param>
/// <param name="maxTriggerCount">最大触发次数</param>
public static UniTimer CreatePepeatTimer(float delay, float interval, long maxTriggerCount)
{
return new UniTimer(delay, interval, -1, maxTriggerCount);
}
/// <summary>
/// 延迟后,在一段时间内触发
/// </summary>
/// <param name="delay">延迟时间</param>
/// <param name="duration">触发周期</param>
public static UniTimer CreateDurationTimer(float delay, float duration)
{
return new UniTimer(delay, -1, duration, -1);
}
/// <summary>
/// 延迟后,永久触发
/// </summary>
public static UniTimer CreateForeverTimer(float delay)
{
return new UniTimer(delay, -1, -1, -1);
}
private readonly float _intervalTime;
private readonly float _durationTime;
private readonly long _maxTriggerCount;
// 需要重置的变量
private float _delayTimer = 0;
private float _durationTimer = 0;
private float _intervalTimer = 0;
private long _triggerCount = 0;
/// <summary>
/// 延迟时间
/// </summary>
public float DelayTime { private set; get; }
/// <summary>
/// 是否已经结束
/// </summary>
public bool IsOver { private set; get; }
/// <summary>
/// 是否已经暂停
/// </summary>
public bool IsPause { private set; get; }
/// <summary>
/// 延迟剩余时间
/// </summary>
public float Remaining
{
get
{
if (IsOver)
return 0f;
else
return System.Math.Max(0f, DelayTime - _delayTimer);
}
}
/// <summary>
/// 计时器
/// </summary>
/// <param name="delay">延迟时间</param>
/// <param name="interval">间隔时间</param>
/// <param name="duration">运行时间</param>
/// <param name="maxTriggerTimes">最大触发次数</param>
public UniTimer(float delay, float interval, float duration, long maxTriggerCount)
{
DelayTime = delay;
_intervalTime = interval;
_durationTime = duration;
_maxTriggerCount = maxTriggerCount;
}
/// <summary>
/// 暂停计时器
/// </summary>
public void Pause()
{
IsPause = true;
}
/// <summary>
/// 恢复计时器
/// </summary>
public void Resume()
{
IsPause = false;
}
/// <summary>
/// 结束计时器
/// </summary>
public void Kill()
{
IsOver = true;
}
/// <summary>
/// 重置计时器
/// </summary>
public void Reset()
{
_delayTimer = 0;
_durationTimer = 0;
_intervalTimer = 0;
_triggerCount = 0;
IsOver = false;
IsPause = false;
}
/// <summary>
/// 更新计时器
/// </summary>
public bool Update(float deltaTime)
{
if (IsOver || IsPause)
return false;
_delayTimer += deltaTime;
if (_delayTimer < DelayTime)
return false;
if(_intervalTime > 0)
_intervalTimer += deltaTime;
if (_durationTime > 0)
_durationTimer += deltaTime;
// 检测间隔执行
if (_intervalTime > 0)
{
if (_intervalTimer < _intervalTime)
return false;
_intervalTimer = 0;
}
// 检测结束条件
if (_durationTime > 0)
{
if (_durationTimer >= _durationTime)
Kill();
}
// 检测结束条件
if (_maxTriggerCount > 0)
{
_triggerCount++;
if (_triggerCount >= _maxTriggerCount)
Kill();
}
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a9ba1e57e76e1c3498c1e678e2737ab2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: