Shader实例:NGUI制作网格样式血条

效果:

思路:
1.算出正确的uv去采样过滤图,上一篇文章说的很明白了。Shader实例:NGUI图集中的UISprite正确使用Shader的方法

2.用当前血量占总血量的百分比来设置shader中的变量,来控制血条的裁剪。
实际操作中,在shader中声明一个uniform float _Factor
然后在C#脚本中,对这个变量进行设置,结果发现,界面上不能实时响应这个值,进行正确的裁剪。
那么我只好牺牲color的一个分量,比如设置g分量,shader中用g分量的值来对血条进行裁剪。最终勉强达到效果。

如果有的其他好的方式,请留言告诉我哦!

shader代码:改写自Unlit – Transparent Colored
//–add– 部分就是我添加的。

Shader "Custom/Unlit/Transparent Colored Hp Mask"
{
    Properties
    {
        _MainTex ("Base (RGB), Alpha (A)", 2D) = "black" {}
 
        //---add---------------------------------
        _MaskTex ("Mask Alpha (A)", 2D) = "white" {}
 
        _WidthRate ("Sprite.width/Atlas.width", float) = 1
        _HeightRate ("Sprite.height/Atlas.height", float) = 1
        _XOffset("offsetX/Atlas.width", float) = 0
        _YOffset("offsetY/Atlas.height", float) = 0
 
        //_Factor("factor",range(0,1)) = 1
        //--------------------------------------
    }
 
    SubShader
    {
        LOD 100
 
        Tags
        {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
        }
 
        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Offset -1, -1
        Blend SrcAlpha OneMinusSrcAlpha
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
 
            #include "UnityCG.cginc"
 
            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                fixed4 color : COLOR;
            };
 
            struct v2f
            {
                float4 vertex : SV_POSITION;
                half2 texcoord : TEXCOORD0;
                fixed4 color : COLOR;
            };
 
            sampler2D _MainTex;
            float4 _MainTex_ST;
 
            //---add-------
            sampler2D _MaskTex;
 
            float _WidthRate;
            float _HeightRate;
            float _XOffset; 
            float _YOffset; 
 
            //float _Factor;
            //--------------
 
            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.texcoord = v.texcoord;
                o.color = v.color;
                return o;
            }
 
            fixed4 frag (v2f i) : COLOR
            {
                fixed4 col;
                col = tex2D(_MainTex, i.texcoord);
 
                //---------add---------------------------------
                //过滤
                if(i.color.r<=0.1)
                {
                    float2 final_uv = float2((i.texcoord.x - _XOffset) / _WidthRate, (i.texcoord.y - _YOffset) / _HeightRate);
 
                    float curr = final_uv.x;
                    final_uv.x *= 20;
                    col.a = col.a * tex2D(_MaskTex, final_uv).a;
 
                    if (curr >= i.color.g)
                    {
                        col.a = 0;
                    }
 
                  /*if (curr >= _Factor)
                    {
                        col.a = 0;
                    }*/
                }        
                //-----------------------------------------------
                return col;
            }
            ENDCG
        }
    }
 
    SubShader
    {
        LOD 100
 
        Tags
        {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
        }
 
        Pass
        {
            Cull Off
            Lighting Off
            ZWrite Off
            Fog { Mode Off }
            Offset -1, -1
            ColorMask RGB
            AlphaTest Greater .01
            Blend SrcAlpha OneMinusSrcAlpha
            ColorMaterial AmbientAndDiffuse
 
            SetTexture [_MainTex]
            {
                Combine Texture * Primary
            }
        }
    }
}

C#脚本:挂在UISprite上

using UnityEngine;
using System.Collections;
 
public class ScaleTexcoord : MonoBehaviour
{
    private float widthRate;
    private float heightRate;
    private float xOffsetRate;
    private float yOffsetRate;
    private UISprite sprite;
 
    float curr;
 
    void Awake()
    {
        sprite = GetComponent<UISprite>();
        widthRate = sprite.GetAtlasSprite().width * 1.0f / sprite.atlas.spriteMaterial.mainTexture.width;
    heightRate = sprite.GetAtlasSprite().height * 1.0f / sprite.atlas.spriteMaterial.mainTexture.height;
        xOffsetRate = sprite.GetAtlasSprite().x * 1.0f / sprite.atlas.spriteMaterial.mainTexture.width;
    yOffsetRate = (sprite.atlas.spriteMaterial.mainTexture.height-(sprite.GetAtlasSprite().y + sprite.GetAtlasSprite().height)) * 1.0f / sprite.atlas.spriteMaterial.mainTexture.height;
    }
 
    private void Start()
    {
        sprite.atlas.spriteMaterial.SetFloat("_WidthRate", widthRate);
        sprite.atlas.spriteMaterial.SetFloat("_HeightRate", heightRate);
        sprite.atlas.spriteMaterial.SetFloat("_XOffset", xOffsetRate);
        sprite.atlas.spriteMaterial.SetFloat("_YOffset", yOffsetRate);
    }
 
    void OnGUI()
    {
        if (GUI.Button(new Rect(100, 100, 100, 50), ""))
        {
            curr += 0.1f;
            sprite.color = new Color(0,curr,1);
        }
 
        if (GUI.Button(new Rect(220, 100, 100, 50), ""))
        {
            curr -= 0.1f;
            sprite.color = new Color(0, curr, 1);
        }
    }
}

===================================================================
补充:
上面的方法太复杂了,而且不精准。
后来发现了更好的方式。
效果:

还是使用NGUI的UISlider,改值还是改value。
把血条的UISprite设置成如下,用来平铺。

然后根据比例是设置血条UIsprite的width,
然后再根据比例设置血条UISprite的Scale.x

测试代码:HpBarScript

using UnityEngine;
using System.Collections;
 
public class HpBarScript : MonoBehaviour 
{
    public UISprite m_hpSprite;
    public UISlider m_hpSlider;
    public UISprite m_bgSprite;
 
    public float m_bgWidth{get;set;}
    public float m_hpWidth{get;set;}
 
    void Start () 
    {
        this.m_bgWidth = this.m_bgSprite.width;
        this.m_hpWidth = this.m_hpSprite.width;
    }
 
    public void SetHpSpriteWidthAndScale(float _width,float _scale)
    {
        this.m_hpSprite.width = (int)_width;
        this.m_hpSprite.transform.localScale = new Vector3(_scale,1,1);
    }
 
    public void SetHpBarSliderValue(float _value)
    {
        this.m_hpSlider.value = _value;
    }
}

测试代码:TestHpBar

using UnityEngine;
using System.Collections;
 
public class TestHpBar : MonoBehaviour 
{
    public HpBarScript m_hpBarScript;
 
    public float  m_defaultMaxHp = 100;
    public float m_currMaxHp;
    private float m_rate;
 
    private float m_currHp;
 
    void Start () 
    {
        this.m_currMaxHp=m_defaultMaxHp;
        this.m_currHp = this.m_currMaxHp;
        this.m_rate = this.m_defaultMaxHp / m_hpBarScript.m_hpWidth;
    }
 
    void OnGUI()
    {
        if(GUI.Button(new Rect(100,100,100,50),"最大血量加10"))
        {    
            this.m_currMaxHp += 10;
            float scale = m_defaultMaxHp/this.m_currMaxHp;
            this.m_hpBarScript.SetHpSpriteWidthAndScale(this.m_currMaxHp/this.m_rate,scale);
        }
 
        if(GUI.RepeatButton(new Rect(100,200,100,50),""))
        {    
            this.m_currHp+=1;
            this.m_currHp = this.m_currHp>this.m_currMaxHp?this.m_currMaxHp:this.m_currHp;
            float progress = this.m_currHp/this.m_currMaxHp;
            this.m_hpBarScript.SetHpBarSliderValue(progress);
        }
 
        if(GUI.RepeatButton(new Rect(100,300,100,50),""))
        {    
            this.m_currHp-=1;
            this.m_currHp = this.m_currHp<0?0:this.m_currHp;
            this.m_currHp= Mathf.Min(this.m_currHp,this.m_currMaxHp);
            float progress = this.m_currHp/this.m_currMaxHp;
            this.m_hpBarScript.SetHpBarSliderValue(progress);
        }
    }
}
posted @ 2016-05-13 16:25  Joe师傅  阅读(1265)  评论(0编辑  收藏  举报