1.Preferences > Scene View > Create Object at Origin开启该选项,可以使得创建的物体在(0,0,0)坐标上。
2.OnMouseDown等事件函数需要具备条件:
1)使用函数的类必须继承自MonoBehaviour
2)挂在脚本的物体必须有碰撞体或者GUI元素
3)Layer不是Ignore Raycast
4)被检测物体必须没有其他物体的遮挡
3.使用[Flags]可以使得枚举在编辑器中实现多选,但是由于每个选项是或逻辑,为了使得每种可能都需要空间,因此每个选项应该赋值二的幂次方。
[Flags]
public enum RoomType
{
MinorEnemy = 1,//普通敌人
EliteEnemy = 2,//精英敌人
Shop = 4,//商店
Treasure = 8,//宝箱
ResetRoom = 16,//休息地
Boss = 32,
}
4. [ContextMenu("名字")]可以右键编辑器中的该脚本即可调用相应函数
[ContextMenu("ReGenerateRoom")]
public void ReGenerateRoom()
{
//重新生成地图
}
5.实现材质动态滚动
使用line这个组件(确定起始位置)实现,动态滚动的line是使用材质(Shader Unlit/Transparent)中的Offset线性增加其值实现的效果。
6.场景加载区别
特性 | UnityEngine.Awaitable | System.Task |
设计目标 | 针对Unity项目尽可能高效 | 通用异步编程模型 |
线程池 | 使用内部Awaitable池限制分配 | 使用.NET线程池 |
调度 | 由Unity引擎调度 | 由.NET运行时调度 |
协程支持 | 直接支持协程 | 需要额外适配 |
Profiler支持 | 支持 | 部分支持 |
7.加载与卸载场景的方式
//异步加载场景
private async Awaitable LoadSceneTask()
{
var s = currentScene.LoadSceneAsync(LoadSceneMode.Additive);
await s.Task;
if (s.Status == AsyncOperationStatus.Succeeded)//如果场景加载完成
{
SceneManager.SetActiveScene(s.Result.Scene);//场景设为激活
}
}
private async Awaitable UnLoadSceneTask()
{
await SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene());
}
8. [TextArea]可以使得字符串在编辑器中显示长方形的文本区域,而不是一行字符串,便于查看。
[TextArea] public string description;
9.对象池工具
对象池是为了防止物体频繁创建与销毁带来的性能消耗,而使用的一种方式,其核心思想是预先创建一定数量的对象并存储到池中,需要时从中取出,不需要时返回池中。
public class PoolTool : MonoBehaviour
{
public GameObject objPrefab;
private ObjectPool<GameObject> pool;
private void Start()
{
//初始化对象池
pool = new ObjectPool<GameObject>(
createFunc: () => Instantiate(objPrefab,transform),//创建
actionOnGet: (obj) => obj.SetActive(true),//获取
actionOnRelease: (obj) => obj.SetActive(false),//回收(到池中)
actionOnDestroy: (obj) => Destroy(obj),//删除
collectionCheck: false,
defaultCapacity: 10,//默认数量
maxSize: 20 //最大数量
);
PreFillPool(7);
}
private void PreFillPool(int count)
{
var preFillArray = new GameObject[count];
for (int i = 0; i < count; i++)
{
preFillArray[i] = pool.Get();
}
foreach (var item in preFillArray)
{
pool.Release(item);
}
}
public GameObject GetObjectFromPool()
{
return pool.Get();
}
public void ReturnObjectToPool(GameObject obj)
{
pool.Release(obj);
}
}
注:PreFillPool函数会执行Get(),如果对象池中没有就会自动执行createFunc创建新对象,之后就会释放回对象池中。
10.DoTween
1)使用DOTween 的API实现简单的动画: GameObject.transform.DOScale/DOMove/
DORotateQuaternion(目标位置,动画耗时);
2)DOTween的事件响应API:~.Complete = ()=> { 执行的内容 }
11.对于场景中的物品,如果想实现类似UI的鼠标检测可在Camera上挂载Physics 2D Raycaster组件,然后在脚本中增加IPointerEnterHandler和IPointerExitHandler等接口来实现鼠标事件的执行。
12.人物数值管理
1)可以创建一个中间件,一方面管理数值,另一方面呼叫事件。
public class IntVariable : ScriptableObject
{
public int maxValue;
public int currentValue;
public IntEventSO ValueChangedEvent;
public void SetValue(int value)
{
currentValue = value;
ValueChangedEvent?.RaisEvent(value,this);
}
}
2)对于人物来讲,需要通过IntVariable来管理数值。
public class CharacterBase : MonoBehaviour
{
public int maxHp;
public IntVariable hp;
public int CurrentHp
{
get => hp.currentValue;
set => hp.SetValue(value);
}
public int MaxHp
{
get => hp.maxValue;
}
protected void Start()
{
hp.maxValue = maxHp;
CurrentHp = MaxHp;
}
}
注: get/set是在赋值(等号右边)/获值时触发。
13.如果输出时需要文本间夹数值,则可以使用该API:Debug.Log($"文本{value}文本");
14.动画相关
1)与Any State相连的逻辑线Settings中关闭Can Transition To Self;如果想执行完之后 退出,执行初始状态则连接Exit。
2)播放某个动画片段使用:_animator.Play("动画片段名");
3)在协程中实现动画提前执行某动作:
IEnumerator ProcessDelayAction(string actionName)
{
//启动动画片段
yield return new WaitUntil(() =>
animator.GetCurrentAnimatorStateInfo(0).normalizedTime % 1.0f > 0.6f && !animator.IsInTransition(0) &&
animator.GetCurrentAnimatorStateInfo(0).IsName(actionName));
//执行动作
}
注:获取动画控制器第0层(主层Layer),若动画进度超过60%,并且不处于动画过渡,检查当前播放动画片段与传入名字匹配 。
15.可以使用贝塞尔曲线使得折线变得平滑
16.项目导出设置
1)Addressables Groups需要把Play Mode Script 改为 Use Existing Build。如果要在编辑 器中运行需要改回去。
2)在Assets > AddressableAssetsData > Addressable Asset Setting > Build >Build > Build Addressables on Player Build改为Addressables content on Player Build
3)创建新场景不添加到Addressable中,再创建脚本启动主场景(因为Unity打包需要正常场景,所以需要这么操作)