库:FlameskyDexive/FastBugly: 快速接入新版Bugly到unity,支持unity2021 (github.com)
启动时,初始化Bugly就可以了
public static void Boot() { //BUGLY初始化 #if UNITY_IPHONE || UNITY_IOS BuglyAgent.InitWithAppId("xxxxxxxx"); #elif UNITY_ANDROID BuglyAgent.InitWithAppId("xxxxxxxx"); #endif if (FrameConfig.Debug) { BuglyAgent.ConfigDebugMode(true); } BuglyAgent.EnableExceptionHandler(); }
带CanvasUI是不在剪裁的目标之内的,所以需要一个中介自身是剪裁目标的,然后获取到这些带Canvas的UI通知它们也做相应处理。
Proxy的脚本为:
using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; [DisallowMultipleComponent] public class RectMask2DClipProxy : MaskableGraphic { private List<MaskableGraphic> _maskableList; protected RectMask2DClipProxy() { useLegacyMeshGeneration = false; } protected override void OnPopulateMesh(VertexHelper toFill) { toFill.Clear(); } protected override void Awake() { base.Awake(); _maskableList = new List<MaskableGraphic>(); } public override void Cull(Rect clipRect, bool validRect) { base.Cull(clipRect, validRect); GetComponentsInChildren(false, _maskableList); if (null != _maskableList) { for (int i = 0; i < _maskableList.Count; i++) { var maskable = _maskableList[i]; if (maskable != null && maskable != this) { maskable.Cull(clipRect, validRect); } } } } public override void SetClipRect(Rect clipRect, bool validRect) { base.SetClipRect(clipRect, validRect); GetComponentsInChildren(false, _maskableList); if (null != _maskableList) { for (int i = 0; i < _maskableList.Count; i++) { var maskable = _maskableList[i]; if (maskable != null && maskable != this) { maskable.SetClipRect(clipRect, validRect); } } } } }
如果元素不是动态变化的,就缓存起来。
inline float SoftUnityGet2DClipping (in float2 position, in float4 clipRect) { float2 xy = (position.xy-clipRect.xy)/float2(_ClipSoftX,_ClipSoftY)*step(clipRect.xy, position.xy); float2 zw = (clipRect.zw-position.xy)/float2(_ClipSoftX,_ClipSoftY)*step(position.xy,clipRect.zw); float2 factor = clamp(0, zw, xy); return saturate(min(factor.x,factor.y)); } c.a *= SoftUnityGet2DClipping(i.wpos.xy, float4(_MinX, _MinY, _MaxX, _MaxY));
需要将RectMask2D的区域传给3d物品显示的Shader,然后控制3d物体的透明度,不在范围内的设置为0
首先修改使用到的Shader,添加(使用到的参数声明忽略):
//Properties _MinX ("Min X", Float) = -10 _MaxX ("Max X", Float) = 10 _MinY ("Min Y", Float) = -10 _MaxY ("Max Y", Float) = 10 //顶点函数 o.wpos = mul(unity_ObjectToWorld, v.vertex).xyz; //片元函数 c.a *= (i.wpos.x >= _MinX ); c.a *= (i.wpos.x <= _MaxX); c.a *= (i.wpos.y >= _MinY); c.a *= (i.wpos.y <= _MaxY); c.rgb *= c.a;
获取RectMask2D的区域,传递需要裁剪的3D物体
Vector3[] corners = new Vector3[4]; RectTransform rectTransform = GetComponent<RectTransform>("UIGirdlView/Viewport"); rectTransform.GetWorldCorners(corners); m_GridCorners[0] = corners[0].x; m_GridCorners[1] = corners[0].y; m_GridCorners[2] = corners[2].x; m_GridCorners[3] = corners[2].y; var items = transform.GetComponentsInChildren<Renderer>(); foreach (var item in items) { var m = item.material; m.SetFloat("_MinX", m_GridCorners[0]); m.SetFloat("_MinY", m_GridCorners[1]); m.SetFloat("_MaxX", m_GridCorners[2]); m.SetFloat("_MaxY", m_GridCorners[3]); }
对于在Shader使用Toggle标志的参数
[Toggle(_KEYWORD0_ON)] _Keyword0("Keyword 0", Float) = 0 #ifdef _KEYWORD0_ON #else #endif
可以通过以下C#控制开关
m_Image.material.EnableKeyword("_KEYWORD0_ON"); m_Image.material.DisableKeyword("_KEYWORD0_ON");
可以直接用对ui的输入操作来对3d物体进行交互,例如添加父物体是ui的一个空image,勾选Raycast target,对他做IpointClickHandler等,后影响3D物体即可
public static void RestartOrKillApp() { if (Application.isEditor) return; if (Application.platform == RuntimePlatform.Android) { using (var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { const int kIntent_FLAG_ACTIVITY_CLEAR_TASK = 0x00008000; const int kIntent_FLAG_ACTIVITY_NEW_TASK = 0x10000000; var currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); var pm = currentActivity.Call<AndroidJavaObject>("getPackageManager"); var intent = pm.Call<AndroidJavaObject>("getLaunchIntentForPackage", Application.identifier); intent.Call<AndroidJavaObject>("setFlags", kIntent_FLAG_ACTIVITY_NEW_TASK | kIntent_FLAG_ACTIVITY_CLEAR_TASK); currentActivity.Call("startActivity", intent); currentActivity.Call("finish"); var process = new AndroidJavaClass("android.os.Process"); int pid = process.CallStatic<int>("myPid"); process.CallStatic("killProcess", pid); } } else if (Application.platform == RuntimePlatform.IPhonePlayer) { //测试只有下面俩种类型好用,FatalError几率卡界面 UnityEngine.Diagnostics.Utils.ForceCrash(UnityEngine.Diagnostics.ForcedCrashCategory.FatalError); //UnityEngine.Diagnostics.Utils.ForceCrash(UnityEngine.Diagnostics.ForcedCrashCategory.PureVirtualFunction); } else { Application.Quit(); } }
需要扩展一下UnityWebRequestAsyncOperation
using System.Runtime.CompilerServices; using System.Threading.Tasks; using UnityEngine.Networking; public static class ExtensionMethods { public static TaskAwaiter<object> GetAwaiter(this UnityWebRequestAsyncOperation op) { var tcs = new TaskCompletionSource<object>(); op.completed += (obj) => { tcs.SetResult(null); }; return tcs.Task.GetAwaiter(); } }
可以用uniwebview插件。
可能都有试过,给文本组件的物体添加了ContentSizeFiter组件然后去获取PreferredHeight的情况,发现PreferredHeight并不是设置文本后的,此时可以留意设置文本和获取长度时物体是不是被隐藏了,ContentSizeFiter在被激活的时候才会生效。