原始的寻路使用了一个第三方的unity3d astar库,这地图中是使用六边形的中心作为路径点,而且可通行的区域不能动态变化,所以想改造一下。
改造达到的效果是1)不使用路径点,而是每个六边形的格子里面的点都可以作为寻路的目标;2)选了不同的角色之后,可以通行的区域不同;3)能显示出可通行的区域。
自己使用a*算法重新写了寻路后,这两点都没有问题了。但是要显示出可以通行的区域就比较麻烦了,最后想了一个办法,修改了代码和shader后实现了,记录在此。
显示的效果如下:绿色部分为可以通行的区域,红色部分为不可通行的区域。当选择不同的角色之后,显示区域会实时变化。
实现的方法如下:
1)为每种格子类型设定一个id,为整数,从1开始。如果有5种格子,那个id就为1到5。那么地图就由类似下面这样组成:
2)在渲染的地形的时候,新建一个渲染的平面图,这个平面图也是有上面的格子构成,但是需要将格子的id转变为颜色,比如,我这里用id除以10作为颜色的红色:id1的红色值为1/10,id2的红色值为2/10,等等。然后用绿色的值作为最后显示通行区域时绿色和红色的alpha透明度。可以看到第一张图中每个格子中间,绿色和红色基本上没有了,而边缘是最浓的,就是有这个alpha值控制的。渲染下来的结果大概如下所示:颜色相同的格子属于同一个id。
3)在显示可通行的区域时,将当前能通行的区域的id信息转换为一个图片,此图片的宽度为格子的种类*错误冗余值,高度为1,如下所示:
4)决定地图上一个点是否能通行时,对第2步中的图中对应点采样,获取到r值和g值。r值转换回id,比如上面id转换为r值时的方法是r=id/10,那么此时转换回来就是id=r*10。
获取到id值为浮点数,有一定误差,比如本来id为2,但是转换回来可能为1.9。第3步中的错误冗余值就是为了消除这个误差的。
获取到id之后,就使用第3步中的图获取到当前id的格子能不能通行。比如:id为1.9,那么第3步中图对应的x坐标=(1.9 - 0.5) * 4=5.6,所以像素值为第6个像素和第7个像素的插值,为黑色,代表当前格子不能通行,当前点需要用红色显示,透明度为之前的g值,就能达到最开始图中的效果了。
错误冗余值就是保证r值转换为id之后,在第2步的图中采样时,即使有计算误差,采样的坐标也在正确范围之内。比如错误冗余值为4时,初始id为1时,保证转换后的id算出来的x坐标在0~3之间,初始id为2时,x坐标在4~7之间,等等。
shader代码如下:
Shader "HoneyFramework/Terrain"
{
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_PathTex ("Path (RGB)", 2D) = "white" {} // 第2步中的图
_IncludeTex ("Include (RGB)", Rect) = "white" {} // 第3步中的图
_PathColor ("Path Color", Color) = (0, 1, 0, 1) // 可通行格子的颜色,默认为绿色
_BlockColor ("Block Color", Color) = (0.5, 0, 0, 1) // 不能通行格子的颜色,默认为红色
_Switch ("Switch", Int) = 0 // 开关,打开时显示通行状态
_Div ("id to color div", Int) = 10 // id转为r值时的除数,也就是说这个数为10时,id=1时,r值=0.1
_DimTime ("dimension time", Int) = 4 // 错误冗余值
_IncludeLen ("Include length", Int) = 10 // 第3步图的宽度,等于格子种类数量,计算时使用
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 300
CGPROGRAM
#pragma surface surf BlinnPhong addshadow fullforwardshadows nolightmap
#pragma target 3.0
#pragma glsl
struct Input {
float2 uv_MainTex;
float2 uv_PathTex;
};
sampler2D _MainTex;
sampler2D _PathTex;
sampler2D _IncludeTex;
float4 _PathColor;
float4 _BlockColor;
int _Switch;
int _Div;
int _DimTime;
int _IncludeLen;
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
if (0 == _Switch)
{
o.Albedo = c.rgb;
}
else
{
half2 posInfo = tex2D (_PathTex, IN.uv_PathTex).rg;
half pos = posInfo.r * _Div;
if (pos < 0.5)
{
o.Albedo = c.rgb;
}
else
{
pos = (pos - 0.5) * _DimTime / _IncludeLen;
half flag = tex2D (_IncludeTex, float2(pos, 0)).r;
half4 layerColor;
if (flag > 0.9)
{
layerColor = _PathColor;
}
else
{
layerColor = _BlockColor;
}
half alpha = posInfo.g * layerColor.a;
o.Albedo = layerColor.rgb * alpha + c.rgb * (1 - alpha);
}
}
o.Specular = 0.2;
o.Gloss = 1.0;
}
ENDCG
}
FallBack "Diffuse"
}