行军导航过程中导向箭头

最近在做大地图,行军导航过程中会试用到导向箭头,这里整理下实现的过程。
最终效果

箭头实例图


思路分解
1 地图上会有很多这种指向的箭头,同时长度是不固定的,需要根据不同的起始点和终点进行计算角度和方向
2 长度在Unity中可以通过scale进行控制
3 需要重复的箭头,要实现图片平铺的效果,这里就有一个Tiling的概念
4 如果需要移动,可以使用材质的Offset属性
5 选择角度计算过程中,需要考虑到四个象限的不同情况
6 箭头显示要在最上层,不能被地表的物体遮挡
看到这些思路你们能实现的出来吗?不卖官司,接着往下看。
具体实现
原料:
Plane一只,做2D的时候用Sprite原理也是一样的;
箭头图片一张;
Shader文件一个;
材质球一枚;
CS文件一个;

操作步骤:
1 先处理材质球,新建一个Shader,命名为TransparentOverlay,具体代码如下:
[Shell]  纯文本查看  复制代码
?
Shader "Custom/TransparentOverlay" 
     Properties 
    
         _MainTex ( "MainTex(RGBA)" ,2D) = "white" {} 
     }
     SubShader 
    
         LOD 100
         Cull Off Lighting Off ZWrite Off ZTestAlways
         Blend SrcAlpha OneMinusSrcAlpha
         Tags
         {
             "Queue" = "Overlay"
             "IgnoreProjector" = "True"
             "RenderType" = "Transparent"
         }
         Pass
         {
             SetTexture[_MainTex]
         }
     }
}


2 利用该Shader创建一个材质球,将箭头图片赋给材质球

箭头和对应的材质球


3 在场景中新建一个Plane,将材质球赋个Plane,调整Plane到你需要的尺寸,做成预制件

我所用的参数,根据场景自行修改


4 新建一个C#脚本,代码有点长,直接看注释咯,需要额外说的是,计算长度和角度公式大致如下,在其他地方使用的时候还是要根据当前场景的相机,地图大小等等进行相应的微调。

[C#]  纯文本查看  复制代码
?
usingUnityEngine;
///<summary>
/// 行军路线
///</summary>
public classMapLine : MonoBehaviour {
     private Vector3 startPos = Vector3.one;
     private Vector3 endPos = Vector3.one;
     private Vector3 rotation = Vector3.zero;
     private Material material;
     private bool isMove;
     private Vector2 moveDir;
     private Vector2 resetOffset;
     void Awake()
     {
         isMove = false ;
         moveDir = new Vector2(0, 0.01f);
         resetOffset = new Vector2(0, 100);
         material =GetComponent<Renderer>().material;
     }
     /// <summary>
     /// 设置材质的Offset的属性,让箭头移动起来
     /// </summary>
     private void Update()
     {
         if (isMove)
         {
             if (material.mainTextureOffset ==resetOffset)
                 material.mainTextureOffset =moveDir;
             material.mainTextureOffset +=moveDir;
         }
     }
     public void SetLine(Vector3 startPos,Vector3 endPos)
     {
         this .startPos = startPos;
         this .endPos = endPos;
         transform.localScale = Vector3.one *0.05f;
         transform.position = startPos;
         transform.eulerAngles = Vector3.zero;
         var scale = transform.localScale;
         var lineLong = CalLineLong() * 2;
         scale.z = scale.z * lineLong;
         transform.localScale = scale;
         rotation.y = CalLineAngle();
         transform.eulerAngles = rotation;
         material.mainTextureScale = newVector2(1, lineLong);
         transform.Translate(0,0,lineLong / 4,Space.Self);
         isMove = true ;
     }
     /// <summary>
     /// 计算行军路线长度
     /// </summary>
     private float CalLineLong()
     {
         return Mathf.Sqrt(Mathf.Pow(startPos.x- endPos.x, 2) + Mathf.Pow(startPos.z - endPos.z, 2));
     }
     /// <summary>
     /// 计算行军路线角度
     /// </summary>
     private float CalLineAngle()
     {
         //斜边长度
         float length = Mathf.Sqrt(Mathf.Pow((startPos.x- endPos.x), 2) + Mathf.Pow((startPos.z - endPos.z), 2));
         //对边比斜边 sin
         float hudu =Mathf.Asin(Mathf.Abs(startPos.z - endPos.z) / length);
         float ag = hudu * 180 / Mathf.PI;
         //第一象限
         if ((endPos.x - startPos.x) >= 0&& (endPos.z - startPos.z >= 0))
             ag = -ag + 90;
         //第二象限
         else if ((endPos.x - startPos.x) <=0 && (endPos.z - startPos.z >= 0))
             ag = ag - 90;
         //第三象限
         else if ((endPos.x - startPos.x) <=0 && (endPos.z - startPos.z) <= 0)
             ag = -ag +270;
         //第四象限
         else if ((endPos.x - startPos.x) >=0 && (endPos.z - startPos.z) <= 0)
             ag = ag + 90;
         return ag;
     }
}



5 将脚本附加到预制件中,通过设置SetLine方法设置起点和终点就可以在地图上画箭头了。

猜你喜欢

转载自blog.csdn.net/wotingdaonile/article/details/80923549