雪千渔Blog

  • 首页
  • 写写代码
    • dotNet
    • C++
    • Lua
    • Visual Basic
    • Java
    • Android
    • Web
  • DCC
    • Maya
    • Maya-Plug
    • AfterEffect
    • AfterEffect-Plug
    • PhotoShop-Plug
  • 游戏制作
    • Unity3D
    • UnrealEngine
    • 经验杂谈
    • 游戏设计
    • 自研引擎
    • 效果实现
  • 其他
    • 乱七八糟
    • 软件工具
    • 留言板
    • 自制素材
    • 关于我
  • 世界的尽头
雪千渔blog
唯有热爱,能抵漫长岁月
  1. 首页
  2. GameDev
  3. Unity3D
  4. 正文

Unity尾随渐变式打字机特效

2021年8月16日 1054点热度 3人点赞 0条评论

需求:以单字为单位的透明度递进与播放。

继承BaseMeshEffect制作UI特效。

制作思路:

  1. 声明一个与文字数量同样长度的数组,用于储存每个文字的透明度。
  2. 用索引标记当前显示的文字。
  3. 每帧对从开始处到索引标记的位置进行透明度增加,并储存更新数组。
  4. 调用graphic.SetVerticesDirty,这样会触发ModifyMesh方法。
  5. 在ModifyMesh设置顶点透明度即可更新渲染。

注意:

一个文字由两个三角形构成,而在操作顶点流时,获取的顶点是两个三角的顶点,也就是说,一个文字的顶点数是6而非4,需要丢弃多余的顶点。


效果:

代码:

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[AddComponentMenu("UI/Effects/Typewriter")]
[RequireComponent(typeof(Text))]
public class UIEff_Typewriter : BaseMeshEffect
{
    //当前播放的字
    [SerializeField]
    private int currentIndex = 0;
    private int renderDoneIndex = 0;

    //每个字完成的透明度
    [SerializeField]
    private byte advanceInterval = 16;
    public byte AdvanceInterval { get => advanceInterval; }

    [SerializeField]
    private bool isPlaying = false;
    public bool IsPlaying { get => isPlaying; }

    //每个网格的透明度
    private byte[] opacity;

    //播放结束
    public event Action EndHandler;

    [SerializeField]
    private float speed = 0.5f;
    public float Speed
    {
        get => speed;
        set
        {
            speed = Math.Min(Math.Max(value, 0f), 1f);
        }
    }

    protected override void Awake()
    {
#if UNITY_EDITOR
        if (!UnityEditor.EditorApplication.isPlaying) return;
#endif
        if (!IsActive()) return;
        base.Awake();
        Refresh();
    }

    public void Refresh()
    {
        currentIndex = 0;
        renderDoneIndex = 0;
        opacity = null;
    }

    private void FixedUpdate()
    {
        if (!IsActive()) return;
        if (!isPlaying) return;
        if (opacity == null || opacity.Length == 0)
        {
            graphic.SetVerticesDirty();
            return;
        }
        for (int w = 0; w < Mathf.Lerp(1, 10, speed); w++)
        {
            for (int i = renderDoneIndex; i < opacity.Length; i++)
            {
                //文字索引超过当前渲染文字
                if (i > currentIndex) break;
                //如果当前渲染字超过设定的完成度则前进
                if (opacity[currentIndex] >= this.advanceInterval)
                {
                    //不超过最大字数就前进一格字符
                    if (currentIndex < opacity.Length - 1)
                        ++currentIndex;
                }
                if (opacity[i] < 255)
                {
                    byte opacityStep = 2;
                    if ((int)opacity[i] + opacityStep > 255)
                    {
                        opacity[i] = 255;
                    }
                    else
                    {
                        opacity[i] += opacityStep;
                    }
                }
                if (opacity[i] == 255)
                {
                    ++renderDoneIndex;
                }
            }

            graphic.SetVerticesDirty();

            //最后一个透明度为1时结束
            if (opacity[opacity.Length - 1] == 255)
            {
                Stop();
            }
        }
    }

    public void Play()
    {
        Refresh();
        isPlaying = true;
    }
    public void Stop()
    {
        isPlaying = false;
        if(opacity != null)
        {
            //显示全部文字
            for (int i = 0; i < opacity.Length; i++)
            {
                opacity[i] = 255;
            }
            currentIndex = opacity.Length - 1;
        }

        graphic.SetVerticesDirty();

        EndHandler?.Invoke();
    }

    public override void ModifyMesh(VertexHelper vh)
    {
#if UNITY_EDITOR
        if (!UnityEditor.EditorApplication.isPlaying) return;
#endif
        if (!IsActive()) return;

        List<UIVertex> verts = new List<UIVertex>();
        vh.GetUIVertexStream(verts);

        //6点转4点
        List<UIVertex> vs = new List<UIVertex>();

        for (int i = 1; i <= verts.Count; i += 3)
        {
            vs.Add(verts[i - 1]);
            vs.Add(verts[i]);
        }

        //初始化每个字的数组长度
        if (opacity == null) opacity = new byte[vs.Count / 4];

        //设置透明
        for (int i = 0; i < vs.Count; i += 4)
        {
            UIVertex v1 = vs[i + 0];
            UIVertex v2 = vs[i + 1];
            UIVertex v3 = vs[i + 2];
            UIVertex v4 = vs[i + 3];

            v1.color.a = opacity[i / 4];
            v2.color.a = opacity[i / 4];
            v3.color.a = opacity[i / 4];
            v4.color.a = opacity[i / 4];

            vh.SetUIVertex(v1, i + 0);
            vh.SetUIVertex(v2, i + 1);
            vh.SetUIVertex(v3, i + 2);
            vh.SetUIVertex(v4, i + 3);
        }

    }

}

 

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: UI特效 Unity
最后更新:2022年1月15日

JomiXedYu

一名游戏玩家。

点赞
< 上一篇
下一篇 >

文章评论

取消回复

*

code

JomiXedYu

一名游戏玩家。

分类
  • AfterEffect / 6篇
  • AfterEffect-Plug / 1篇
  • Android / 1篇
  • C++ / 13篇
  • dotNet / 12篇
  • Lua / 4篇
  • Maya / 2篇
  • Maya-Plug / 2篇
  • Office-VSTO&VBA / 2篇
  • Unity3D / 14篇
  • UnrealEngine / 4篇
  • Visual Basic / 8篇
  • Web / 2篇
  • 乱七八糟 / 2篇
  • 效果实现 / 2篇
  • 经验杂谈 / 2篇
  • 自制素材 / 3篇
  • 自研引擎 / 1篇
  • 计算机图形学 / 1篇
  • 软件工具 / 4篇
友情链接
  • DorinXL
  • 小博博客
  • 秋橘斋

COPYRIGHT © 2014-2021 雪千渔Blog. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

辽ICP备20006894号-1