系列文章目录
迷失岛游戏框架开发个人每集总结(第一期)
迷失岛游戏框架开发个人每集总结(第二期)
迷失岛游戏框架开发个人每集总结(第三期)
迷失岛游戏框架开发个人每集总结(第四期)
前言
在上一期中,我们实现的是保存物品在场景中的状态,以及互动的状态。在这一期要完成的是可互动的基本逻辑,以及右下角UI的逻辑,点击右下角的物品可以显示一个手,并且显示物品的名字。
1
1.1
在迷失岛这款游戏中,点击某一个物体所发生的事件会与你是否与其产生了互动有所挂钩,比如交给老奶奶一张船票后与你之间的对话会有所不同,没有钥匙与信箱交互,就打不开信箱。
脚本Interactive 作为可互动物品的基类,具体的互动物品会额外创建,然后继承Interactive。
在Interactive基类里,包含对应的、要物品互动的道具的名称、能够判断该物体是否与我们手头的道具进行了交互的值(这里用的是bool值),将交互情况进行保存,这样在重新加载场景后,根据交互情况来加载不同的事件。
public class Interactive : MonoBehaviour
{
public ItemName requireItem;//对应的要互动的道具
public bool isDone;//保存互动的情况是否完成了
//用于检测传递进来的,即你鼠标所选中的物品是否是我需求的物品
public void CheckItem(ItemName itemName)
{
if(itemName==requireItem && !isDone)
{
isDone = true;
//使用这个物品,移除场景中的物品
OnClickedAction();
//订阅了该事件(ItemUsedEvent)的脚本执行它们各自的方法
EventHandler.CallItemUsedEvent(itemName);
}
}
///<summary>
/// 默认是正常的物品的情况执行
/// </summary>
protected virtual void OnClickedAction()
{
//在继承该类的子类中实现这个方法
}
public virtual void EmptyClicked()//在CursorManager中执行
{
Debug.Log("空点");
}
}
OnClickedAction()
这是一个 C# 中的方法定义,用于声明一个名为 OnClickedAction 的方法。该方法被标记为 protected virtual,表示它是一个受保护的虚方法,在继承层次结构中可被子类重写。
该方法没有输入参数,并且没有指定返回值类型,因为它没有返回任何结果。
在该方法的代码块内部,没有指定具体的实现逻辑,这意味着该方法的功能需要在其子类中实现。即当该方法在子类中被调用时,将会执行子类中所重写的方法中的代码。
通常情况下,该方法是在游戏引擎中用于处理用户点击事件的回调函数,用于响应用户的触发操作并实现相应的交互逻辑。例如,可以在该方法中实现按钮被点击后的音效播放、
界面展示或场景跳转等功能,以提高游戏的交互性和用户体验。
protected virtual
protected virtual用于修饰一个名为OnClickedAction()的虚方法。虚方法是一种允许继承的成员,它可以被子类重写以实现不同的行为。使用protected访问修饰符可以使得这个方法只能被当前类和子类访问,而其他类则无法直接访问。
1.2
脚本:CursorManager
public class CursorManager : MonoBehaviour
{
//实现鼠标是否点击到了某个东西 用Physics2D来判断
//实现点击这个物体之后,能够返回这个物体
//获取鼠标的世界坐标
private Vector3 mouseWorldPos => Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
private bool canclick;//判断是否可以点击
//RectTransform 是 Unity 引擎中的一个组件,用于控制游戏对象在 UI 界面中的位置、大小、旋转等属性。该组件会自动添加到拥有 UI 组件的游戏对象上。
public RectTransform hand;//用于显示拿了道具的手
private ItemName currentItem;
private bool holdItem;
private void OnEnable()
{
EventHandler.ItemSelectEvent += OnItemsSelectedEvent;//注册事件
EventHandler.ItemUsedEvent += OnItemUsedEvent;
}
private void OnDisable()
{
EventHandler.ItemSelectEvent -= OnItemsSelectedEvent;
EventHandler.ItemUsedEvent -= OnItemUsedEvent;
}
//用update时刻检测是否有点击到碰撞体
private void Update()
{
canclick = ObjectAtMousePosition();
if (hand.gameObject.activeInHierarchy)//如果“手”这个图片已经在视图中被激活,那么“手”的位置跟随鼠标的位置
hand.position = Input.mousePosition;
if (canclick && Input.GetMouseButtonDown(0))
{
//检测鼠标互动情况
ClickAction(ObjectAtMousePosition().gameObject);
}
}
private void OnItemUsedEvent(ItemName obj)
{
currentItem = ItemName.None;
holdItem = false;
hand.gameObject.SetActive(false);
}
//实现注册的方法
private void OnItemsSelectedEvent(ItemDetails itemDetails, bool isSelected)
{
holdItem = isSelected;//根据isSelectd的值来判断拿起或放下物品
if(isSelected)
{
currentItem = itemDetails.itemName;
}
hand.gameObject.SetActive(holdItem);//根据holdItem这个bool值来判断显不显示“手”的图片
}
private void ClickAction(GameObject clickObject)
{
switch(clickObject.tag)
{
case "Teleport":
var teleport = clickObject.GetComponent<Teleport>();
teleport?.TeleportToScene();
break;
case "Item":
var item = clickObject.GetComponent<Item>();
item?.ItemClicked();
break;
case "Interactive":
var interactive = clickObject.GetComponent<Interactive>();
//需要判断当前鼠标是否选择了一个物品
//在SlotUI里设置我们的点击事件,获得SlotUI里的currentItem,将currentItem传入interactive里面进行判断
//看看是否为所需道具
if (holdItem)//如果鼠标选择了一个物体
{
interactive?.CheckItem(currentItem);//调用interactive的方法判断当前物体是否为正确的物品
}
else
interactive?.EmptyClicked();//否则报空点
break;
}
}
private Collider2D ObjectAtMousePosition()
{
return Physics2D.OverlapPoint(mouseWorldPos);
}
}
在case "Interactive"中,我们还需判断鼠标是否拿着一个物品(视频里说的是物品,更具体一点可以说是游戏中的道具),在我们点击了可以互动的物体后(比如说老奶奶),就会判断我们鼠标是否拿着道具,如果拿着道具,就会判断这个道具是否为可互动物体所要求的道具(requireItem),然后触发下一步的事件( 比如空点或者 OnClickedAction )。
如何实现判断鼠标是否拿着道具呢?在游戏里,我们要在工具栏(SlotUI)里点击我们要选择的道具,我们在SlotUI里实现检测鼠标点击的方法(OnPointerClick)、当我们点击了SlotUI的物品(道具)后,呼叫我们订阅了该事件(ItemSelectedEvent)的方法(CursorManager),传递该物品的名称以及是否被选中了的布尔值(因为单点一次SlotUI的物品为拿着,再点一次为放下),这样,CursorManager里就有了当前鼠标拿着的物品的信息,再将该物品的名称传入Interactive这个脚本,进行下一步的判断。
拿着道具的情况:
1.3
脚本:SlotUI
public class SlotUI : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler//接口
{
public Image itemImage;
public ItemTooltip tooltip;
private ItemDetails currentItem;//储存当前的物品信息
private bool isSelected;
public void SetItem(ItemDetails itemDetails)
{
currentItem = itemDetails;
this.gameObject.SetActive(true);
itemImage.sprite = itemDetails.itemSprite;
itemImage.SetNativeSize();
}
public void SetEmpty()
{
this.gameObject.SetActive(false);
isSelected = false;
}
public void OnPointerClick(PointerEventData eventData)//鼠标点击
{
isSelected = !isSelected;//物品选择的切换
EventHandler.CallItemSelectedEvent(currentItem, isSelected);
}
public void OnPointerEnter(PointerEventData eventData)//鼠标划入
{
if(this.gameObject.activeInHierarchy)//当挂载slotUI的物体显示在视图中时
{
tooltip.gameObject.SetActive(true);
tooltip.UpdateItemName(currentItem.itemName);
}
}
public void OnPointerExit(PointerEventData eventData)//鼠标划出
{
tooltip.gameObject.SetActive(false);
}
}
IPointerClickHandler、IPointerEnterHandler和IPointerExitHandler
是Unity Engine中定义的三个用户输入接口,它们用于处理鼠标或触摸屏等输入事件,实现与用户交互的功能。这三个接口分别是:
IPointerClickHandler(指针点击事件接口):处理鼠标或触摸屏等输入设备的单击事件,该事件在指针按下并快速释放时触发。
IPointerEnterHandler(指针进入事件接口):处理指针进入对象的事件,当用户将鼠标或手指悬停在对象上时触发。
IPointerExitHandler(指针退出事件接口):处理指针离开对象的事件,当用户将鼠标或手指从对象移开时触发。
1.4
脚本:EventHandler
public class EventHandler : MonoBehaviour
{
public static event Action<ItemDetails, int> updateUIEvent;
public static void CallUpdateUIEvent(ItemDetails itemDetails,int index)
{
updateUIEvent?.Invoke(itemDetails, index);
}
//创建两个事件来传递或者执行某些函数方法
public static event Action BeforeSceneUnloadEvent;
public static void CallBeforeSceneUnloadEvent()
{
BeforeSceneUnloadEvent?.Invoke();
}
public static event Action AfterSceneUnloadEvent;
public static void CallAfterSceneUnloadEvent()
{
AfterSceneUnloadEvent?.Invoke();
}
public static event Action<ItemDetails, bool> ItemSelectEvent;
public static void CallItemSelectedEvent(ItemDetails itemDetails,bool isSelected)
{
ItemSelectEvent?.Invoke(itemDetails, isSelected);
}
public static event Action<ItemName> ItemUsedEvent;
public static void CallItemUsedEvent(ItemName itemName)
{
ItemUsedEvent?.Invoke(itemName);
}
public static event Action<int> ChangeItemEvent;
public static void CallChangeItemEvent(int index)
{
ChangeItemEvent?.Invoke(index);
}
public static event Action<string> ShowDialogueEvent;
public static void CallShowDialogeEvent(string diague)
{
ShowDialogueEvent?.Invoke(diague);
}
public static event Action<GameState> GameStateChangeEvent;
public static void CallGameStateChangeEvent(GameState gameState)
{
GameStateChangeEvent?.Invoke(gameState);
}
}
1.5
脚本:ItemTooltip
public class ItemTooltip : MonoBehaviour
{
public Text itemNameText;
public void UpdateItemName(ItemName itemName)
{
itemNameText.text = itemName switch//根据枚举的类型来输出文本框里的文字
{
ItemName.Key =>"信箱钥匙",
ItemName.Ticket =>"一张船票",
_=>""//默认为空
};
}
}
2 最后
看了好几遍,视频里的有些地方比较绕,如果我的总结有哪里写错了,欢迎指正~