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
形成的效果
使用高亮shader后
这里是要动态生成一个扇形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();
}
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;
///
/// 创建一个扇形Mesh
///
/// 扇形半价
/// 扇形角度
/// 扇形弧线分段数
/// 扇形角度精度(在满足精度范围内,认为是同个角度)
///
///
/// 扇形半价精度(在满足半价精度范围内,被认为是同个半价)。
/// 比如:半价精度为1000,则:1.001和1.002不被认为是同个半径。因为放大1000倍之后不相等。
/// 如果半价精度设置为100,则1.001和1.002可认为是相等的。
///
///
///
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)分配三角形.
如图所示:
生成一个扇形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参数。
这类和扇形一样,就是不需要设置度数,使用一个默认的选择度数,例如60度。当有1个敌人在这个选择扇形的60度之内,他就是目标。如果有多个敌人在范围之内,选取离中心射线夹角最近的。如图所示:
1.当选择指示器的扇形范围内没敌人
2.当选择指示器的扇形范围内有一个敌人,那个选中的敌人头上显示红柱子(后期使用上帝之光来做)
3.当有多个敌人在选择范围内,选择离中心射线最近的
代码如下:
///
/// 选择提示器
///
///
///
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 listUnit = new List();
foreach (var item in bufCollider)
{
UnitCtrl unit = item.GetComponentInParent();
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;
}
其中要注意的是选中的红柱子,场景内只能有一个(选中型技能一次只能攻击一个人),当我有选择目标时,设置红柱子的父节点为该目标(实现红柱子在选择范围内跟目标走),当我不存在选择目标,红柱子不激活,并且放回pool池的子节点中。代码如下:
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();
hintRenderer.material.SetColor("_Color", Color.red);
}
else
{
m_headLock.transform.SetParent(m_prefab.transform);
m_headLock.transform.localPosition = new Vector3(0, 0, 0);
}
}