选自过去1~2周 自己所看到外文内容:https://twitter.com/unity3d 和各种其他博客来源吧
1、 看到一个帖子: https://qiita.com/chocho/items/51b65c2601c67e5cc6d2
通过脚本克隆UI.Button时,也会复制onClick事件 ! 具体说是:
1).如果在脚本中完成AddListener()。(这个将不是永久性的)
onClick事件未复制。不能接管
2).从Inspector 面板上进行事件绑定时。(这个将是永久的)
onClick事件也被复制。被接管
想要拷贝之后删除原来的监听 就要关闭:
int persistentEventCount = btn.onClick.GetPersistentEventCount();
for (int i = 0; i < persistentEventCount; i++)
btn.onClick.SetPersistentListenerState(i, UnityEventCallState.Off);
https://docs.unity3d.com/2018.3/Documentation/ScriptReference/UI.Button.ButtonClickedEvent.html
https://docs.unity3d.com/jp/current/ScriptReference/Events.UnityEventCallState.html
https://docs.unity3d.com/jp/current/ScriptReference/Events.UnityEventBase.GetPersistentEventCount.html
2、 在UI.Image上绘画 一条线。
https://qiita.com/chocho/items/d5125ed051b22e95709c
3、 获取[Unity] AssetDatabase中的所有资产类型名称
public Type[] GetAllAssetClassTypeInfo()
{
return AssetDatabase.FindAssets("t:object").Select(guid => new
{
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
return AssetDatabase.GetMainAssetTypeAtPath(assetPath);
}).Distinct(); // 重复的类型信息将不会在Distinct中重复
}
4、 当Unity的Log 中发生错误类型时, 打开一个窗口:
public class ErrorReceivedWindow : EditorWindow
{
[InitializeOnLoadMethod]
private static void _onInit()
{
Application.logMessageReceived += ApplicationOnLogMessageReceived;
}
private static void ApplicationOnLogMessageReceived(string condition, string stacktrace, LogType type)
{
if (type == LogType.Exception)
{
GetWindow();
}
}
}
5、 原来 Inspector上显示的 Rotation角度并不一定就是 。 transform.localEulerAngles
我之前以为就是一个值。
Debug.LogError(" " + transform.localEulerAngles);
Debug.LogError(" " + transform.localRotation.eulerAngles);
UnityEditor.SerializedObject serializedObject = new UnityEditor.SerializedObject(transform);
UnityEditor.SerializedProperty serializedEulerHint = serializedObject.FindProperty("m_LocalEulerAnglesHint");
Debug.LogError(serializedEulerHint.vector3Value);
参考帖子: https://forum.unity.com/threads/how-to-get-euler-rotation-angles-exactly-as-displayed-in-the-transform-inspector-solved.425244/
6、 如果查看 Unity开源出来的 UnityCsReference 会发现一个 不知道的隐藏功能。我们来介绍一个例子。
https://connect.unity.com/p/unitycsreferencededuo-kunozhi-shi-woqu-riru-reyou
AboutWindow类有一个名为 ListenForSecretCodes的方法。当我阅读代码时...在窗口中输入Internal似乎切换到InternalMode 。 如果退出这个模式 就在输入一下 Internal
然后就会出现一些菜单:
7、【Unity】示例编辑器扩展,以获取Unity项目中包含的所有场景文件的路径
var list = AssetDatabase
.FindAssets( "t:scene" )
.Select( AssetDatabase.GUIDToAssetPath )
;
// 或者
var list = AssetDatabase
.GetAllAssetPaths()
.Where( c => c.EndsWith( ".unity" ) )
;
[Unity]“EditorSceneManager.GetSceneManagerSetup”,可以获取 层次结构中存在的所有场景的信息
[MenuItem( "Tools/Hoge" )]
private static void Hoge()
{
var list = EditorSceneManager.GetSceneManagerSetup();
foreach ( var n in list )
{
var sb = new StringBuilder();
sb.AppendLine( $"path: {n.path}" );
sb.AppendLine( $"isLoaded: {n.isLoaded}" );
sb.AppendLine( $"isActive: {n.isActive}" );
Debug.Log( sb.ToString() );
}
}
8、 【Unity】如何将附加到游戏对象的所有MonoBehaviour的信息输出为JSON
using System.Linq;
using UnityEngine;
public class Example : MonoBehaviour
{
private void Start()
{
var list = GetComponents()
.Select( c => JsonUtility.ToJson( c, true ) )
;
var str = string.Join( "\n", list );
Debug.Log( str );
}
}
9、 [Unity]扩展方法,当从脚本中切换uGUI的isOn时,不希望触发onValueChanged
using UnityEngine.UI;
public static class ToggleExt
{
public static void SetIsOnWithoutCallback( this Toggle self, bool isOn )
{
var onValueChanged = self.onValueChanged;
self.onValueChanged = new Toggle.ToggleEvent();
self.isOn = isOn;
self.onValueChanged = onValueChanged;
}
}
怎么用?
var toggle = GetComponent();
toggle.isOn = true; // onValueChanged 触发
toggle.SetIsOnWithoutCallback( true ); // onValueChanged 不触发
10、 [Unity]如何创建可在创建新项目时选择的自定义模板
http://baba-s.hatenablog.com/entry/2019/03/18/090000
11、 宣雨凇 分享:一个查堆内存泄漏的神器。
简介: https://forum.unity.com/threads/wip-heap-explorer-memory-profiler-debugger-and-analyzer-for-unity.527949/
下载: https://bitbucket.org/pschraut/unityheapexplorer/src
好文值得收藏!
GPU大百科全书前传 看图形与装修的关系 O网页链接
GPU大百科全书第一章:美女 方程与几何 OGPU大百科全书第一章:美女 方程与几何
GPU大百科全书第二章 凝固生命的光栅化 O网页链接
GPU大百科全书第三章:像素处理那点事儿 O网页链接
GPU大百科全书第四章:虚与实共舞的TMU O网页链接
GPU大百科全书第五章 桌面显卡的捍卫者 O网页链接
GPU大百科全书第六章 谁也离不开的缓冲 O网页链接
GPU大百科全书最终章:33毫秒的咏叹调 O网页链接
还在 <<1 符号 | 符号 来添加多个layer层吗?
发现一个深坑,unity的RichText标签会生成大量废顶点。我就说怎么玩家名字一长就无法合批了
最近发现一个问题, 虽然关闭了日志输出但是字符串拼接部分依然会产生大量堆内存。最好的办法还是用条件编译Conditional 将无用的函数整体剥离出去。
不影响原有布局拓展RectTransform。
在 LINE 的官方工程师博客上发了一篇关于通过 wrap native library 做 Unity 插件的文章,包括一些挑战和集成方面的内容..以后还是要多锻炼用英文写文章- -…
https://engineering.linecorp.com/en/blog/wrapping-a-native-sdk-for-unity/
12、 Unity3d UI Automation with Selenium
https://medium.com/@autoplay.automation/unity3d-ui-automation-with-selenium-87030ab7b62a
一个开源的自动化测试: GitHub: https://github.com/AutoplayAutomation
13、 又是一个在Inspector上弄游戏的人: 如何在Unity编辑器中制作太空侵略者
https://github.com/bzgeb/AlienInvadersEditorDemo/
https://connect.unity.com/p/how-to-make-space-invaders-inside-a-unity-editor
14、 [Unity]“渲染队列Unity扩展”简介,可以显示Unity项目中存在的所有材质和着色器的渲染队列。
https://github.com/FreyaHolmer/Render-Queue
15、[Unity]“Unity Heap Crawler”简介,您可以在其中看到静态变量,Hierarchy对象,预制件,ScriptableObject等使用了多少堆变量的细分。
https://github.com/vasyab/UnityHeapCrawler
using System.Linq;
using UnityEngine;
public class Example : MonoBehaviour
{
public class Pokemon
{
public string m_name = "皮卡丘";
}
public static Pokemon[] m_pokemons = Enumerable
.Range( 0, 1000000 )
.Select( c => new Pokemon() )
.ToArray()
;
}
例如,使用静态变量定义类Pokemon的数组,
创建1,000,000个元素,执行“Unity Heap Crawler
”并打开输出“2-static-fields.txt”。 ,
因此,您可以看到m_pokemons数组使用30.5 MB
Example.m_pokemons [Pokemon[]] 30.5 MB ★ Keywords.keywords [LookupTable] 545.5 KB root [Node] 545.4 KB UIElementsUtility.s_UIElementsCache [Dictionary`2 entries [Entry[]] 379.2 KB ... EditorGUIUtility.s_GUIContents [Hashtable] 326.6 KB buckets [bucket[]] 326.5 KB Keywords.keywords [LookupTable] 285.5 KB root [Node] 285.5 KB
... |
16、 【Unity】编辑器扩展示例
[Unity] 如何从编辑器扩展中的Unity项目中获取指定类型的ScriptableObject。例如,获取名为HogeSettings的ScriptableObject
var settings = AssetDatabase
.FindAssets( "t:HogeSettings" )
.Select( c => AssetDatabase.GUIDToAssetPath( c ) )
.Select( c => AssetDatabase.LoadAssetAtPath( c ) )
.FirstOrDefault();
【Unity】示例编辑器扩展,以获取Unity项目中包含的所有材料
using System.Linq;
using UnityEditor;
using UnityEngine;
public static class Example
{
[MenuItem( "Tools/Hoge" )]
private static void Hoge()
{
var list = AssetDatabase
.FindAssets( "t:Material" )
.Select( AssetDatabase.GUIDToAssetPath )
.Select( c => AssetDatabase.LoadAssetAtPath( c ) )
.Where( c => c != null )
;
foreach ( var n in list )
{
Debug.Log( n.name );
}
}
}
【Unity】示例编辑器扩展,用于获取Unity项目中包含的所有预制件
using System.Linq;
using UnityEditor;
using UnityEngine;
public static class Example
{
[MenuItem( "Tools/Hoge" )]
private static void Hoge()
{
var list = AssetDatabase
.FindAssets( "t:Prefab" )
.Select( AssetDatabase.GUIDToAssetPath )
.Select( c => AssetDatabase.LoadAssetAtPath( c ) )
.Where( c => c != null )
.Where( c => c.name != "DataPrivacyButton" )
.SelectMany( c => c.GetComponentsInChildren( true ) )
.Select( c => c.gameObject )
;
foreach ( var n in list )
{
Debug.Log( n.name );
}
}
}
您可以通过编写如上所述的代码来获取Unity项目中包含的所有预制件(包括子对象)。
我尝试在Unity 2018.3中 排除它,因为我有一个名为“DataPrivacyButton”的预制件,它不包含在Unity项目中
[Unity]如何在真实机器上获取已加载材料的列表
public class Example : MonoBehaviour
{
private void Awake()
{
var list = Resources
.FindObjectsOfTypeAll()
.Where( c => ( c.hideFlags & HideFlags.NotEditable ) == 0 )
.Where( c => ( c.hideFlags & HideFlags.HideAndDontSave ) == 0 )
.ToArray()
;
var sb = new StringBuilder();
foreach( var n in list )
{
sb.AppendLine( n.name );
}
Debug.Log( sb.ToString() );
}
}
您可以使用Resources.FindObjectsOfTypeAll 获取实际机器上已加载材料的列表
我还检查了hideFlags ,以确保列表中不包含Unity内部使用的材料
在Unity编辑器中,列表还包括编辑器加载的材料,因此这仅适用于真实设备。
【Unity】如何获取真实机器上加载的纹理列表
public class Example : MonoBehaviour
{
private void Awake()
{
var list = Resources
.FindObjectsOfTypeAll()
.Where( c => ( c.hideFlags & HideFlags.NotEditable ) == 0 )
.Where( c => ( c.hideFlags & HideFlags.HideAndDontSave ) == 0 )
.ToArray()
;
}
}
通过使用Resources.FindObjectsOfTypeAll,您可以获得实际计算机上加载的纹理列表。
我还检查了hideFlags ,以确保Unity内部使用的纹理不包含在列表中
Unity Editor还包含编辑器在列表中加载的纹理,因此这仅适用于真实设备。
17、 [Unity]“CustomSampler”,可以测量任意代码和GC Alloc的执行时间,并在Profiler上显示
using UnityEngine;
using UnityEngine.Profiling;
public class Example : MonoBehaviour
{
private void Start()
{
var sampler = CustomSampler.Create( "Pokemon" );
sampler.Begin();
for ( int i = 0; i < 10000; i++ )
{
Debug.Log( "啊啊啊啊啊啊啊" );
}
sampler.End();
}
}
您可以测量任何代码或GC Alloc的执行时间并在Profiler中显示它
与Profiler.BeginSample 类似,但开销比Profiler.BeginSample少
此外,条件属性已应用,并且未包含在发布版本中
18、[Unity]“Profiler.GetRuntimeMemorySizeLong”,它可以获取指定Unity对象和资产的内存使用情况
例如,在Android上构建一个如上所示绘制3个纹理的场景
using System.Linq;
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.Profiling;
public class Example : MonoBehaviour
{
public TMP_Text m_text;
private void Start()
{
var list = Resources
.FindObjectsOfTypeAll()
.Where( c => ( c.hideFlags & HideFlags.NotEditable ) == 0 )
.Where( c => ( c.hideFlags & HideFlags.HideAndDontSave ) == 0 )
.ToArray()
;
var sb = new StringBuilder();
foreach ( var n in list )
{
var memory = Profiler.GetRuntimeMemorySizeLong( n );
var mb = ( memory >> 10 ) / 1024f;
sb.AppendLine( $"{n.name}: {mb.ToString( "0.00" )} MB" );
}
var text = sb.ToString();
m_text.text = text;
}
}
如果你获得当前由Resources.FindObjectsOfTypeAll加载的所有纹理, 使用
Profiler.GetRuntimeMemorySizeLong 获取每个纹理的
内存使用情况并在屏幕上绘制它
如您所见,每个纹理使用0.37 MB的内存
(Emoji One和LiberationSans SDF Atlas是TextMesh Pro使用的图像)
如果在Unity Editor Inspector中查看纹理体积,可以看到
它们大致一致(0.382 MB)
Profiler还显示纹理体积大致相同
通过这种方式,您可以使用Profiler.GetRuntimeMemorySizeLong
来获取指定Unity对象或资产的内存使用情况。
19、 [Unity]脚本获取托管内存的使用状态(已用过的Mono内存)
using UnityEngine.Profiling;
public sealed class MonoMemoryChecker
{
public float Used { get; private set; }
public float Total { get; private set; }
public string UsedText { get; private set; }
public string TotalText { get; private set; }
public void Update()
{
Used = ( Profiler.GetMonoUsedSizeLong() >> 10 ) / 1024f;
// 较大的堆需要更多的GC时间,但运行频率较低
Total = ( Profiler.GetMonoHeapSizeLong() >> 10 ) / 1024f;
UsedText = Used.ToString( "0.0" ) + " MB";
TotalText = Total.ToString( "0.0" ) + " MB";
}
}
using System.Text;
using TMPro;
using UnityEngine;
public class Example : MonoBehaviour
{
public TMP_Text m_text;
private readonly MonoMemoryChecker m_monoMemoryChecker =
new MonoMemoryChecker();
private void Update()
{
m_monoMemoryChecker.Update();
var sb = new StringBuilder();
sb.AppendLine( "Mono" );
sb.AppendLine();
sb.AppendLine( $" Used: {m_monoMemoryChecker.UsedText}" );
sb.AppendLine( $" Total: {m_monoMemoryChecker.TotalText}" );
var text = sb.ToString();
m_text.text = text;
}
}
https://docs.unity3d.com/ja/current/ScriptReference/Profiling.Profiler.GetMonoUsedSizeLong.html
https://docs.unity3d.com/ja/current/ScriptReference/Profiling.Profiler.GetMonoHeapSizeLong.html
[Unity]用于获取Unity分配的内存使用状态(Unity使用的内存)的脚本
using UnityEngine.Profiling;
public sealed class UnityMemoryChecker
{
public float Used { get; private set; }
public float Unused { get; private set; }
public float Total { get; private set; }
public string UsedText { get; private set; }
public string UnusedText { get; private set; }
public string TotalText { get; private set; }
public void Update()
{
// Unity分配的内存
Used = ( Profiler.GetTotalAllocatedMemoryLong() >> 10 ) / 1024f;
// 保留但未分配内存
Unused = ( Profiler.GetTotalUnusedReservedMemoryLong() >> 10 ) / 1024f;
// Unity为当前和未来分配保留的总内存
Total = ( Profiler.GetTotalReservedMemoryLong() >> 10 ) / 1024f;
UsedText = Used.ToString( "0.0" ) + " MB";
UnusedText = Unused.ToString( "0.0" ) + " MB";
TotalText = Total.ToString( "0.0" ) + " MB";
}
}
public class Example : MonoBehaviour
{
public TMP_Text m_text;
private readonly UnityMemoryChecker m_unityMemoryChecker =
new UnityMemoryChecker();
private void Update()
{
m_unityMemoryChecker.Update();
var sb = new StringBuilder();
sb.AppendLine( "Unity" );
sb.AppendLine();
sb.AppendLine( $" Used: {m_unityMemoryChecker.UsedText}" );
sb.AppendLine( $" Unused: {m_unityMemoryChecker.UnusedText}" );
sb.AppendLine( $" Total: {m_unityMemoryChecker.TotalText}" );
var text = sb.ToString();
m_text.text = text;
}
}
( 两个图片之间存在细微差别,可能是由于Profiler数据使用的内存和音频驱动程序使用的内存等的影响)
https://docs.unity3d.com/ja/current/ScriptReference/Profiling.Profiler.GetTotalAllocatedMemoryLong.html
https://docs.unity3d.com/ja/current/ScriptReference/Profiling.Profiler.GetTotalUnusedReservedMemoryLong.html
https://docs.unity3d.com/ja/current/ScriptReference/Profiling.Profiler.GetTotalReservedMemoryLong.html
20、 [Unity]“UnityEngine.Diagnostics.Utils.ForceCrash”可以故意杀死应用
using UnityEngine;
using UnityEngine.Diagnostics;
public class Example : MonoBehaviour
{
private void Update()
{
if ( Input.GetKeyDown( KeyCode.Space ) )
{
Utils.ForceCrash( ForcedCrashCategory.AccessViolation );
}
}
}
您可以使用ForceEngine.Diagnostics.Utils.ForceCrash故意杀死。
强制终止的类型
项目 |
内容 |
AccessViolation |
内存访问无效导致崩溃 |
致命错误FatalError |
由于本机致命错误导致崩溃 |
Abort |
因中止功能而崩溃 |
PureVirtualFunction |
由于纯虚函数异常导致崩溃 |
我试图找出我手边的iOS / Android设备会有什么样的结果
项目 |
iOS版 |
Android的 |
AccessViolation |
它被打死 |
冻结的 |
致命错误FatalError |
输出错误日志 |
输出错误日志 |
Abort |
它被打死 |
它被打死 |
PureVirtualFunction |
它被打死 |
它被打死 |
除了FatalError,我们可以获得iOS的CrashReport
21、 [Unity]自制类,用于测量GC发生的次数
public sealed class GCWatcher
{
//=变量
private int m_startCount;
//=属性
public int Count { get; private set; }
///开始测量
public void Start()
{
m_startCount = GC.CollectionCount( 0 );
Count = 0;
}
//结束测量
public void Stop()
{
Count = GC.CollectionCount( 0 ) - m_startCount;
}
}
using UnityEngine;
public class Example : MonoBehaviour
{
private void Awake()
{
var watcher = new GCWatcher();
watcher.Start();
for ( int i = 0; i < 10000; i++ )
{
Debug.Log( "【您要测量的过程】" );
}
watcher.Stop();
Debug.Log( watcher.Count );
}
}
您可以测量GC发生的次数
可以像System.Diagnostics.Stopwatch一样使用
22、 C# 4.6 和 之前的string.format 的GC Alloc 一样就是这个结论。
m_sampler1.Begin();
var str1 = $"{count}{max}";
m_sampler1.End();
m_sampler2.Begin();
var str2 = $"{count.ToString()}{max.ToString()}";
m_sampler2.End();
m_sampler3.Begin();
var str3 = string.Format( "{0}{1}", count, max );
m_sampler3.End();
m_sampler4.Begin();
var str4 = string.Format( "{0}{1}", count.ToString(), max.ToString() );
m_sampler4.End();
顺便说一下, 我同事测试lua的字符串拼接三种方式的内存消耗是一样的。 string.format , .. , string.concat .
23、 [Unity]封装一个类, 可以通过事件检测GC是否发生
public static class GCEvent
{
private static int m_count;
public static int Count => m_count;
public static event Action mOnCollect;
//初始化时调用
public static void Initialize()
{
m_count = GC.CollectionCount( 0 );
}
public static void Update()
{
var oldCount = m_count;
m_count = GC.CollectionCount( 0 );
if ( m_count == oldCount ) return;
mOnCollect?.Invoke();
}
}
using UnityEngine;
public class Example : MonoBehaviour
{
private void Awake()
{
GCEvent.Initialize();
GCEvent.mOnCollect += OnCollect;
}
private void OnDestroy()
{
GCEvent.mOnCollect -= OnCollect;
}
private void OnCollect()
{
Debug.Log( "皮卡丘" );
}
private void Update()
{
GCEvent.Update();
}
}
24、 [Unity]一种扩展方法,如果Animator Controller的任何状态的Motion为null,则返回true。
using System.Linq;
using UnityEditor.Animations;
public static class AnimatorControllerExt
{
public static bool HasNullMotion( this AnimatorController self )
{
foreach ( var n in self.layers )
{
if ( n.stateMachine.states.Any( c => c.state.motion == null ) )
{
return true;
}
}
return false;
}
}
private static void Hoge()
{
var path = AssetDatabase.GetAssetPath( Selection.activeObject );
var controller = AssetDatabase.LoadAssetAtPath( path );
Debug.Log( controller.HasNullMotion() );
}
或者编写如下测试检查代码 作为工具使用:
using NUnit.Framework;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEditor.Animations;
public partial class UniCommonTestRunner
{
///
/// Animator Controller 测试状态是否为空
///
[Test]
public void CheckAnimatorControllerState()
{
var list = AssetDatabase
.FindAssets( "t:AnimatorController" )
.Select( AssetDatabase.GUIDToAssetPath )
.Select( c => AssetDatabase.LoadAssetAtPath( c ) )
.Where( c => c != null )
.Where( c => HasNullMotion( c ) )
.Select( c => AssetDatabase.GetAssetPath( c ) ) ;
if ( !list.Any() ) return;
var sb = new StringBuilder();
foreach ( var n in list )
{
sb.AppendLine( n );
}
Assert.Fail( sb.ToString() );
}
private bool HasNullMotion( AnimatorController controller )
{
foreach ( var layer in controller.layers )
{
if ( layer.stateMachine.states.Any( c => c.state.motion == null ) )
{
return true;
}
}
return false;
}
}
[Unity]代码,可以测试iOS插件的目标平台是否合适
using NUnit.Framework;
using System.Linq;
using System.Text;
using UnityEditor;
public partial class UniCommonTestRunner
{
[Test]
public void CheckiOSPlugin()
{
var list = AssetDatabase
.GetAllAssetPaths()
.Where( c => c.Contains( "Plugins" ) )
.Where( c => c.Contains( "iOS" ) )
.Select( c => AssetImporter.GetAtPath( c ) )
.OfType()
.Where( c => c != null )
.Where( c => c.GetCompatibleWithPlatform( BuildTarget.Android ) )
.Select( c => AssetDatabase.GetAssetPath( c ) )
;
if ( !list.Any() ) return;
var sb = new StringBuilder();
foreach ( var n in list )
{
sb.AppendLine( n );
}
Assert.Fail( sb.ToString() );
}
}
您可以测试Android是否设置为“插件”文件夹中“iOS”文件夹中包含的插件的目标平台
同理, 可以检测安卓插件。
[Test]
public void CheckAndroidPlugin()
{
var list = AssetDatabase
.GetAllAssetPaths()
.Where( c => c.Contains( "Plugins" ) )
.Where( c => c.Contains( "Android" ) )
.Select( c => AssetImporter.GetAtPath( c ) )
.OfType()
.Where( c => c != null )
.Where( c => c.GetCompatibleWithPlatform( BuildTarget.iOS ) )
.Select( c => AssetDatabase.GetAssetPath( c ) )
;
https://pimdewitte.me/2016/11/03/optimizing-ios-builds-in-unity-a-tutorial-for-getting-under-the-100mb-over-the-air-download-limit-on-the-app-store/
https://answers.unity.com/questions/1187539/why-does-unity-54-include-the-contents-of-pluginsa.html
[Unity] 可以测试2D场景中是否禁用全局照明的代码
因为 2d 游戏根本不需要。
public partial class UniCommonTestRunner
{
[Test]
public void CheckGlobalIllumination()
{
var sceneList = AssetDatabase
.FindAssets( "t:scene" )
.Select( AssetDatabase.GUIDToAssetPath )
.Where( c => c.Contains( "2D" ) )
.OrderBy( c => c ) ;
var result = new List();
foreach ( var n in sceneList )
{
var scene = EditorSceneManager.OpenScene( n );
var isValid = !Lightmapping.realtimeGI && !Lightmapping.bakedGI;
if ( isValid ) continue;
result.Add( n );
}
if ( result.Count <= 0 ) return;
var sb = new StringBuilder();
foreach ( var n in result )
{
sb.AppendLine( n );
}
Assert.Fail( sb.ToString() );
}
}
http://baba-s.hatenablog.com/entry/2019/03/06/141858
http://baba-s.hatenablog.com/entry/2019/03/06/143028
http://baba-s.hatenablog.com/entry/2019/03/06/143224
25、 [Unity]可以测试加速度传感器是否被禁用的代码
public partial class UniCommonTestRunner
{
///
/// 测试加速度计是否被禁用
///
[Test]
public void CheckAccelerometerFrequency()
{
Assert.IsTrue( PlayerSettings.accelerometerFrequency == 0 );
}
}
您可以测试在不使用加速度计的项目中是否禁用了加速度计
[Unity]发布了“iPhone X Safe Area Drawer”,它可以在GitHub上的Unity编辑器的Game视图中显示iPhone X安全区域。
https://github.com/ianwaldrop/iPhoneX-overlay