原视频:https://www.udemy.com/course/unity-2d-game-developer-course-farming-rpg/
bilibili课程地址:https://www.bilibili.com/video/BV1qi4y1k7ix
通用性的
GetComponent<>
可以获取当前指定类型的组件,返回null代表没有MonoBehaviour
基础函数- Awake
- Update
- Start
- OnEnable
- OnDisable
单例类
防止多个玩家创建
using UnityEngine;
public abstract class SingletonMonoBehavior<T> : MonoBehaviour where T : MonoBehaviour
{
public static T Instance { get; private set; }
protected virtual void Awake()
{
if (Instance == null)
{
= this as T;
Instance } else {
Destroy(gameObject);
}
}
}
多个部位动画绑定
使用订阅发布模式,利用delegate给所有的子动画部件发送触发动作,使用静态类处理发布订阅
public delegate void MovementDelegate(...);
public static class EventHandler
{
public static event MovementDelegate MovementEvent;
public static void CallMovementEvent(...)
{
if (MovementEvent != null)
{
MovementEvent(...);
}
}
}
其他带有Animator
的动画组件在OnEnable
中使用EventHandler.MovementEvent += SetParameters;
;在OnDisable
中使用EventHandler.MovementEvent -= SetParameters;
动画测试脚本
手动调用EventHandler
的CallMovementEvent
,把变量设置好拖到玩家上
玩家移动
根据键盘输入、玩家速度和Time.deltaTime
计算位移向量,调用Rigidbody2D
的MovePosition
来实现,需要加原来的位置
层
层数高的会在上层,而且永远在层数低的上面
单个物体如果有多个子部件,比如SpriteRenderer
,需要使用排序组来保证所有的子部件在一个层上
Tilemap
可以绘制贴图也可以存储碰撞关系,还可以存储一些根网格相关的关系,比如网格是否可以丢弃物品等
碰撞
有一方设置isTrigger
后,函数private void OnTriggerEnter2D(Collider2D other)
就会触发
相机
cinemachine相机可以有阻尼的跟随玩家
设置Confiner
可以防止相机超过地图导致看到地图外的东西,需要添加碰撞体,设置Layer
为Ignore Raycast
预制件
可以把模板化的组件拖到资源里面生成预制件(Prefabs),预制件可以减少每次重新编辑的操作,类似于godot里面的scene
预制件参数:右键预制件创建预制件参数,在预制件的基础上生成新的预制件,只改变参数,节省空间,类似于设计模式里面的原型模式
字符串哈希化
使用静态的类保存int类型的字符串哈希,可以避免多次输入字符串的繁琐,用在Animator
的动画属性里面
= Animator.StringToHash("xInput"); xInput
C#属性
[System.Serializable]
public class ItemDetails
{
public int itemCode;
//...
}
可以用来定义类、成员变量、方法等属性,已经用到的有:
TODO: 持续加入内容
[System.Serializable] // 可被从文件序列化反序列化
[Range(10000, 100100)] // 整型数据范围
[SerializeField] // unity脚本页面可以编辑该字段
[HideInInspector] // 使变量不显示在检查器中,而是序列化
可编程对象
添加到右键菜单创建可编程对象,提供图形化控件编辑数据
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName ="so_ItemList", menuName ="Scriptable Object/Item/Item List")]
public class SO_ItemList : ScriptableObject
{
[SerializeField]
public List<ItemDetails> itemDetails;
}
fileName
指定文件名,menuName
指定右键菜单或者主菜单位置
自定义脚本属性
除了脚本变量属性外,可以定义额外的脚本属性来更方便的设置数据调试接口
在脚本字段上使用自定义属性
public class Item : MonoBehaviour
{
[ItemCodeDescription] // 自定义属性
[SerializeField]
private int itemCode;
}
// 属性来自
public class ItemCodeDescriptionAttribute : PropertyAttribute
{
}
// 属性GUI渲染方法
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(ItemCodeDescriptionAttribute))]
public class ItemCodeDescriptionDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
.BeginProperty(position, label, property);
EditorGUIif (property.propertyType != SerializedPropertyType.Integer) return;
.BeginChangeCheck();
EditorGUI// draw item code
var newValue = EditorGUI.IntField(
new Rect(position.x, position.y, position.width, position.height / 2),
, property.intValue);
label
// draw item description
.LabelField(
EditorGUInew Rect(position.x, position.y + position.height / 2, position.width, position.height / 2),
"Item Description", GetItemDescription(property.intValue));
// if item code value changed, then set value to new value
if (EditorGUI.EndChangeCheck())
{
.intValue = newValue;
property}
}
// 查表渲染id对应的说明
private static string GetItemDescription(int itemCode)
{
var soItemList = AssetDatabase.LoadAssetAtPath("Assets/ScriptableObjectAssets/Item/so_ItemList.asset", typeof(SO_ItemList))
as SO_ItemList;
if (!soItemList) return "";
var itemDetailsList = soItemList.itemDetails;
var itemDetails = itemDetailsList.Find(x => x.itemCode == itemCode);
return itemDetails != null ? itemDetails.itemDescription : "";
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property) * 2;
}
}
物品管理拾取
使用静态类管理物品,物品类可以设置堆叠数量,物品和玩家发生碰撞触发玩家的pickup脚本,添加到物品管理类里面
物品栏UI
物品根据人物在世界坐标转换为viewport坐标的位置,然后在人物要被挡住时把物品栏移动到顶部
物品栏刷新
通过发布订阅从物品管理类中获取到物品变更函数,然后从里面刷新数据更新到UI上
弹窗描述
零散
- 在鼠标事件中,可以通过Raycast获取鼠标下面的物体
.pointerCurrentRaycast.gameObject eventData
- 根据预制件创建对象的函数
var obj = Instantiate(prefab, parentTransform);
未完待续💤