关于Unity2018最新杏彩合买源码新增腾讯分分彩完整版带手机端新版ECS框架

关于Unity2018最新杏彩合买源码新增腾讯分分彩完整版带手机端新版ECS框架
杏彩源码下载Q212303635 论坛:aqiulian.com先说说和它一同推出的,和ECS没直接关系的新特性:
NativeArray<T>
按照官方的说法,以后还会有NativeList,NativeHashMap,NativeQueue之类(这些在C#端就能实现)。

NativeArray内部只能容纳值对象。而且在创建的时候除了指定length外,还需要指定allocator模式:

Temp(临时)
TempJob(Job内临时)
Persistent(持久)
按文档的说法,这种Native的数组更加有助于数据的连续性,对cache友好。但仅仅如此的话,一个普通的只包含struct的Array也可以达到同样的效果。

我个人是相当怀疑这玩意儿其实是在非托管堆上申请的内存,也就是和Mono的内存管理没啥关系,毕竟这东西是Jobs系统必须的东西,而Jobs看上去和C++部分走的很近。从名字上,也比较像。

先不管这个。至少从表面上看,它就是个普通的struct数组。

使用struct数组其实并不是为了减少GC(虽然实际上也大幅减少了),目的是为了更快的内存访问速度,在访问速度上通常能提高>100%的效率。这个和GPU里对纹理的cache是一样的道理,数据会先从内存到达二级缓存,在二级缓存内的读取速度远大于内存,而连续的内存会很大概率被提前放进二级缓存中。

在CPU的工作过程中,数据的读取成为瓶颈的情况其实并不罕见,只是我们平时使用的情况下,很多数据本来就是连续的,所以连续性相当不友好的“链表”才较少被使用。这种整块的内存结构也能减轻内存管理器整理内存的成本。

即使,数据读取确确实实没有成为瓶颈,但CPU内的晶体管可不是光用来计算的,也有很大一部分用于数据存取,减少它们的工作量会很明显的降低功耗和发热。

这点在GPU上提得比较多。但其实,只要是芯片,都是一样的。

另一个就是提供了SIMD的可能性……只是可能性而已。

不过C#里struct的使用有一个“复制”的大坑。因为C#不提倡使用指针,在存取数组里struct数据的时候只能多次复制,语言特性注定这个问题现在没法解决,所以虽然struct大家都知道好处,真去用它却是不现实的。

而最新版的C#7则适时提供了local/return ref进行了支持。

但目前的Unity最多支持到C#6。

你们也知道这事儿啊……
所以这个框架的存在确实有可能会督促Unity将Mono编译环境升级到C#7,那样struct就能真正开始用了。没这玩意儿struct很容易搞成负优化的。
Jobs System
ECS的一个重要特性就是并发优势,甚至可以说,不支持多并发的ECS几乎没有价值。

(多线程可以支持多核执行,在单核天花板已经到达的现在,多核逻辑的时代也差不多该到了。而ECS是少数有可能自动实现多核的逻辑架构,因为提供了数据隔离的依据。)

Jobs是Unity自己的多线程框架,在这里就对ECS提供了支持。

public class RotationSpeedSystem : JobComponentSystem
{
[ComputeJobOptimization]
struct RotationSpeedRotation : IJobProcessComponentData<Rotation, RotationSpeed>
{
public float dt;
public void Execute(ref Rotation rotation, [ReadOnly]ref RotationSpeed speed)
{
rotation.Value = math.mul(math.normalize(rotation.Value), math.axisAngle(math.up(), speed.Value * dt));
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
var job = new RotationSpeedRotation() { dt = Time.deltaTime };
return job.Schedule(this, 64, inputDeps); //64指单个时间片内至少循环64次
}
}
整套东西使用起来还是很简单的,用实现IJobProcessComponentData<T1, T2...>的类标记要读写的ComponentData,Execute是逻辑,然后用Schedule推入Jobs系统。按这个模板书写就行了。

[ReadOnly][WriteOnly]元标签可以指定Component的读写模式,将数据进一步分离。

剩下就是归系统内部调配了,会在不产生线程冲突的情况下分配逻辑线程的时间片,实现高效率的并发。

上面这个IJobProcessComponentData是ECS框架实现的一个比较简便的用法(不需要写循环,只写其中一个循环节就可以了),本身是IJob的一个扩展,可以点进去看看稍微原始一点的写法。如果在循环前后还有处理,或者需要对数组做筛选就必须用这个了。

ISharedComponentData
这个不是个底层相关特性,却是个很有趣的东西。

与普通的IComponentData不同,虽然都是struct,如果你先初始化它的值再给每个Entity用AddSharedComponent附加上它的话,并不会产生复制,只会占用一块内存(估计传过去的是地址)

只是读取很正常,但当你修改某个Entity上它的副本的时候,它会把自己立即复制一份,然后应用这个修改。

这玩意儿很类似PSS或者WindowDLL共享内存的做法,充分体现了“这是一个性能框架”的特征。

不过认真一想……

这东西不就是shareMaterial和material的关系么……

至于这个ECS框架本身……
其实还是很传统的。Entitiy实际上是一个int,ComponentData也就是普通的struct,System则是各种系统事件的接受者,类似MonoBehaviour。他们都只要实现对应的接口就能实现功能。在用EnitityManager创建Entity,添加Component之后(和原来的GameObject一样),System逻辑就会自动生效。

System的逻辑实现,是在特定的事件上(如OnUpdate)用自定义的代码拉取一些Component数组来执行自己的逻辑,主要用的就是GetEntities<Group>方法,这会按Group的内容,拉取指定的Component数组出来,然后遍历就可以了。

(注意拉取的是整个场景上同类型的所有Component,而不是一个)

拉取的时候会进行筛选,没有添加指定Component的Entitiy并不会被拉取(除此之外,还可以用ComponentGroup设置筛选条件)

总之就是每个System手动遍历一遍指定的Component执行逻辑了——但也可以不遍历,或者遍历多次,两两交叉遍历都是可以的,因为全都是自定义代码,就算是JobComponentSystem也一样。不要被上面的Job的简单例子误导,用IJob就可以在Jobs里写任意逻辑了,并不需要一定按循环走。

所以,System其实就是MonoBehaviour(删除数据后)的集合体,MonoBehaviour执行一个Entity的逻辑,而System执行全部的。

class RotatorSystem : ComponentSystem
{
struct Group
{
RotateComponentData rotation;
SpeedComponentData speed;
}

override protected OnUpdate()
{
    float deltaTime = Time.deltaTime;
    foreach (var e in GetEntities<Group>())
    {
        e.rotation *= Quaternion.AxisAngle(e.speed * deltaTime, Vector3.up);
    }
}

}

执行顺序
然后有心人就会意识到,MonoBehaviour执行顺序不确定的问题在这里依然存在……

虽然并发的系统本来就希望允许乱序执行嘛,系统还是给了方法确定顺序的,只要在System上加元标签就行了:

[UpdateBefore(typeof(RotationSpeedSystem))]

觉得可以乱序执行的部分不加就是了,在使用Jobs的时候不限制顺序才能增加性能。

对GameObject系统的支持
ECS和原有的GameObject+MonoBehaviour功能其实并没有完全重合。至少在现在,Transfrom,Renderer和物理组件依然必须挂接在GameObject上,并且不挂在GameObject上也无法在场景里编辑。

Entity本来是用EntityManager.CreateEntity()来创建,然后这样进行复制的(非必须)

EntityManager.Instantiate(entity, instances);
但是如果你把上面参数里的entity换成一个Prefab对象的话,它也能正常执行,并和GameObject.Instantiate一样生成一个可显示的GameObject对象,并且照常生成对应的entity。这些生成的entity就是和GameObject绑定的存在了,也就把GameObject引入了ECS系统。

对于引入ECS的GameObject,不管是GameObject还是上面的组件都可以和ComponentData一样管理。

虽然Renderer之类必须得是Behaviour组件,但是一些挂载在GameObject用来填写数据的脚本,我们显然还是希望它们进入系统用的是ComponentData,而不是旧版的MonoBehaviour。

另外,我们的ComponentData也是需要能够在编辑器环境显示以及编辑的,而ComponentData并不能挂在GameObject上。

这个框架提供了一个桥接类来处理这个问题:

[Serializable]
public struct Radius : IComponentData
{
    public float radius;
}

public class RadiusComponent : ComponentDataWrapper<Radius> { } 

下面那个RadiusComponent 是可以正常挂到脚本上的。而在ECS系统内,它则会被处理隐式地处理成Radius。

依赖注入
使用[Inject]标签,可以根据字段类型自动注入一些数据。

public struct Group
{
//获得某个类型的ComponentData
public ComponentDataArray<Position> Position;

    //获得某个类型的Component(这里的Component指的是原本的Unity组件)
    public ComponentArray<Rigidbody> Rigidbodies;

    //获得Entity列表
    public EntityArray Entities;

    //获得GameObject列表
    public GameObjectArray GameObjects;

    //标识排除所有包含MeshCollider的对象
    public SubtractiveComponent<MeshCollider> MeshColliders;

    //数据数量
    public int Length;

}
[Inject]Group m_Group;
和之前GetEntities<Group>不同,这次的Group的不会返回迭代器,所以Group里的字段本身就必须是数组。但依然会进行筛选,并且按Entity顺序排列。

[Inject]OtherSystem m_SomeOtherSystem;
用这个方法可以直接和另一个System通信。这个框架并没有提供任何和解耦相关的东西,所以System间通信都是直接调用。

[Inject]ComponentDataFromEntity<LocalPosition> m_LocalPositions;

Entity myEntity = ...;
var position = m_LocalPositions[myEntity];
这个东西看上去和GetEntities<Group>差不多(除了只能获得一个Component外),但其实功能完全不同。GetEntities会做筛选,而它不会。

但为啥不直接用EntityManager.GetComponentData<LocalPosition>(myEntity)就不了解了,可能是性能问题吧。

EntityCommandBuffer
写过物体管理系统的都会遇到“遍历中增删对象”这个麻烦的问题。虽然确实可以用倒序遍历处理,但其实这样很不稳定,而且很可能出现删除未遍历到的对象这个问题,然后产生非必现错误。

通常的做法就是将所有这些操作延后执行。

这个框架里虽然没有这个问题,但是在多线程的时候,增删对象依然会产生较大的数据变动,这容易对同时运行的其他线程产生阻塞,就依然需要进行延后处理。

可以在一个调用次数靠后的System(SystemA)调用CreateCommandBuffer()创建EntityCommandBuffer对象,然后把它的实例传给其他需要增删对象的System(SystemB),调用这个实例的函数来负责增删。

这样增删操作会延迟到SystemA时才执行。

由于系统会特地将增删操作向后延迟,所以SystemA不做任何处理就会是最后一个执行的System,像示例里那样,用一个空System当这个SystemA也是可以的。

RemoveDeadSystem.cs

对方的文档也不全,先这样吧。

其实这次除了ECS,Jobs的部分存在感也极强。你们可以看看下面这个是啥玩意儿……

NativeCounter.cs?github.com图标

另外这个玩意儿什么时候加进来的?

using System;
using System.Runtime.CompilerServices;
using UnityEngine.Collections;

namespace UnityEngine
{
internal static class UnsafeUtility
{
public unsafe static void CopyPtrToStructure<T>(IntPtr ptr, out T output) where T : struct
{
output = *ptr;
}

    public unsafe static void CopyStructureToPtr<T>(ref T output, IntPtr ptr) where T : struct
    {
        *ptr = output;
    }

    public unsafe static T ReadArrayElement<T>(IntPtr source, int index)
    {
        return *(source + (IntPtr)index);
    }

    public unsafe static void WriteArrayElement<T>(IntPtr destination, int index, T value)
    {
        *(destination + (IntPtr)index) = value;
    }

    public static IntPtr AddressOf<T>(ref T output) where T : struct
    {
        return ref output;
    }

    public static int SizeOf<T>() where T : struct
    {
        return UnsafeUtility.SizeOfStruct(typeof(T));
    }

    public static int AlignOf<T>() where T : struct
    {
        return 4;
    }

    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern IntPtr Malloc(int size, int alignment, Allocator label);

    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern void Free(IntPtr memory, Allocator label);

    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern void MemCpy(IntPtr destination, IntPtr source, int size);

    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern int SizeOfStruct(Type type);

    [MethodImpl(MethodImplOptions.InternalCall)]
    public static extern void LogError(string msg, string filename, int linenumber);
}

}
ps.其实个人认为ECS框架以后会慢慢和传统的MVC架构等这种注重继承的游戏框架结合并且这种可能性是很大的。一个是随着网络数据交互量的增加(主要由于网速加快,网络资费便宜),二呢是因为随着游戏的创新发展更多的玩法功能将被实现出来,所以游戏设计不在是传统的功能设计,对功能的要求更多的是想搭乐高一样的实现。三呢现在游戏中具体的业务逻辑实现确实需要一套框架来进行规范。

原文地址:http://blog.51cto.com/13853718/2136660

时间: 2024-08-01 22:47:50

关于Unity2018最新杏彩合买源码新增腾讯分分彩完整版带手机端新版ECS框架的相关文章

合买源码搭建建与MySQL · 引擎特性

一 序本文根据<MYSQL运维内参>第11章INNODB日志管理机制整理,本篇书上侧重于原理说明日志的生成.格式.工作原理.刷盘机制等.限于篇幅,崩溃恢复的需要单独整理.InnoDB 有两块非常重要的日志,一个是undo log,另外一个是redo log,前者用来保证事务的原子性以及InnoDB的MVCC,后者用来保证事务的持久性.解释下redolog与事务持久性:redo log用来数据异常恢复和数据库重启时页数据同步恢复,redo log是建立在在mini transaction基础上.

2014年最新720多套Android源码2.0GB免费一次性打包下载

之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年3月份开始不断整理源码区和其他网站上的android源码,目前总共有720套左右,根据实现的功能被我分成了100多个类,总共2G多,还在不断更新安卓源码.初学者可以快速方便的找到自己想要的例子,大神也可以看一下别人的方法实现.虽然的例子都是我一个人辛辛苦苦花了很多时间和精力整理的,但是既然这些例子是来自于社区那就让他们免费回归社区吧,(是的!特么的不要一分钱!最看不起那些挂羊头卖狗的)你可以在本帖里面按Ctrl+F查找你

网狐棋牌源码搭建2017年最新网狐荣耀棋牌源码搭建下载

2017年最新网狐荣耀棋牌源码:含大厅全套源码+客户端+服务端+网站+后台+完整数据库 (更多详情网狐棋牌源码搭建 www.yasewl.com QQ:2189563389)

腾讯分分彩源码带龙虎和玩法自言自语Spring依赖注入(XML配置)

至于基于XML依赖注入的过程,首先要找一个比较合适的入口,那就是getBean.那么具体是怎么实现的呢?首先写个测试方法: ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("application-common.xml","application-beans.xml","application_jdbc.xml");Object obj = app.g

彩38完整源码下载+带H5自适应手机版

彩38完整源码下载+带H5自适应手机版源码下载Q:2947702644运行环境:WIN+APACHE+PHP5.4+MYSQL5.6+伪静态源码授权:无加密文件及认证授权,永久性可直接使用.版本支持:PC/WAP网页版编程语言:PHP开发框架:ThinkPHP框架开发ThinkPHP是一个框架:MVC(采用面向对象思想)框架 市面上常用的框架: zend framework yii thinkPHP ThinkPHP: 有完善的中文资料,使用相对来说比较多 下载ThinkPHP 解压之后生成两个

Java程序员腾讯分分彩源码出售的5年职业规划

第1部分 在搭建SSM的腾讯分分彩源码出售(www.1159880099.com)QQ1159880099 过程中,可能会经常接触到一个叫maven的工具.这个工具也是你以后工作当中几乎是必须要使用的工具,所以你在搭建SSM的过程中,也可以顺便了解一下maven的知识.在你目前这个阶段,你只需要在网络上了解一下maven基本的使用方法即可,一些高端的用法随着你工作经验的增加,会逐渐接触到的. 第2部分: 对于参加工作一年以内的同学.恭喜你,这个时候,你已经拥有了一份Java的工作.这个阶段是你成

redis-5.0 cluster带腾讯分分彩出售认证及客户端连接

Redis在3.0版腾讯分分彩出售dsluntan.com Q:3393756370 VX:17061863513正式引入redis-cluster集群这个特性.Redis集群是一个提供在多个Redis间节点间共享数据的程序集.Redis集群是一个分布式(distributed).容错(fault-tolerant)的Redis内存K/V服务,集群可以使用的功能是普通单机Redis所能使用的功能的一个子集(subset),比如Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间

企业站点如何做高质量的外链?腾讯分分彩官网

经常做外链的朋友都知道,外链难做.外链掉得快.外链质量低.网站得分也低,垃圾外链.黑链等问题.这些问题直接或是间接影响着网站的权重.那么企业又该如何做高质量的外链呢?我这里有几个建议,可解决企业站问题,供大家参考.(www.txfencai.com腾讯分分彩官网) 一.外链资源多样化,做为企业站.因为行业局限性,资源本来就少,在这种情况之下 就要多样化,注册几个B2B平台.博客平台.百度文库.百度贴吧.行业论坛等高权重的网站上发外链.减少被掉的风险. 二.用站群做外链,以站养站,重点是每个站都要

彩票稳赢计划:腾讯分分彩刷流水方法

简码编程在写<如何提高彩票胜率>系列的过程中,发现某些网站有充值优惠活动,首次充值1000元赠送68元,于是一个彩票稳赢计划随之产生. 此充值优惠活动的规则是首次充值满1000元,赠送68元,所赠送的余额需要在流水够充值额时才能提现,即是实充1000元帐户得1068元,要打够1000元流水才可以提现. 那么可以如下操作.先用一个大号开AB两个小号,每个小号各充1000元,则每个小号的余额都有了1068元.然后两个小号对刷流水,比如小号A投单,则小号B投双,小号A投大,则小号B投小.这样两个小号