交互

交互方式

上一次我们完成了道具类的编写,但是消耗与获得道具的交互脚本还仅限于碰撞产生光照,因此我们这次要完善一下交互代码。
鼠标移动用来控制视野方向,所以我们用鼠标左键点击来模拟交互,在鼠标点击后使用射线检测与前方物体交互。
而物体对于交互的响应虽然有各种形式,但是其可以具体分成几个大类——生成物体,销毁物体,获得道具,道具交换,使用道具。
很明显前两种之一可以和后三种之一共存,于是我们只需要留好扩展代码块,按照几个大类对其处理即可。

物体响应代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BeContacted : MonoBehaviour
{
    [Range(0,3)]
    public int objectType;     //0为给予道具,1为交换道具,2为消耗道具,3为机关类
    public int needItem;
    public int[] giveItem;
    public GameObject[] showGameObject;
    public GameObject[] clearGameObject;
    public GameObject messageShower;
    public string successMessage;
    public string falseMessage;

    private Item item;

    private void Start()
    {
        item = GameObject.Find("ItemManager").GetComponent<Item>();
    }

    public void Contact()
    {
        switch (objectType)
        {
            case 0:
                foreach(int i in giveItem)
                {
                    item.AddItem(i);
                }
                ObjectChange();
                messageShower.SendMessage("ShowMsg", successMessage);
                tag = "Touched";
                break;
            case 1:
                if (item.GetItem() != needItem)
                {
                    messageShower.SendMessage("ShowMsg", falseMessage);
                    break;
                }
                item.UseItem();
                ObjectChange();
                foreach (int i in giveItem)
                {
                    break;
                }
                messageShower.SendMessage("ShowMsg", successMessage);
                tag = "Touched";
                break;
            case 2:
                if (item.GetItem() != needItem)
                {
                    messageShower.SendMessage("ShowMsg", falseMessage);
                    break;
                }
                item.UseItem();
                ObjectChange();
                tag = "Touched";
                break;
            case 3:
                ObjectChange();
                messageShower.SendMessage("ShowMsg", successMessage);
                tag = "Touched";
                break;
            default:
                break;
        }
    }

    private void ObjectChange()
    {
        foreach (GameObject obj in showGameObject)
            obj.SetActive(true);
        foreach (GameObject obj in clearGameObject)
            Destroy(obj);
    }
}

无论物体是否生成或销毁物体,我们都调用ObjectChange来对数组中的待生成/销毁物体做遍历,如果无此需求为空即可。
而关于道具的变动则分为四类,得到,交换,使用,不变,对于这四类分别编写对应代码,因为我们之前在Item中已经充分做好了Add和Use的代码编写,这里只需要调用函数即可。

交互检测代码

我们还需要在操作物体移动的脚本的Update函数中加入如下几行:

if (Input.GetMouseButtonDown(0))
        {
            if (Physics.Raycast(sight.transform.position, sight.transform.forward, out contact, 5f))
            {
                if (contact.transform.CompareTag("Untouched"))
                    contact.transform.gameObject.SendMessage("Contact");
            }
        }

其中,contact的类型为RaycastHit,需要我们提前声明在代码顶部,在检测到点击物体为Untouched标签后,便调用其Contact函数,同时Contact函数会改变标签为Touched,来防止一个物体反复交互。

UI

准心

因为我们的游戏多了鼠标点击的功能,让玩家知道自己的点击会在哪里生效十分重要,我们要做的也十分简单,在UI界面正中心添加一个准心。
在UIInGame画布中添加Image,按图中设置调整参数,之后放上自己画好的准星图片,我们的准心就做好了。
在这里插入图片描述

交互消息

相信刚才有读者注意到,在交互代码中有几个地方调用了叫做“ShowMsg”的函数,这个函数是做什么用的呢?
因为玩家不一定总能做出正确的操作,所以我们需要在玩家进行错误操作时进行提醒,或者在进行正确操作时告知玩家操作结果,因此需要在屏幕上打印相应的信息。
而打印方式也十分简单,提前做好消息预制体,之后在需要打印消息时生成相应的实例即可。
以下为两个脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Message : MonoBehaviour
{
    public GameObject textObj;
    public float spanTime;
    public Transform startPos;

    private Text text;
    private Queue<string> msgs = new Queue<string>();
    private float lastShow = 0;

    private void Start()
    {
        text = textObj.GetComponent<Text>();
    }

    private void Update()
    {
        if (msgs.Count > 0)
        {
            if (Time.time - lastShow >= spanTime)
            {
                text.text = msgs.Dequeue();
                Instantiate(textObj,startPos).transform.SetParent(transform);
                lastShow = Time.time;
            }
        }
    }

    public void ShowMsg(string s)
    {
        msgs.Enqueue(s);
    }
}

这是挂载在场景中MessageManager上的一个脚本,通过队列的方式来解决多条消息并发问题,并加入最低响应间隔,防止玩家快速按下交互导致消息连续发出。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MsgTextAnimator : MonoBehaviour
{
    public float moveSpeed;
    public float fadeSpeed;

    private Text text;

    private void Start()
    {
        text = GetComponent<Text>();
    }

    void Update()
    {
        transform.Translate(new Vector3(0, moveSpeed * Time.deltaTime, 0));
        text.color -= new Color(0, 0, 0, fadeSpeed * Time.deltaTime);
        if (text.color.a <= 0)
            Destroy(gameObject);
    }
}

这是挂载在消息预制体上的脚本,文字生成后向上移动变淡至消失,透明度为0时销毁减少无用计算消耗。

Inspector参数

我们将刚刚编写的交互脚本挂载在初始房间的cube上,并改变参数如下:
在这里插入图片描述
让我们来看看实现的效果:
在这里插入图片描述
消息按照预期出现并消失,方块上的光照也顺利出现,再次按下左键也不会再有后续响应。

道具测试

但我们的脚本编写还涉及道具消耗这部分,因此我们稍微修改cube上的数值进行测试。
在这里插入图片描述
在道具栏为钥匙和空瓶的时候按下点击都没有反应,在道具栏为水瓶时点击,水瓶消耗,也顺利发生响应,道具和响应代码宣告成功,接下来就是关卡的正式设计了。

更多推荐