实现定时器并不复杂,就是写个类存放回调,再写个类来统一管理这些回调类。但是ECS写代码的方式变了,所以还是有些区别的。
实现过程中需要注意的几点:
1、由于IComponentData不能存放managed类型的数据,所以无法用常规的ECS方式来存放定时器数据,只能用一个NativeHashMap作为SystemBase里的一个字段来存数据了。
2、常规来说,NativeList肯定比NativeHashMap的内存占用小的,但是用过后发现List要在遍历过程中删除元素实在是不好看,就只能用Map了。不过影响不大。
3、试过回调的保存用c#官方的delegate,但是打包WASM到浏览器上运行,报了个错“function signature mismatch”
。没有深入处理,直接放弃了该用法。也试过用Unity.Burst自带的FunctionPointer函数指针,但是有个限制,函数不能作为类的实例方法,只能是static的静态方法,而static方法遍历IComponentData很不方便,也只能放弃。
4、目前的实现方法有个小小的瑕疵,但不影响功能。就是每个SystemBase里只能实现一个定时器回调,如果需要实现一个每2秒执行一次的回调,和一个每1秒执行一次的回调,就不行,只能分开在两个SystemBase里。由于SystemBase是class来的,太多的话,创建和销毁会涉及到GC,对性能有一点影响。
不过新版的Entities有了ISystem,是struct类型的,可以随便创建删除,且可以完全BurstCompile的。ProjectTiny无法更新到新版,只能先这样用着。用法跟MonoBehavior实现的差不多,可以添加任意间隔,重复执行的回调,也可以添加指定执行几次或间隔执行一次的回调。看代码:
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using System.Runtime.CompilerServices;
using System;
namespace wangtal.ClockSystem {
#pragma warning disable 660, 661
[BurstCompile]
public readonly struct ClockHandle : IEquatable<ClockHandle>{
private static uint _uid = 1;
internal static uint uid => _uid++;
public static ClockHandle Null = new ClockHandle(0);
private readonly uint Id;
internal ClockHandle(uint id) {
Id = id;
}
bool IEquatable<ClockHandle>.Equals(Tiny3D.ClockHandle other) {
return this == other;
}
public static bool operator ==(ClockHandle left, ClockHandle right) {
return left.Id == right.Id;
}
public static bool operator !=(ClockHandle left, ClockHandle right)
{
return left.Id != right.Id;
}
public override string ToString() {
return $"id:{
Id}";
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
#pragma warning restore 660, 661
public interface IClockExecutor {
void Execute();
}
// public delegate void Callback(/*EntityManager entityManager*/);
[BurstCompile]
internal struct Clock {
internal readonly ClockHandle Handle;
// function signature mismatch
// internal readonly /*FunctionPointer<Callback>*/Callback FunctionPointer;
internal readonly IClockExecutor Executor;
// 负数代表无限循环,0代表结束循环了,大于0代表重复执行次数
internal int Repeat;
// 毫秒数
internal double StartTime