Unity在屏幕边界追踪目标提示

Unity 在屏幕边界显示追踪目标提示 c#

实现功能:物体A在屏幕内,物体B在屏幕外,在屏幕四周边框上显示物体B相对于A的方向提示

  • 思路
    1、将物体A、B的世界坐标变为屏幕坐标
    2、检测屏幕坐标AB连线与屏幕四条边是否有交点
    3、将屏幕交点坐标转化为UI坐标
    4、将UI坐标赋给图标

  • 将【两点--------->线段】,判断两线的关系并求交点

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

public class Line2D  {

    //共线
    public const int COLINE = 0;
    //相交
    public const int CROSS = 1;
    //平行线
    public const int PARALLEL = 2;
    //无相交
    public const int NOT_CROSS = 3;


    private double EPS = 1e-4;

    public Vector3 point1;
    public Vector3 point2;

    private float A;
    private float B;
    private float C;

    public Line2D(Vector3 point1, Vector3 point2)
    {
        this.point1 = point1;
        this.point2 = point2;
        this.calcCoefficient();
    }

    //计算两点组成的直线的系数(Ax+By+C=0)
    private void calcCoefficient()
    {
        this.A = this.point2.y - this.point1.y;
        this.B = this.point1.x - this.point2.x;
        this.C = this.point2.x * this.point1.y - this.point1.x * this.point2.y;
    }

    //检查是否交叉(当前线的两点,其他线的两点)
    private bool checkCross(Vector3 sp1, Vector3 ep1, Vector3 sp2, Vector3 ep2)
    {

        if (Mathf.Max(sp1.x, ep1.x) < Mathf.Min(sp2.x, ep2.x))
        {
            return false;
        }

        if (Mathf.Min(sp1.x, ep1.x) > Mathf.Max(sp2.x, ep2.x))
        {
            return false;
        }

        if (Mathf.Max(sp1.y, ep1.y) < Mathf.Min(sp2.y, ep2.y))
        {
            return false;
        }

        if (Mathf.Min(sp1.y, ep1.y) > Mathf.Max(sp2.y, ep2.y))
        {
            return false;
        }

        Vector3 vectorA = sp1 - sp2;
        Vector3 vectorB = ep2 - sp2;
        Vector3 vectorC = ep2 - sp2;
        Vector3 vectorD = ep1 - sp2;
        double temp1 = (vectorA.x * vectorB.y - vectorA.y * vectorB.x) * (vectorC.x * vectorD.y - vectorC.y * vectorD.x);

        vectorA = sp2 - sp1;
        vectorB = ep1 - sp1;
        vectorC = ep1 - sp1;
        vectorD = ep2 - sp1;
        double temp2 = (vectorA.x * vectorB.y - vectorA.y * vectorB.x) * (vectorC.x * vectorD.y - vectorC.y * vectorD.x);

        if ((temp1 >= 0) && (temp2 >= 0))
        {
            return true;
        }

        return false;
    }

    //
    private bool isDoubleEqualZero(float data)
    {
        if (Mathf.Abs(data) <= EPS)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    /// <summary>
    /// 交点计算
    /// </summary>
    /// <param name="otherLine">其他要比较的线</param>
    /// <param name="intersectantPoint">交点</param>
    /// <returns>两条线的情况</returns>
    public int Intersection(Line2D otherLine, out Vector2 intersectantPoint)
    {
        intersectantPoint = Vector2.zero;
        //检查是否相交
        if (!checkCross(this.point1, this.point2, otherLine.point1, otherLine.point2))
        {
            return Line2D.NOT_CROSS;
        }
        //检查是否平行
        if (isDoubleEqualZero(this.A * otherLine.B - this.B * otherLine.A))
        {
            if (isDoubleEqualZero((this.A + this.B) * otherLine.C - (otherLine.A + otherLine.B) * this.C))
            {
                return Line2D.COLINE;
            }
            else
            {
                return Line2D.PARALLEL;
            }
        }
        else
        {
            //    C1*B2-B1*C2           A1*C2-C1*A2
            // X=-------------       Y=--------------
            //    B1*A2-A1*B2           B1*A2-A1*B2
            intersectantPoint.x = (otherLine.B * this.C - this.B * otherLine.C) / (otherLine.A * this.B - this.A * otherLine.B);
            intersectantPoint.y = (this.A * otherLine.C - otherLine.A * this.C) / (otherLine.A * this.B - this.A * otherLine.B);
            
            return Line2D.CROSS;
        }
    }
}
  • 将下面的代码绑定在指示作用的UI图片上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;

public class ScreenEdgeTips : MonoBehaviour {

    //UI
    public Text distanceLabel;
    //父对象的rect
    public RectTransform directContainer;
    //本图片标签的宽度
    public float prefabWidth;
    //物体A
    public GameObject fromHero;
    //物体B
    public GameObject toHero;

    //cameras
    private Camera mainCamera;
    public Camera uicamera;

    //param
    private List<Line2D> screenLines;


    private void Update()
    {
       UpdateImp();
    }

    private void Start()
    {
        float offsetWidth = prefabWidth / 2; //偏差
        float originalPoint = 0 + offsetWidth; //初始点+偏差
        float correctionWidth = Screen.width - offsetWidth;//修正的屏幕宽度          
        float correctionHeight = Screen.height - offsetWidth;//修正的屏幕高度          
        Vector3 point1 = new Vector3(offsetWidth, offsetWidth, 0);              //     P2------------P3           
        Vector3 point2 = new Vector3(offsetWidth, correctionHeight, 0);         //       |          |
        Vector3 point3 = new Vector3(correctionWidth, correctionHeight, 0);     //       |          |
        Vector3 point4 = new Vector3(correctionWidth, offsetWidth, 0);          //     P1------------ P4
        this.screenLines = new List<Line2D>();
        this.screenLines.Add(new Line2D(point1, point2));
        this.screenLines.Add(new Line2D(point2, point3));
        this.screenLines.Add(new Line2D(point3, point4));
        this.screenLines.Add(new Line2D(point4, point1));
        this.mainCamera = Camera.main;
    }
    
    //点是否在屏幕内
    private bool PointIsInScreen(Vector3 pos)
    {
        if (pos.x <= this.screenLines[0].point1.x
            || pos.x >= this.screenLines[1].point2.x
            || pos.y <= this.screenLines[0].point1.y
            || pos.y >= this.screenLines[1].point2.y)
        {
            return false;
        }
        return true;
    }

    //世界坐标转换为屏幕坐标
    private Vector2 WorldToScreenPoint(Vector3 pos)
    {
        if (null != this.mainCamera)
        {
            return mainCamera.WorldToScreenPoint(pos);
        }
        return Vector2.zero;
    }
    
    public void UpdateImp()
    {
        bool isIntersce = false;
        if (fromHero != null)
        {
            Vector2 intersecPos = new Vector2();
            Vector2 fromPos = this.WorldToScreenPoint(fromHero.transform.position);
            Vector2 toPos = Vector2.zero;
            //Debug.Log("fromPos的屏幕坐标是=" + fromPos);
            if (toHero != null)
            {
                toPos = this.WorldToScreenPoint(toHero.transform.position);
                //Debug.Log("toPos的屏幕坐标是=" + toPos);
            }
            //物体B存在且物体A在屏幕内
            if (toPos != Vector2.zero && this.PointIsInScreen(fromPos))
            {
                Line2D line = new Line2D(fromPos, toPos);
                foreach (Line2D l in this.screenLines)
                {
                    if (line.Intersection(l, out intersecPos) == Line2D.CROSS)
                    {
                        isIntersce = true;
                        Debug.Log("有交点 ");
                        break;
                    }
                }
                //有交点
                if (isIntersce)
                {
                    Vector2 finalPos = new Vector2();
                    //将屏幕上的交点换成UI上的交点
                    RectTransformUtility.ScreenPointToLocalPointInRectangle(directContainer, intersecPos, uicamera, out finalPos);
                    this.GetComponent<RectTransform>().anchoredPosition = finalPos;//ui的绝对布局
                }
                //无交点,即物体B在屏幕内,则标签位置位于物体B的上端
                else {
                    if (this.PointIsInScreen(toPos)) {
                        Vector2 finalPos = new Vector2();
                        RectTransformUtility.ScreenPointToLocalPointInRectangle(directContainer, toPos, uicamera, out finalPos);
                        this.GetComponent<RectTransform>().anchoredPosition = finalPos+new Vector2(0,50);//ui的绝对布局
                    }
                }
                if (this.distanceLabel != null && toHero != null)
                {
                    this.distanceLabel.text = String.Format("{0}米", Mathf.Round((toHero.transform.position - fromHero.transform.position).magnitude));
                }
            }
        }
        
    }

}
  • 物体B在屏幕内的情况
    物体B在屏幕内的情况

  • 物体B在屏幕外的情况

物体B在屏幕外的情况

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值