您当前的位置: 首页 >  unity
  • 4浏览

    0关注

    193博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity实现UI在屏幕边缘跟随并指向视野外敌人

我寄人间雪满头丶 发布时间:2021-11-29 18:09:16 ,浏览量:4

最终效果

请添加图片描述

实现

心急的小伙伴可以直接跳到文章末尾查看最终代码,如果有问题再来看下思路。

首先我们需要确定实现思路。我想到的方案是将玩家和敌人的世界坐标转换为UI坐标,然后求玩家和敌人坐标的线段与Canvas边界的交点即为箭头坐标。 下面是求出交点的代码。

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

public class FindTest : MonoBehaviour
{
    public Canvas canvas;
    public Camera cam;
    public Image find; //箭头UI
    public GameObject player; //玩家
    public GameObject target; //跟踪目标
    List points = new List(); //canvas边界点

    void Start()
    {
        //存储canvas边界点
        points.Add(new Vector3(-canvas.GetComponent().rect.width / 2f, -canvas.GetComponent().rect.height / 2f, 0));
        points.Add(new Vector3(canvas.GetComponent().rect.width / 2f, -canvas.GetComponent().rect.height / 2f, 0));
        points.Add(new Vector3(canvas.GetComponent().rect.width / 2f, canvas.GetComponent().rect.height / 2f, 0));
        points.Add(new Vector3(-canvas.GetComponent().rect.width / 2f, canvas.GetComponent().rect.height / 2f, 0));
    }

    void Update()
    {
        Vector3 pos = Vector3.zero;
        Vector3 pos1 = Camera.main.WorldToScreenPoint(target.transform.position); //目标屏幕坐标
        Vector3 pos2 = Camera.main.WorldToScreenPoint(player.transform.position); //玩家屏幕坐标
        Vector2 worldPoint1;
        Vector2 worldPoint2;

        //求出目标与玩家的UI坐标
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, pos1, cam, out worldPoint1);
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, pos2, cam, out worldPoint2);

        //玩家与目标UI坐标连线与Canvas边界连写交点即为箭头位置
        for (int i = 0; i = 0)
        {
            return false;
        }
        //计算交点坐标  
        float t = Cross(a - c, d - c) / Cross(d - c, b - a);
        float dx = t * (b.x - a.x);
        float dy = t * (b.y - a.y);

        IntrPos = new Vector3() { x = a.x + dx, y = a.y + dy };
        return true;
    }
}

效果 请添加图片描述 核心的部分写完了,但是效果差强人意。还缺少箭头朝向敌人的功能,箭头也没有完整的显示出来,而且如果敌人进入视野内箭头应该消失。

1.箭头朝向敌人 首先是箭头朝向敌人,我们可以加段转向的代码。 因为箭头默认朝上,所以第三个参数传Vector3.up。

	//箭头朝向目标
    UILookAt(find.transform, worldPoint1 - worldPoint2, Vector3.up);

    //参数分别为:1.UI的Transform 2.朝向向量 3.起始向量
    public void UILookAt(Transform transform, Vector3 dir, Vector3 lookAxis)
    {
        Quaternion q = Quaternion.identity;
        q.SetFromToRotation(lookAxis, dir);
        transform.rotation = q;
    }

2.箭头完整显示 可以在代码中加一个箭头位置偏移。还有种更简单的方法就是修改UI的轴心点。如下图。 在这里插入图片描述 3.敌人进入视野内箭头消失 最开始打算使用OnBecameVisibleOnBecameInVisible来判断目标是否在视野内,但是这种方法不够灵活。于是考虑用另一种方法,就是通过判断玩家和目标UI坐标的线段与Canvas边界有没有交点来判断物体是否在视野内,并且给目标点设置偏移量让箭头可以提前或者延迟显隐。

最终代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class FindTest : MonoBehaviour
{
    public Canvas canvas;
    public Camera cam;
    public Image find; //箭头UI
    public GameObject player; //玩家
    public GameObject target; //跟踪目标
    List points = new List(); //canvas边界点
    bool isHaveIntersection = false; //判断有没有交点来显隐箭头
    public float targetOffset; //设置目标点偏移,用来控制箭头提前或者延后显隐


    void Start()
    {
        //存储canvas边界点
        points.Add(new Vector3(-canvas.GetComponent().rect.width / 2f, -canvas.GetComponent().rect.height / 2f, 0));
        points.Add(new Vector3(canvas.GetComponent().rect.width / 2f, -canvas.GetComponent().rect.height / 2f, 0));
        points.Add(new Vector3(canvas.GetComponent().rect.width / 2f, canvas.GetComponent().rect.height / 2f, 0));
        points.Add(new Vector3(-canvas.GetComponent().rect.width / 2f, canvas.GetComponent().rect.height / 2f, 0));
    }

    void Update()
    {
        Vector3 pos = Vector3.zero;
        Vector3 pos1 = Camera.main.WorldToScreenPoint(target.transform.position - targetOffset * (target.transform.position - player.transform.position).normalized); //目标屏幕坐标
        Vector3 pos2 = Camera.main.WorldToScreenPoint(player.transform.position); //玩家屏幕坐标
        Vector2 worldPoint1;
        Vector2 worldPoint2;

        //求出目标与玩家的UI坐标
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, pos1, cam, out worldPoint1);
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, pos2, cam, out worldPoint2);

        isHaveIntersection = false; //默认没交点

        //玩家与目标UI坐标连线与Canvas边界连写交点即为箭头位置
        for (int i = 0; i = 0)
        {
            return false;
        }
        //计算交点坐标  
        float t = Cross(a - c, d - c) / Cross(d - c, b - a);
        float dx = t * (b.x - a.x);
        float dy = t * (b.y - a.y);

        IntrPos = new Vector3() { x = a.x + dx, y = a.y + dy };
        return true;
    }
}

PS:如果觉得目标移动的快箭头抖动可以加个过度效果,下面是我用DOTWEEN实现的,可以参考下。

            for (int i = 0; i             
关注
打赏
1648518768
查看更多评论
0.0941s