天天看點

Unity3D+moba+技能訓示器(二)

2.3訓示器圖檔高亮顯示shader

建立shader,代碼如下

Shader "Custom/SkillHintBg" {
Properties {
  _MainTex ("Base Texture", 2D) = "white" {}
  _Color ("Main Color", Color) = (1,1,1,1)  
}

Category {
  Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
  Blend SrcAlpha OneMinusSrcAlpha
  Cull Off 
  Lighting Off 
  ZWrite Off 
  
  BindChannels {
    Bind "Color", color
    Bind "Vertex", vertex
    Bind "TexCoord", texcoord
  }
  
  SubShader {
    Pass {
    //ZTest Always
      CGPROGRAM   
        #pragma vertex vert  
        #pragma fragment frag
        
        #include "UnityCG.cginc"   
        
        struct v2f {   
          float4 pos : SV_POSITION;   
          float2 uv : TEXCOORD0;   
        };   
        
        v2f vert(appdata_tan v)   
        {   
          v2f o;   
          o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
          o.uv = v.texcoord; 
          return o;    
        }   
        
        sampler2D _MainTex;  
        float4 _Color; 

        half4 frag (v2f i) : COLOR   
        {   
          half4 result = tex2D (_MainTex, i.uv); 
          result*=_Color;
          return result; 
        }    
      ENDCG 
    }
    Pass {
    ZTest Greater
      CGPROGRAM   
        #pragma vertex vert  
        #pragma fragment frag
        
        #include "UnityCG.cginc"   
        
        struct v2f {   
          float4 pos : SV_POSITION;   
          float2 uv : TEXCOORD0;   
        };   
        v2f vert(appdata_tan v)   
        {   
          v2f o;   
          o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
          o.uv = v.texcoord; 
          return o;    
        }   
        
        sampler2D _MainTex;  
        float4 _Color; 

        half4 frag (v2f i) : COLOR   
        {   
          half4 result = tex2D (_MainTex, i.uv); 
          result*=_Color;
          result.a /= 3;
          return result; 
        }    
      ENDCG 
    }
  }
}
}      

原來使用的shader

Unity3D+moba+技能訓示器(二)

形成的效果

Unity3D+moba+技能訓示器(二)

使用高亮shader後

Unity3D+moba+技能訓示器(二)

2.4 扇形範圍訓示器

這裡是要動态生成一個扇形mesh,通過設定角度和半徑達到要顯示的效果。動态生成扇形mesh代碼如下:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class MeshFan : MonoBehaviour
{
    public float radius = 2;
    public float angleDegree = 100;
    public int segments = 10;
    public int angleDegreePrecision = 1000;
    public int radiusPrecision = 1000;

    private MeshFilter meshFilter;

    private SectorMeshCreator creator = new SectorMeshCreator();
    private Mesh m_mesh;
    [ExecuteInEditMode]
    private void Awake()
    {
        meshFilter = GetComponent<MeshFilter>();
    }

    private void Update()
    {
        meshFilter.mesh = creator.CreateMesh(radius, angleDegree, segments, angleDegreePrecision, radiusPrecision);
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.gray;
        DrawMesh();
    }

    void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.green;
        DrawMesh();
    }

    private void DrawMesh()
    {
        Mesh mesh = creator.CreateMesh(radius, angleDegree, segments, angleDegreePrecision, radiusPrecision);
        int[] tris = mesh.triangles;
        for (int i = 0; i < tris.Length; i += 3)
        {
            Gizmos.DrawLine(convert2World(mesh.vertices[tris[i]]), convert2World(mesh.vertices[tris[i + 1]]));
            Gizmos.DrawLine(convert2World(mesh.vertices[tris[i]]), convert2World(mesh.vertices[tris[i + 2]]));
            Gizmos.DrawLine(convert2World(mesh.vertices[tris[i + 1]]), convert2World(mesh.vertices[tris[i + 2]]));
        }
    }

    private Vector3 convert2World(Vector3 src)
    {
        return transform.TransformPoint(src);
    }

    private class SectorMeshCreator
    {
        private float radius;
        private float angleDegree;
        private int segments;

        private Mesh cacheMesh;

        /// <summary>
        /// 建立一個扇形Mesh
        /// </summary>
        /// <param name="radius">扇形半價</param>
        /// <param name="angleDegree">扇形角度</param>
        /// <param name="segments">扇形弧線分段數</param>
        /// <param name="angleDegreePrecision">扇形角度精度(在滿足精度範圍内,認為是同個角度)</param>
        /// <param name="radiusPrecision">
        /// <pre>
        /// 扇形半價精度(在滿足半價精度範圍内,被認為是同個半價)。
        /// 比如:半價精度為1000,則:1.001和1.002不被認為是同個半徑。因為放大1000倍之後不相等。
        /// 如果半價精度設定為100,則1.001和1.002可認為是相等的。
        /// </pre>
        /// </param>
        /// <returns></returns>
        public Mesh CreateMesh(float radius, float angleDegree, int segments, int angleDegreePrecision, int radiusPrecision)
        {
            if (checkDiff(radius, angleDegree, segments, angleDegreePrecision, radiusPrecision))
            {
                Mesh newMesh = Create(radius, angleDegree, segments);
                if (newMesh != null)
                {
                    cacheMesh = newMesh;
                    this.radius = radius;
                    this.angleDegree = angleDegree;
                    this.segments = segments;
                }
            }
            return cacheMesh;
        }

        private Mesh Create(float radius, float angleDegree, int segments)
        {

            if (segments == 0)
            {
                segments = 1;
#if UNITY_EDITOR
                Debug.Log("segments must be larger than zero.");
#endif
            }

            Mesh mesh = new Mesh();
            Vector3[] vertices = new Vector3[3 + segments - 1];//全部的頂點資料
            vertices[0] = new Vector3(0, 0, 0);

            float angle = Mathf.Deg2Rad * angleDegree;
            float currAngle = angle / 2;
            float deltaAngle = angle / segments;

            currAngle = Mathf.Deg2Rad * (90 + angleDegree / 2);

            //生成頂點資料
            for (int i = 1; i < vertices.Length; i++)
            {
                vertices[i] = new Vector3(Mathf.Cos(currAngle) * radius, 0, Mathf.Sin(currAngle) * radius);
                currAngle -= deltaAngle;
            }

            //生成三角形資料
            int[] triangles = new int[segments * 3];//有segments個三角形,每3個資料構成一個三角形
            for (int i = 0, vi = 1; i < triangles.Length; i += 3, vi++)
            {
                triangles[i] = 0;
                triangles[i + 1] = vi;
                triangles[i + 2] = vi + 1;
            }

            mesh.vertices = vertices;
            mesh.triangles = triangles;

            //紋理坐标
            Vector2[] uvs = new Vector2[vertices.Length];
            for (int i = 0; i < uvs.Length; i++)
            {
                uvs[i] = new Vector2(vertices[i].x, vertices[i].z);
            }
            mesh.uv = uvs;
            
            return mesh;
        }
        private bool checkDiff(float radius, float angleDegree, int segments, int angleDegreePrecision, int radiusPrecision)
        {
            return segments != this.segments || (int)((angleDegree - this.angleDegree) * angleDegreePrecision) != 0 ||
                   (int)((radius - this.radius) * radiusPrecision) != 0;
        }
    }
}      

Mesh :網格元件,主要用于設定外形和外表。3d模型都是由N個三角形構成,而mesh就是儲存描述資訊的集合,建立mesh網格:應該按照以下順序:1)配置設定頂點2)配置設定三角形.

如圖所示:

Unity3D+moba+技能訓示器(二)

生成一個扇形Mesh,由10個小三角形構成。頂點總數數為12.第0個頂點坐标為(0,0,0),然後以z軸為正方向,依次計算每個定點坐标。

//生成頂點資料
            for (int i = 1; i < vertices.Length; i++)
            {
                vertices[i] = new Vector3(Mathf.Cos(currAngle) * radius, 0, Mathf.Sin(currAngle) * radius);
                currAngle -= deltaAngle;
            }      

有了所有頂點坐标後,配置設定三角形。mesh.triangles為一個int[],數量一定是3的倍數,每3個為一組,每個值為索引号到mesh.vertices中找對應的坐标資料。

//生成三角形資料
            int[] triangles = new int[segments * 3];//有segments個三角形,每3個資料構成一個三角形
            for (int i = 0, vi = 1; i < triangles.Length; i += 3, vi++)
            {
                triangles[i] = 0;
                triangles[i + 1] = vi;
                triangles[i + 2] = vi + 1;
            }      

最後根據技能的施法距離和影響半徑設定扇形mesh參數。

Unity3D+moba+技能訓示器(二)

2.5選擇性技能訓示器

這類和扇形一樣,就是不需要設定度數,使用一個預設的選擇度數,例如60度。當有1個敵人在這個選擇扇形的60度之内,他就是目标。如果有多個敵人在範圍之内,選取離中心射線夾角最近的。如圖所示:

1.當選擇訓示器的扇形範圍内沒敵人

Unity3D+moba+技能訓示器(二)

2.當選擇訓示器的扇形範圍内有一個敵人,那個選中的敵人頭上顯示紅柱子(後期使用上帝之光來做)

Unity3D+moba+技能訓示器(二)

3.當有多個敵人在選擇範圍内,選擇離中心射線最近的

/// <summary>
    /// 選擇提示器
    /// </summary>
    /// <param name="skill"></param>
    /// <param name="obj"></param>
    public UnitCtrl tarSelect(SkillCtrl skill,GameObject obj)
    {
        UnitCtrl unitSelect = null;
        float fRadius = 0.0f;
        fRadius = skill.m_disRange;//技能的半徑
        Vector3 pos = transform.position;
        Collider[] bufCollider = Physics.OverlapSphere(pos, fRadius);//擷取周圍成員
        List<UnitCtrl> listUnit = new List<UnitCtrl>();
        foreach (var item in bufCollider)
        {
            UnitCtrl unit = item.GetComponentInParent<UnitCtrl>();
            if (unit != null)
            {
                if (!MainMgr.self.isWe(unit.m_camp) && unit.isAlive && unit.m_isVisible)//非我方,活着,可見
                {
                    listUnit.Add(unit);
                }    
            }
        }

        float minDegree = m_selectDegree/2.0f;
        //在大圓範圍内的再進行篩選  1.滿足選擇範圍夾角,2.離中心射線夾角最小的
        foreach (var unit in listUnit)
        {
            Vector3 unitVec = unit.transform.position - obj.transform.position;
            Vector3 selectVec = obj.transform.forward;
            float degree = Vector3.Angle(unitVec, selectVec);
            if (degree <= minDegree)
            {
                minDegree = degree;
                unitSelect = unit;
            }
        }

        if (unitSelect != null)
        {
            UIMgr.self.headLockSet(true, unitSelect);
        }
        else
        {
            UIMgr.self.headLockSet(false, unitSelect);
        }
        return unitSelect;
}      
public void headLockSet(bool active,UnitCtrl unit)
    {
        m_headLock.SetActive(active);
        if (active == true)
        {
            m_headLock.transform.SetParent(unit.transform);
            m_headLock.transform.localPosition = new Vector3(0,10,0);
            Renderer hintRenderer = m_headLock.GetComponent<Renderer>();
            hintRenderer.material.SetColor("_Color", Color.red);
        }
        else
        {
            m_headLock.transform.SetParent(m_prefab.transform);
            m_headLock.transform.localPosition = new Vector3(0, 0, 0);
        }
    }