【迷失岛游戏框架开发个人每集总结(第五期)】

系列文章目录

迷失岛游戏框架开发个人每集总结(第一期)
迷失岛游戏框架开发个人每集总结(第二期)
迷失岛游戏框架开发个人每集总结(第三期)
迷失岛游戏框架开发个人每集总结(第四期)

前言

在上一期中,我们实现的是保存物品在场景中的状态,以及互动的状态。在这一期要完成的是可互动的基本逻辑,以及右下角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 最后

看了好几遍,视频里的有些地方比较绕,如果我的总结有哪里写错了,欢迎指正~

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值