最终效果
心急的小伙伴可以直接跳到文章末尾查看最终代码,如果有问题再来看下思路。
首先我们需要确定实现思路。我想到的方案是将玩家和敌人的世界坐标转换为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.敌人进入视野内箭头消失 最开始打算使用
OnBecameVisible
和OnBecameInVisible
来判断目标是否在视野内,但是这种方法不够灵活。于是考虑用另一种方法,就是通过判断玩家和目标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
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?