Unity是 实时3D互动内容创作和运营平台 。
包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。
Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。
也可以简单把 Unity 理解为一个游戏引擎,可以用来专业制作游戏!
Unity小知识点学习
获取某个游戏对象下的所有子物体
在Unity中有时候我们会有这样的需求,拿到某个对象下的所有子对象然后统一做一些事情
我们可以通过GetChild的方式拿到这个物体的子对象,但是挨个拿会很麻烦
所以这里说一个可以拿到所有子对象的方法:GetComponentsInChildren
用法示例:
Unity3D 灵巧小知识点 ☀️ | 获取某个游戏对象下的所有子物体_其他
将脚本挂在到场景中,并赋值某个游戏对象
public GameObject @object;
Transform[] transforms;
void Start()
{
//游戏对象下的子物体激活的没激活的都会被拿到,包括游戏对象本身
//transforms =@objectGetComponentsInChildren<Transform>(true);
//游戏对象下的子物体激活的会被拿到,包括游戏对象本身;没激活的不会被拿到
transforms = @object GetComponentsInChildren<Transform>(false);
//遍历
foreach (Transform t in transforms)
{
//打印拿到的子对象
DebugLog("t的值为:"+t);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
打印结果如下:
Unity3D 灵巧小知识点 ☀️ | 获取某个游戏对象下的所有子物体_非激活_02
可以通过代码控制是否要拿到非激活的子对象,这样就可以通过一个方法拿到所有子对象了!
这里顺便说一下几个常用的方法
获取某个对象子物体数量的方法
a = @objecttransformchildCount;
DebugLog("子物体的数量为:" + a);
1
2
打印结果:
Unity3D 灵巧小知识点 ☀️ | 获取某个游戏对象下的所有子物体_非激活_03
获取当前对象的索引值(当前对象为第几个子类,从0开始)
int child = transformGetSiblingIndex();
1
Unity3D 灵巧小知识点 ☀️ | 获取某个游戏对象下的所有子物体_3d_04
Unity技术支持团队经常会对有需求的客户公司项目进行游戏项目性能审查与优化,在我们碰到过的各种项目相关的问题中也有很多比较共同的方面,这里我们罗列了一些常见的问题并进行了归类,开发者朋友们可以参考下。
(1)资源导入
1纹理没有压缩
在很多情况下,美术会觉得纹理压缩后效果不理想。我们建议的是: 可以把原图的分辨率长宽都扩大一倍,保持原有压缩格式。这样压缩过后的文件还是比不压缩的文件要小,并且视觉效果可以得到较大的改善。
2纹理导入设置中的 Read/Write Enabled 处于勾选状态
开启纹理导入设置中 Read/Write Enabled,纹理在传到GPU之后,CPU端的数据也会一直保留在内存中。因为在移动端显存共享内存,会导致内存占用加倍。 因此需要注意是否有需要在CPU端访问的纹理 ,比如:需要通过脚本获取纹理像素的情况下,就要开启纹理导入设置中的 Read/Write Enabled。
3模型文件导入设置中 Read/Write Enabled 处于勾选状态
除了需要脚本中访问的网格,作为网格碰撞器中的网格,脚本中用StaticBatchingUtilityCombine静态合批的网格,以及粒子系统发射的网格之外,其它模型建议不要勾选此项, 否则会在内存也保留一份网格实例占用内存。
4模型导入设置[Rig]选项页中Optimize GameObject没有勾选
建议开启Optimize GameObject ,这个选项可以把SceneManager中用于skinning的节点都去除,节省了场景节点树更新以及查询的CPU消耗,对于需要做挂点的节点可以添加到例外列表中。
5使用第三方音频插件时没有禁用Unity内置音频
不需要使用Unity内置音频模块的时候,建议Editor中通过勾选Edit->Project Settings->Audio->Disable Unity Audio来完全禁用FMOD模块 ,避免不必要的CPU消耗。
(2)CPU常见性能问题
1频繁调用的Cameramain
建议脚本做好Main Camera的Cache 。Cameramain实际为GameObjectFindGameObjectsWithTag(“MainCamera”)调用,主要因为引擎无法得知用户通过脚本设置的MainCamera,CPU消耗较高。
2脚本中大量UnityEngineObject的判等 *** 作
建议改为用InstanceID来判断 ,即Object GetInstanceID,运行期间保证唯一。 因为Object的判等还有额外的耗时 *** 作,而Int类型的判等就非常快速了。同理,使用Object作为key的数据结构也建议改用InstanceID做key。
3用于查询 *** 作的数据使用list数据结构
List线性结构Contains的耗时非常高,建议改为hashset,hashtable之类的查询 *** 作效率高的数据结构 。
4加载资源时每帧从Assetbundle加载的Asset数量没有限制
在场景内每帧从Assetbundle加载的Asset数建议限制在2到5个 ,数量高时耗时过长容易造成卡顿。
(3)内存常见问题
1加载场景的时候有 一段内存尖峰
常见的情况是 有无索引的资源被加载进来,然后因为UnloadUnusedAssets被卸载掉 。内存尖峰基本都是对游戏本身无用的内存,但是可能会因此造成游戏在内存紧张的机器上被强制关闭。
2静态索引导致的内存泄漏
一些内存占用较大的资源如纹理, 因为有静态索引而无法在切换场景或者调用UnloadUnusedAssets时被卸载掉,因此内存的泄漏量会随着用户切换场景的次数而增加。
这个值越大说明有越多的不必要内存池扩展 ,比如说在同一帧内有加载大量资源,实例化大量对象等,可能让内存池瞬间膨胀的 *** 作。
4GC分配量较大
项目Review过程中,除了CPU时间占用和内存分配量,我们还会留意脚本函数的GC分配。 GC分配越频繁,量越大,由于Mono内存池可用内存不足导致的GCCollect(造成卡顿原因之一)调用就越频繁,并且可能引起mono内存池不必要的扩展,因此脚本函数的GC分配量是既影响CPU也影响内存的重要参数 。
对于GC分配量。我们建议的参考数值为 :
对于基本每帧都会分配GC的函数,GC分配量大于2KB的建议都确认下是否有可能把临时变量抽取出来。对于偶尔分配GC的函数,GC分配量大于10KB的建议都确认下分配的数据结构是否有优化空间。
(4)GPU常见性能问题
1 特效渲染的Pass数量较多
一些特效的渲染可以合并到同一个Pass以节省GPU开销,另外RenderTexture在可以共用的情况下尽量共用
2 同屏面数过多
同屏面数建议在20W以下,较优情况是控制在10W以内
3 UI元素在需要隐藏的时候使用了设置Alpha为0的方式
实际上GPU依然需要对UI mesh进行渲染,建议不要通过设置Alpha为0的方式来隐藏UI。
4 当使用网格作为地形时,适当切分地形网格
在网格顶点数很高情况下需要依靠硬件裁剪来剔除顶点,比较消耗GPU性能,建议按照大概的同屏可见范围来切分地形网格。
5 UI元素过多依赖多层元素的混合来达到美术效果
这样会造成较多的Overdraw,建议尽量通过预制纹理来做到想要的效果。
转自:unity官方中文论坛
感觉你的问题应该有更直接的办法,一是不太懂你的意思,比如你具体是要实现怎样的功能?为什么要根据XY计算,难道同样的装备随机次数不同,power计算也不同? 第一、第二个装备又是什么意思?理论上应该限定总的可装备上限,比如一共就可以装备三个东西,那么你自然需要定义一个三个元素的数组了。如果每个装备名称对应的xy是固定的话,计算power似乎没意义了,还不如把power参数和装备写在一起,而你只要随机xy来取不同装备就行了吧。
以下顺带讲一下写入数据的办法。
(不好意思我用的是JS,语法上转换一下就行了。)
不用playerprefs的方法是:
新建一个类,这个类里面定义你要储存在磁盘上的变量,最后把这个类写成dat文件(binary文件),这样这个类里的数据就写在磁盘上了,以后你就可以随时调取、更新所存储的数据了。
(1)编程时你要用到几个基本的包:
import System;
import SystemRuntimeSerializationFormattersBinary; //用来写binary文件
import SystemIO; //基本的输入输出
详细的你还可以去查net 的MSDN 参考。
(2)你要自定义一个类用来规定数据,比如:
Class GameData {
var itemID:int;
var power:float;
}
(3)你还需要一个实例化的脚本(比如命名成,GameDataManager ),把这个脚本放在一个场景中GameObject上就可以了,这个脚本用来实际 *** 作读取和写入。把这个类做成一个Singleton,就是说仅在整个游戏刚启动时初始化一个静态的实例,而且在此后的场景退出时都不要清除,这样可以避免反复覆盖读取和存储数据的风险。比如:
static var instance:GameDataManager;
Awake() {
if(instance == null){ //当前场景中没有其他实例化的脚本,
DontDestroyOnLoad(gameObject); //那么说现在本脚本是唯一的实例,所以不要销毁
instance = this; //把唯一的静态指针指向自己。
}else if(instance != this){
Destroy(gameObject); //当前场景中已经有了其它实例!说本脚本是重复的实例,销毁!
}
}
(4)接下来要判断是否已经存在先前的存档binary文件,如果没有,就需要初始化一个GameData类。
var myGameData:GameData;
function Start () {
myGameData= Load(); //此处Load()是脚本后面定义的一个读取binary文件Dat的方法
if(myGameData== null){ // 如果没有读取到文件,就初始化一个新的数据类
myGameData= new GameData();
myGameDatapower= 999; // 数据初始化,这里你可以自定义更复杂的方法或算法
Save(); //写入数据,此处Save()也是后面定义的一个存储binary文件Dat的方法
}
}
(5)具体完成Load() 和 Save()方法:
function Save (){
var bFile:BinaryFormatter;
var file:FileStream;
bFile = new BinaryFormatter();
file = FileCreate(ApplicationpersistentDataPath + "/GameDatadat"); //在系统默认应用程序路径创建Dat文件
bFileSerialize(file, currentGameData); // 写入数据
fileClose(); //完成文件
}
function Load ():GameData{
var bFile:BinaryFormatter;
var file:FileStream;
var loadData:GameData;
if(FileExists(ApplicationpersistentDataPath + "/GameDatadat")){//判断dat文件是否存在
bFile = new BinaryFormatter();
file = FileOpen(ApplicationpersistentDataPath +"/GameDatadat", FileModeOpen);//打开系统默认路径中的Dat文件
loadData = bFileDeserialize(file) as GameData; //获取读取到的数据
fileClose();//关闭文件
}
return loadData; //返回获取到的数据类
}
最后,如果你英文过的去,unity的官方网站上有全套视频,其中一个章节就是讲解如何存储数据的!不过前提是你得会 夫安 七一昂,否则视频可能看不了。今年封的更严了,国情你懂的,
1获得Unity和iOS导出器如果您还未获得Unity3D工具,不要说IOS了,恐怕任何Unity3D游戏根本无法进行开发,这时,您首先应该到官网去下载最新版本的Unity。该程序目前有两个版本,分别是免费版(2注册苹果开发者接下来,您需要做的下一件事便是加入苹果开发者,这是继续您IOS开发的必要过程(不注册,不能上传软件,开发了也没意义)。附带一提,加入苹果开发者,需要每年支付99美元。如果您可以承受此代价,那么,您可以通过以下地址进行注册:3下载并安装XCode好了,如果您已经加入苹果开发者,那么,下一件事便是下载并安装XCode了。这在一开始可能会让人困惑,有些初次接触Unity的朋友,可能会认为XCode是为iOS创造原生应用的,关Unity什么事?其实,Unity在IOS开发时,也要使用XCode作为中介将C#或JS代码,编译为IOS的本地应用,再发布到iOS设备中,所以,您真正使用的核心,依旧是苹果XCode,只是Unity3D封装了具体的 *** 作与转化过程,您所有的开发将是发生在Unity上,而非XCode上执行(底层借助Mono实现,而Mono借助LLVM翻译Unity脚本为本地语言)。在这里,XCode的作用只是将内容从Unity导入到具体设备中。您可以从苹果商店中下载XCode:4创造一个开发者配置文件到目前为止,您应该已经下载了Unity(无论正版或破解)以及XCode,并激活了您的苹果开发者身份。但是现在,为了能将您的游戏直接从Unity导入到IOS设备上,您还需要一个开发者配置文件(需要依赖此配置文件,才能让你移植你所开发的游戏或任何测试用例到您的IOS设备上)。具体来说,苹果提供了两种类型的文件配置方式,即用于开发和测试的开发者配置文件以及用于提交到苹果商店的分布配置文件。为了创造开发者配置文件,您需要做3件事:1、注册你的设备2、建立一个应用ID3、获得签名证书。您可以通过你的苹果开发者邮件中的引导,来完成这三件事。具体 *** 作可通过地址:现在选择Certificates,Identifiers和Profiles,您便能够从中访问并管理你的配置文件,苹果ID等等。1)注册你的设备在Certificates,Identifiers和Profiles部分中选择设备。因为这对于苹果去识别用于测试的特定设备是必要的。这并不会改变你的设备的任何设置,你能够轻松地使用自己每天所使用的设备。在注册你的设备时,你可以点击+按键去添加一个新设备。然后你需要填写设备的名字(可以是任何名字)以及UDID(即设备独一无二的ID)。你将会发现自己可以注册一个以上的设备进行测试,如果你想要基于不同设备进行测试的话这边很有帮助(如一台iPhone和一台iPad)。为了找到你的设备的UDID,你需要将你的设备与电脑连接在一起,然后打开iTunes并点击iPhone按键(界面的右上方的),你将看到设备的信息包含了名字。然后你可以将鼠标停在上方并点击SerialNumber,这将变成一个常标识,这便是UDID。这是你需要的数字,你必须将其复制黏贴到MemberCenterPortal的ID部分。现在你便可以注册你的设备了。记住一旦你注册了设备,你便只能改变它的名字而不能改变UDID。2)设置一个应用ID下一步便是设置你的应用ID。仍然在MemberCenterPortal的Certificates,Identifiers和Profiles,选择应用ID并点击+按键。首先提供任何你想要的描述,只要它能够帮助你记得你的ID是用于做什么便可。一个好的方法便是为一款应用使用一个独特的名字并为一款测试应用使用一个普通的名字。接下来你需要设置BundleIdentifier,这是以相反的域符号形式呈现出来“即:com+你的全名(如果你是一名个体开发者的话)+你的游戏名称:comYourNameTheGameName这类型的BundleID将很清楚并只能用于唯一的一款游戏中。因此你需要为你的每一款游戏使用不同的名字。然而这是很有用的,这让你能够访问像“游戏中心”和“应用内部购买”等服务。另一方面,Wildcard的BundleID是以如下形式呈现出来:comYourName这里用星号替代了游戏名字。这种格式让你能够在多款应用中使用同样的ID,而无需每次都设置一个不同的名字,但是这却不允许你使用特定的设备。现在你已经选择了继续并确认了应用ID。将捆绑ID记录下来,因为之后你将需要在Unity的构建设置中使用到它。3)获得开发者证书现在,你需要做的第一件事,便是通过你的计算机获得CertificateSigningRequest。前往Applications>Utilities>KeychaneAccess,然后是Preferences>Certificates。确保OnlineCertificateStatusProtocol和CertificateRevocationList都是处于OFF,并关闭Preference。现在在KeychaneAccess中前往CertificateAssistant并从CertificateAuthority中选择RequestCertificate。提供与你在注册开发者计划时使用的同样细节并点击继续。提供一个名字并保存到Desktop。在保存时选择2048位体和RSA。现在在你的Desktop中应该拥有一个带着certSigningRequest前缀的文件。现在回到MemberCenterPortal的Certificates,Identifiers和Profiles部分,选择Certificates>Development(就像你要获得开发证书那样),然后按压+按键进行创造。选择上传你保存在Desktop中的CertificateSigningRequest。在你提交前,确保向下滚动页面并在IntermediateCertificates中找到WWDRCertificate。在你之后需要的时候可以下载它。现在进行提交,你的CertificateSigningRequest将被发送到苹果并被另外一个你能够下载的内容所取代。它将被命名为:ios_developmentcer所以现在你的Desktop上应该拥有两个证书。即ios_developmentcer和WWDRCertificate,你需要双击这两个证书将其安装于KeychaneAccess。现在你便设置好你的开发者证书了。4)创造配置文件在完成上述三个步骤后,现在的你可以继续去创造配置文件了。仍然在MemberCenterPortal的Certificates,Identifiers和Profiles中,前往ProvisioningProfiles>All并按压+按键去创造一个全新的配置文件。在Development和DistributionProfile中做出选择(这里我们需要的是Development!),然后在下一个屏幕上选择与该配置文件相联系的应用ID,设备和证书(注:这是你在之前步骤已经设置好了的)。最后为配置文件命名并回顾之前的选择。当准备好时点击Generate。现在你便可以看到你的全新配置文件,你需要将其下载到你的Desktop上然后安装它。配置文件将是一个带有mobileprovision前缀的文件。现在转向XCode,前往Window>Organizer>Devices>ProvisioningProfile,然后双击已经下载到你的Desktop上的配置文件。你便完成了安装并能够给予Organizer视图看到它。最后一步非常重要,因为只有将配置文件安装到Xcode,它才能够正常运行。一些额外的内容:仍然在XCode,如果你的设备在Devices视图中仍看不到,那就前往Window>Organizer>Devices,按照名字选择设备。你可能需要在这个过程中选择UseforDevelopment,然后提供你的开发者记录细节。虽然这是一个较为漫长的过程,但好消息是你已经完成工作了!现在,您可以开始致力于你的Unity游戏并准备好导出它。但请记住,您只能注册设备和创造开发者证书一次,每当你创造一款新游戏时你都需要创造一个全新的应用ID和全新的配置文件。5使用Unity发布IOS游戏当您准备好导出你的游戏时,启动Unity3D,选择File>BuildSettings,确保您选择了iOS作为平台,并记得包含当前场景到导出游戏中(使用AddCurrent按键)。然后点击PlayerSeetings按键并前往OtherSettings。将BundleIdentifier按照你之前设置好的进行设置(comYourNameTheGameName),你可能需要将TargetIOS版本设为6(或者未来的最新版本)。除此之外,将所有内容都保持为默认即可,除非您有必须改变它们的理由(特殊设定之类)。然后回到BuildSettingsWindow并点击Build,将项目保持到其自身的文件夹中。此刻,连接你的设备和计算机,打开文件夹并开始XCode项目。你将看到它在XCode中打开。从XCode界面的左上角选择你的设备,然后点击Run按键。
由于数据要序列化,所以要保存类中的字段是可在Unity可序列化的,例如:Type 和 MethodInfo 以及 object 就不行
object不能序列化就导致反射函数的参数需要转换,带来很多麻烦
一、定义保存数据的类
[Serializable]
public class SerializableClass
{
public byte bytedata;
public short shortdata;
public int intdata;
public string stringdata = "";
public float floatdata;
public double doubledata;
public bool booldata;
public Color colordata;
public Vector2 Vector2data;
public Vector3 Vector3data;
public Vector4 Vector4data;
public Vector2Int Vector2Intdata;
public Vector3Int Vector3Intdata;
public AnimationCurve animationCurvedata = new AnimationCurve();
public Gradient gradientdata = new Gradient();
public Ease animationType = EaseLinear;
public UnityEngineObject data = null;
public CustomType type = CustomTypeInt16;
public SerializableClass()
{
}
public SerializableClass(object value)
{
type = (CustomType)EnumParse(typeof(CustomType), valueGetType()Name);
FieldInfo[] fieldinfo = typeof(SerializableClass)GetFields();
for (int i = 0; i < fieldinfoLength; i++)
{
if(fieldinfo[i]FieldType == valueGetType() || valueGetType()IsInstanceOfType(fieldinfo[i]FieldType))
{
fieldinfo[i]SetValue(this, value);
}
}
}
public object GetData()
{
FieldInfo[] fieldinfo = typeof(SerializableClass)GetFields();
for (int i = 0; i < fieldinfoLength; i++)
{
if (fieldinfo[i]FieldTypeName == typeToString())
{
return fieldinfo[i]GetValue(this);
}
}
return data;
}
public void SetValue(object value )
{
if (value == null) return;
if (typeof(UnityEngineObject)IsAssignableFrom(valueGetType()))
type = (CustomType)EnumParse(typeof(CustomType), typeof(UnityEngineObject)Name);
else
type = (CustomType)EnumParse(typeof(CustomType), valueGetType()Name);
FieldInfo[] fieldinfo = typeof(SerializableClass)GetFields();
for (int i = 0; i < fieldinfoLength; i++)
{
if (fieldinfo[i]FieldType == valueGetType() || fieldinfo[i]FieldTypeIsAssignableFrom(valueGetType()))
{
fieldinfo[i]SetValue(this, value);
}
}
}
}
public enum CustomType
{
Byte,
Int16,
Int32,
String,
Single,
Double,
Boolean,
Color,
Vector2,
Vector3,
Vector4,
Vector2Int,
Vector3Int,
AnimationCurve,
Gradient,
Object,
Ease
}
登录后复制

首先把数据分成3种,一种是基础的数据类型例如int、float等,第二种是在Unity种定义的没有继承Object的类型,一般是Unity种的结构体,第三种是Unity中定义的继承与Object的类型,例如继承MonoBehaviour的类。
因为C#中的Type不能序列化,所以自定义CustomType,这个通过对比类型名和CustomType中的字段,区分属于哪种类型。
二、计算
public enum MathParameterEnum
{
[CanUsedType(null, "GreaterThan")]
[TipsName("大于")]
Greater = 0,
[CanUsedType(null, "LessThan")]
[TipsName("小于")]
Less,
[CanUsedType(null, "")]
[TipsName("等于")]
Equal,
[CanUsedType(null, "")]
[TipsName("不等于")]
NotEqual,
[CanUsedType(null, "Add")]
[TipsName("加法")]
Addition,
[CanUsedType(null, "Subtract")]
[TipsName("减法")]
Subtraction,
[CanUsedType(null, "Multiply")]
[TipsName("乘法")]
Multiply,
[CanUsedType(null, "Divide")]
[TipsName("除法")]
Division,
[TipsName("绝对值")]
[CanUsedType(typeof(Mathf) , "Abs")]
Abs = 8,
[TipsName("正切")]
[CanUsedType(typeof(Mathf), "Tan")]
Tan,
[TipsName("余弦")]
[CanUsedType(typeof(Mathf), "Cos")]
Cos,
[TipsName("正弦")]
[CanUsedType(typeof(Mathf), "Sin")]
Sin,
[TipsName("长度归一")]
[CanUsedType(null , "Normalize")]
Normalized = 12,
[TipsName("角度" )]
[CanUsedType(null, "Angle")]
Angle,
[TipsName("距离")]
[CanUsedType(null, "Distance")]
Distance,
}
登录后复制

首先通过自定义特性来简化计算的遍历。这里有三种计算类型,一种是基础类型的加减乘除运算,一种是Mathf类或者其他计算类中的函数,还有一种是数据类型自定义的计算。
其中大部分运算都可以通过反射实现,但是这里有两个问题。
1、隐式转换
例如Vector3 可以和float 相乘,也可以和Int相乘,但是Vector3的自定义运算中并没有和int相乘的函数。因为int可以隐式转换乘float,然后再调用float的运算重载。
因此在计算判断的时候,需要考虑类型能否隐式转换为可计算的类型。
//判断类型是否有隐式转换
public static bool HasImplicitConversion(Type baseType, Type targetType)
{
if (IsNumber(baseType, targetType))
{
if(typeof(double) == targetType && (typeof(long) == targetType || typeof(float) == baseType || typeof(int) == baseType|| typeof(short) == baseType|| typeof(byte) == baseType))
{
return true;
}
if (typeof(float) == targetType && (typeof(long) == targetType || typeof(int) == baseType || typeof(short) == baseType || typeof(byte) == baseType))
{
return true;
}
if (typeof(long) == targetType && (typeof(int) == baseType || typeof(short) == baseType || typeof(byte) == baseType))
{
return true;
}
if (typeof(int) == targetType && (typeof(short) == baseType || typeof(byte) == baseType))
{
return true;
}
if (typeof(short) == targetType && (typeof(byte) == baseType))
{
return true;
}
}
return baseTypeGetMethods(BindingFlagsPublic | BindingFlagsStatic)
Where(mi => miName == "op_Implicit" && miReturnType == targetType)
Any(mi => {
ParameterInfo pi = miGetParameters()FirstOrDefault();
return pi != null && piParameterType == baseType;
});
}
登录后复制

因为C#的基础数据类型,并没有靠op_Implicit去写隐式转换,所以只能手写。
2基本数据的计算
Vector3这种类型的加减乘除可以通过发射寻找计算函数,但是float,int,double等的加减运算就不行了。
public static BinaryExpression CanMath(ParameterExpression type1, ParameterExpression type2, string methodName)
{
try
{
BinaryExpression obj = (BinaryExpression)typeof(Expression)InvokeMember(methodName,
SystemReflectionBindingFlagsInvokeMethod | SystemReflectionBindingFlagsStatic
| SystemReflectionBindingFlagsPublic, null, null,
new object[] { type1, type2 });
return obj;
}
catch (Exception e)
{
return null;
}
}
登录后复制

public static object MathNumber(List<object> allobj, MathParameterEnum mathtype)
{
Type baseType = null;
for (int i = 0; i < allobjCount; i++)
{
Type nowtype = allobj[i]GetType();
if (baseType == null)
baseType = nowtype;
else
{
if (nowtype != baseType)
{
if (!HasImplicitConversion(nowtype, baseType))
{
if (HasImplicitConversion(baseType, nowtype))
{
baseType = nowtype;
}
else
return null;
}
}
}
}
CanUsedType obsAttr = GetEnumMathTip(mathtypeGetType()GetField(mathtypeToString()));
ParameterExpression _ParaA = ExpressionParameter(baseType, "a");
ParameterExpression _ParaB = ExpressionParameter(baseType, "b");
BinaryExpression _BinaAdd = CanMath(_ParaA, _ParaB, obsAttrmethodName);
if (_BinaAdd == null) return null;
Expression<Func<double, double, double>> doubleLamb;
Expression<Func<float, float, float>> floatLamb;
Expression<Func<long, long, long>> longLamb;
Expression<Func<int, int, int>> intLamb;
Expression<Func<short, short, short>> shortLamb;
if (baseType == typeof(double))
{
doubleLamb = ExpressionLambda<Func<double, double, double>>(_BinaAdd, new ParameterExpression[] { _ParaA, _ParaB });
double data = ConvertToDouble(allobj[0]);
for (int i = 1; i < allobjCount; i++)
{
data += doubleLambCompile()(data, ConvertToDouble(allobj[i]));
}
return data;
}
else if (baseType == typeof(float))
{
floatLamb = ExpressionLambda<Func<float, float, float>>(_BinaAdd , new ParameterExpression[] { _ParaA, _ParaB });
float data = ConvertToSingle(allobj[0]);
for (int i = 1; i < allobjCount; i ++)
{
data = floatLambCompile()(data , ConvertToSingle(allobj[i]));
}
return data;
}
else if (baseType == typeof(long))
{
longLamb = ExpressionLambda<Func<long, long, long>>(_BinaAdd, new ParameterExpression[] { _ParaA, _ParaB });
long data = ConvertToInt64(allobj[0]);
for (int i = 1; i < allobjCount; i++)
{
data = longLambCompile()(data, ConvertToInt64(allobj[i]));
}
return data;
}
else if (baseType == typeof(int))
{
intLamb = ExpressionLambda<Func<int, int, int>>(_BinaAdd, new ParameterExpression[] { _ParaA, _ParaB });
int data = ConvertToInt32(allobj[0]);
for (int i = 1; i < allobjCount; i++)
{
data = intLambCompile()(data, ConvertToInt32(allobj[i]));
}
return data;
}
else if (baseType == typeof(short))
{
shortLamb = ExpressionLambda<Func<short, short, short>>(_BinaAdd, new ParameterExpression[] { _ParaA, _ParaB });
short data = ConvertToInt16(allobj[0]);
for (int i = 1; i < allobjCount; i++)
{
data = shortLambCompile()(data, ConvertToInt16(allobj[i]));
}
return data;
}
return null;
}
登录后复制

这种方式虽然还是很麻烦,但是比用if else 简单了很多很多。
(T)ConvertChangeType(dataValue, typeof(T)); 应用为类型转换为范型
以上就是关于unity怎么用代码获得当前激活的子类全部的内容,包括:unity怎么用代码获得当前激活的子类、【unity官方】Unity项目常见问题、unity中游戏装备数据怎么 建立,存储和读取等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)