Allen Kashiwa Blog

羁旅红尘不曾醉,笑歌年少且长行。

专注游戏开发与设计


唯佳人与游戏不可辜负

Unity——来个可变角度的扇形技能指示器

技能指示器

如果你的游戏有战斗系统,那极有可能会做成技能系统,如果你的游戏有技能系统,那极有可能需要提示当前技能的攻击范围,以便玩家预判命中或者闪避这次攻击。

具体的形式如这样的:

image

这样的:

image

还有这样的:

image

矩形(箭头也算是矩形的)和圆形比较好弄,可以绘制好贴图用一个面片搞定。大小通过缩放面片实现。麻烦的是扇形。因为技能肯定不单一,扇形的角度就会有变化。不可能每种角度的扇形都做个特效,这样游戏资源会变多而且策划不能随意调整角度。所以,这个时候程序员们就得解决这个问题,让这样的范围指示器自动生成,避免繁重的美术制作。

网络上常见的方式是生成面片,这种方式的优点是顶点高度可以通过地形改变,在有高度的地形中显示比较自然,缺点是计算复杂,想要产生更平滑的效果需要更多的顶点。网上有不少这种生成面片的文章,大家搜来看看。而我今天要说的这种是通过shader来绘制扇形。

Shader实现版

先来看看最终的效果:

image

从左到右分别是纯色版,带透明度渐变版和实用贴图版。

下面说说制作步骤:

  1. 创建一个Plane
  2. 创建一个Material
  3. 创建一个Shader,内容如下:
Shader "Custom/Indicator" {
    Properties {  
        _MainTex("Main Texture", 2D) = "white" {}
        _Color ("Color", Color) = (0.17,0.36,0.81,0.0)
        _Angle ("Angle", Range(0, 360)) = 60
        _Gradient ("Gradient", Range(0, 1)) = 0
    }

    SubShader {
    Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
         Pass {
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
 
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _Color;
            float _Angle;
            float _Gradient;
 
            struct fragmentInput {
                float4 pos : SV_POSITION;
                float2 uv : TEXTCOORD0;
            };

            fragmentInput vert (appdata_base v)
            {
                fragmentInput o;

                o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.texcoord.xy;

                return o;
            }
 
            fixed4 frag(fragmentInput i) : SV_Target {
            	// 离中心点的距离
                float distance = sqrt(pow(i.uv.x - 0.5, 2) + pow(i.uv.y - 0.5, 2));
                // 在圆外
                if(distance > 0.5f){
                    discard;
                }
                // 根据距离计算透明度渐变
                float grediant = (1 - distance - 0.5 * _Gradient) / 0.5;
                // 正常显示的结果
                fixed4 result = tex2D(_MainTex, i.uv) * _Color * fixed4(1,1,1, grediant);
                float x = i.uv.x;
                float y = i.uv.y;
                float deg2rad = 0.017453;	// 角度转弧度
                // 根据角度剔除掉不需要显示的部分
                // 大于180度
                if(_Angle > 180){
                    if(y > 0.5 && abs(0.5 - y) >= abs(0.5 - x) / tan((180 - _Angle / 2) * deg2rad))
                        discard;// 剔除
                }
                else    // 180度以内
                {
                    if(y > 0.5 || abs(0.5 -y) < abs(0.5 - x) / tan(_Angle / 2 * deg2rad))
                        discard;
                }
                return result;
            }

            ENDCG
        }
    }  
    FallBack "Diffuse"
}
  1. 将Shader赋予Material,将Material赋予Plane
  2. Done

简单吧?

Shader的内容并不复杂,简单来说就是通过UV坐标进行剔除操作。代码注释应该也比较清楚了,大家玩玩看吧。本次依然放出示例工程到我的 Github ,欢迎大家围观。

用支付宝请我喝咖啡

用微信请我吃辣条

最近的文章

Unity预设序列化的自动化方案

预设在Unity中,我们会将重复使用的资源做成预设(Prefab)。预设上可以挂载脚本并在Aspector面板中指定可序列化的值便于配置。在实际操作过程中,我们的脚本上需要配置的部分可能常常需要指定一些固定的组件。加入有这样的一个脚本:像这样,rigBody和capsuleCollider如果在游戏运行时获取会有些消耗,而在Editor模式下又需要我们每次从Hierarchy面板拖动到Aspector面板来指定费时费力。而这一切我们可以通过脚本自动完成。我们在Monster脚本上添加如下接...…

继续阅读
更早的文章

Unity如何自动生成动画状态机

前言不好意思,拖更几个月了,最近屁股先锋中毒太深。今天来说说如何在Unity的编辑模式下自动生成动画状态机。为何需要自动生成动画状态机?游戏角色的动画状态中有许多相似的状态,每个角色都需要创建动画状态机,创建诸如Idle,Run,Walk,NormalAttak等相似的状态,甚至状态机的迁移条件也有雷同。为了不然创建这些相似的状态机并指定状态中相对应的动画这类繁琐的事全部交给手工操作,自动化生成这些状态机成为理所当然。如何自动化生成动画状态机?官方参考官方文档中有关于这个的一份参考代码。你...…

继续阅读