2024.7.11
实现随机地图
新建的场景的摄像机都要删除,都要勾选Addressable
准备:创建6个关卡图标,Map的RoomDataSO,创建新的场景Scene(Map),将Map开头的两个场景移动到这个场景,还要勾选Addressable,修改Group.
找到Wundow 中的Addressable 的Group
2处是右键选的简写的
再新建敌人场景 Minor Enemy 等等
1.添加背景,自行调整大小,修改Scale
2.制作一个临时使用按钮,创建Square,命名为BackToMap,Sprite的图标添加为按键类型的,层级设置为Background。挂载FimishRoom.cs
2.1添加碰撞体,接着添加一个3D 的文字,调整大小,层级等
FinishRoom
public class FinishRoom : MonoBehaviour
{
private void OnMouseDown()
{
// 返回地图
}
}
现在就将关卡的图片换成设置的图片,就是查找然后匹配。
就是先得到MapConfigSO列表中的roomtype房间类型,然后随机生成。这就可以用到字典匹配,Dictionary<RoomType, RoomDataSO>
private List<Room> rooms = new List<Room>(); //
private List<LineRenderer> lines = new List<LineRenderer>();
public List<RoomDataSO> roomDataList = new List<RoomDataSO>();
private Dictionary<RoomType, RoomDataSO> roomDataDict = new Dictionary<RoomType, RoomDataSO>(); //用字典来匹配
private void Awake()
{
// 获取屏幕的高度和宽度
screenHeight = Camera.main.orthographicSize * 2;
screenWidth = screenHeight * Camera.main.aspect;
// 获取一列的宽度
columnWidth = screenWidth / mapConfig.roomBlueprints.Count;
foreach (var roomData in roomDataList)
{
roomDataDict.Add(roomData.roomType, roomData);
}
}
private RoomDataSO GetRoomData(RoomType roomType)
{
return roomDataDict[roomType];
}
private RoomType GetRandomRoomType(RoomType flags)
{
// 首先获取出所有房间的名称字符串数组
string[] options = flags.ToString().Split(',');
// 然后从数组中随机取出一个
string randomOption = options[UnityEngine.Random.Range(0, options.Length)];
// 然后根据字符串获取到对应的 RoomType
return (RoomType)Enum.Parse(typeof(RoomType), randomOption);
}
效果:
。。。。还的注意一下,场景的顺序,map在主场景的下面。不然获取不到主场景的屏幕的高度和宽度。
泛型事件框架
目的:点击房间启动房间场景。设置了一个事件系统来在点击房间时进行广播,加载房间的事件,并传递RoomData
Events文件(存放事件的)->MonoBehaviour和ScriptableObject(存放SO文件)
UnityEvent / UnityAction
Delegate/Action/Event/UnityAction/UnityEvent 区别与使用场景 - 青叶煮酒 - 博客园 (cnblogs.com)
BaseEventSO (泛型的基类/父类)
using UnityEngine.Events;
public class BaseEventSO<T> : ScriptableObject
{
[TextArea]//[TextArea] 属性标记。这个属性使得在 Unity 的 Inspector 窗口中,该字符串的输入区域会变成一个多行文本区域,方便输入更长的描述。
public string description;//描述
public UnityAction<T> OnEventRaised;
public string lastSender;//用于存储最后触发事件的发送者的标识。就是知道谁用了
public void RaiseEvent(T value, object sender)
{
OnEventRaised?.Invoke(value);
lastSender = sender.ToString();
}
}
BaseEventListener 添加事件注销事件
public class BaseEventListener<T> : MonoBehaviour
{
public BaseEventSO<T> eventSO;
public UnityEvent<T> response;
private void OnEnable() {
if (eventSO != null)
{
eventSO.OnEventRaised += OnEventRaised;
}
}
private void OnDisable() {
if (eventSO != null)
{
eventSO.OnEventRaised -= OnEventRaised;
}
}
private void OnEventRaised(T value)
{
response.Invoke(value);
}
}
ObjectEventSO 传递 object 类型的事件
using UnityEngine;
[CreateAssetMenu(fileName = "ObjectEventSO", menuName = "Events/ObjectEventSO")]
public class ObjectEventSO : BaseEventSO<object>
{
}
对应的
using UnityEngine;
public class ObjectEventListener : BaseEventListener<object>
{
}
Room
[Header("广播")]
public ObjectEventSO loadRoomEvent;
//加载场景,是在点击(关卡房间)后进行
loadRoomEvent.RaiseEvent(roomData, this);
创建Events的ObjectEventSO,命名LoadRoom Event
点击房间广播加载对应场景,传递RoomData数量
谁来监听?
监听的都放到主场景中
SceneLode Manager
挂载SceneLode Manager和Object Event Listener
Manager文件
SceneLodeManager 负责监听加载房间的事件
/// <summary>
/// 在房间加载事件中监听
/// </summary>
/// <param name="data"></param>
public async void OnLoadRoomEvent(object data)
{
if (data is Room)
{
Room currentRoom = (Room)data;
Debug.Log($"{currentData.roomType}");
}
}
创建一个文件夹Events -->Edtor(最后打包不会打包这个文件,相当于一个工具)
用于在Unity项目中跨组件或场景传递事件。这个自定义编辑器界面会展示当前订阅了该事件的所有监听者的数量,并列出每个监听者的信息:
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(BaseEventSO<>))]
public class BaseEventSOEditor<T> : Editor
{
private BaseEventSO<T> baseEventSO;
private void OnEnable() {
if (baseEventSO == null)
{
baseEventSO = target as BaseEventSO<T>;
}
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUILayout.LabelField($"订阅数量: {GetListeners().Count}");
foreach (var listener in GetListeners())
{
EditorGUILayout.LabelField(listener.ToString());
}
}
private List<MonoBehaviour> GetListeners()
{
List<MonoBehaviour> listeners = new List<MonoBehaviour>();
if (baseEventSO == null || baseEventSO.OnEventRaised == null)
{
return listeners;
}
var subscribers = baseEventSO.OnEventRaised.GetInvocationList();
foreach (var subscriber in subscribers)
{
var obj = subscriber.Target as MonoBehaviour;
if (!listeners.Contains(obj))
{
listeners.Add(obj);
}
}
return listeners;
}
}
看的,学的很懵逼
梳理泛型事件框架
1. 泛型基类 BaseEventSO<T>
- 作用:作为所有事件脚本对象的基类,提供事件触发的基础功能。
- 成员:
string description
:事件的描述。UnityAction<T> OnEventRaised
:当事件被触发时调用的委托。string lastSender
:记录最后触发事件的发送者。RaiseEvent(T value, object sender)
:触发事件的方法,接受一个泛型参数和一个发送者对象。
2. 事件监听器 BaseEventListener<T>
- 作用:作为MonoBehaviour组件,用于游戏对象上订阅和取消订阅
BaseEventSO<T>
事件。 - 成员:
BaseEventSO<T> eventSO
:要监听的事件脚本对象。UnityEvent<T> response
:当事件被触发时响应的Unity事件。OnEnable()
和OnDisable()
:自动订阅和取消订阅事件。OnEventRaised(T value)
:当事件被触发时调用的方法,通过response
转发事件。
3. 特定类型的事件 ObjectEventSO
- 作用:继承自
BaseEventSO<object>
,用于传递object
类型的事件。这使得它可以传递任何类型的数据。 - 实现:简单继承
BaseEventSO<object>
,无需额外实现。
4. 特定类型的事件监听器 ObjectEventListener
- 作用:继承自
BaseEventListener<object>
,用于订阅ObjectEventSO
事件。 - 实现:简单继承
BaseEventListener<object>
,无需额外实现。
5. 房间(Room)
- 作用:在游戏中代表一个房间,当点击或触发某个事件时,广播加载房间的事件。
- 实现:
- 拥有一个
ObjectEventSO
类型的字段(如loadRoomEvent
),用于存储加载房间事件的引用。 - 在适当的时候(如点击房间时),调用
loadRoomEvent.RaiseEvent(roomData, this)
来广播事件,其中roomData
是与房间相关的数据。
- 拥有一个
6. 场景加载管理器(SceneLoaderManager)
- 作用:负责监听加载房间的事件,并根据接收到的数据加载相应的场景。
- 实现:
- 拥有一个
ObjectEventListener
组件,其eventSO
字段指向用于加载房间事件的ObjectEventSO
实例。 - 在
ObjectEventListener
的response
事件中,实现加载场景的逻辑。 - 可能还需要一个
RoomData
类型(或类似)的字段来存储当前房间的数据。
- 拥有一个
7. 自定义编辑器 BaseEventSOEditor
- 作用:为
BaseEventSO<T>
提供一个自定义的编辑器界面,可能包括显示当前监听者的信息。 - 实现:
- 继承自
UnityEditor.Editor
。 - 使用
OnInspectorGUI
方法来绘制自定义的Inspector界面。 - 使用反射或其他方法来获取
OnEventRaised
委托中已注册的监听者信息,并在Inspector中显示。
- 继承自
梳理过程
- 创建一个
BaseEventSO<T>
基类,用于定义泛型事件。 - 创建一个
BaseEventListener<T>
类,用于游戏对象上订阅和取消订阅这些事件。 - 根据需要创建特定类型的事件(如
ObjectEventSO
)和监听器(如ObjectEventListener
)。 - 在游戏中(如
Room
类中),当需要时触发事件。 - 在
SceneLoaderManager
中监听这些事件,并根据接收到的数据执行相应的逻辑(如加载场景)。 - (可选)为
BaseEventSO<T>
创建一个自定义编辑器,以提供更丰富的编辑体验。