【游戏开发实战】Unity实现水果忍者切水果的刀痕效果教程(两种实现方式:TrailRenderer、LineRenderer)

一、前言

嗨,大家好,我是新发,相信很多人都玩过水果忍者,在屏幕上滑手指头切水果,效果如下:
在这里插入图片描述
这个手指头滑来滑去的刀痕效果,如果使用Unity如何实现呢?
今天我就来讲讲两种实现方式:
方式一:TrailRenderer
方式二:LineRenderer
最终两种方式的效果如下。
TrailRenderer方式的效果 LineRenderer方式的效果
Demo工程我已上传到GitHub,感兴趣的同学可以自行下载学习(注:我使用的Unity版本为:2019.4.17f1c1
GitHub地址:https://github.com/linxinfa/UnityLineRendererAndTrailRendererDemo
在这里插入图片描述

二、资源准备

先把必要的资源导入到Unity工程中。一张背景图、两张刀痕素材图。
(注:两种刀痕素材图会分别用作用于下文中要说的TrailRendererLineRenderer)。
请添加图片描述 请添加图片描述 在这里插入图片描述
如下,
在这里插入图片描述
注意图片设置勾选Alpha Is Transparency
在这里插入图片描述

三、制作材质球

创建三个材质球:bgtrailtrail_2
其中bg材质球使用的shaderUnlit/Texture
在这里插入图片描述
trailtrail_2材质球使用的shaderMobile/Particles/Additive
在这里插入图片描述

四、背景图

先在场景中创建一个平面,赋值bg材质球,这样背景的显示就完成了。
在这里插入图片描述

五、刀痕的实现,方式一:TrailRenderer

TrailRenderer组件可以很方便地实现一个拖尾效果,我们只需控制所挂的物体的移动即可出现拖尾效果。

1、创建物体挂TrailRenderer组件

首先,在场景中创建一个空物体,重命名为trailrenderer
在这里插入图片描述
挂上TrailRenderer组件。并设置一下各个参数:
Width:线段宽度;
Time:线段持续时间;
Min Vertex Distance:点与点之间的最小距离;
Color:线段颜色;
Texture Mode:线段贴图填充模式;
Materials:材质球;
在这里插入图片描述

2、编写TrailRendererBehaviour脚本

接着就是使用脚本来获取鼠标的位置并控制物体的移动。
创建一个脚本:TrailRendererBehaviour,挂到物体上,
在这里插入图片描述
代码如下:

// TrailRendererBehaviour.cs

using UnityEngine;

public class TrailRendererBehaviour : MonoBehaviour
{
    public TrailRenderer trailrenderer;
    Transform mSelfTrans;

    /// <summary>
    /// 线段的z轴坐标
    /// </summary>
    const float LINE_POS_Z = 10;

    void Awake()
    {
        mSelfTrans = transform;
    }


    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            // 停止划线,防止坐标瞬移导致出现一个拖尾
            trailrenderer.emitting = false;
            var mousPos = Input.mousePosition;
            mSelfTrans.position = Camera.main.ScreenToWorldPoint(new Vector3(mousPos.x, mousPos.y, LINE_POS_Z));
            return;
        }
        
        
        if(Input.GetMouseButton(0))
        {
            trailrenderer.emitting = true;
            var mousPos = Input.mousePosition;
            mSelfTrans.position = Camera.main.ScreenToWorldPoint(new Vector3(mousPos.x, mousPos.y, LINE_POS_Z));
        }
    }
}

3、运行测试

运行Unity,测试效果如下:
在这里插入图片描述

六、刀痕的实现,方式二:LineRenderer

LineRenderer组件可以很方便地实现划线功能,不过,不像TrailRenderer那样可以自动根据物体移动划出拖尾痕迹,需要我们自己去计算划痕的每个点的坐标并赋值给LineRenderer的点。

1、创建物体挂LineRenderer组件

首先,创建一个空物体,重命名为linerenderer
在这里插入图片描述
挂上LineRenderer组件,并设置PositionsSize10,即:我们使用10个点来画线。
在这里插入图片描述
记得设置一下材质球:
在这里插入图片描述

2、编写LineRendererBehaviour脚本

创建一个LineRendererBehaviour脚本,挂到物体上。
在这里插入图片描述
我们在LineRendererBehaviour脚本中去获取鼠标移动的位置并设置给LineRenderer组件的各个点的坐标。
代码如下,基本我都写了清晰的注释,大家应该能看懂。

// LineRendererBehaviour.cs
using UnityEngine;

public class LineRendererBehaviour : MonoBehaviour
{
    public LineRenderer linerenderer;
    /// <summary>
    /// 线段的z轴坐标
    /// </summary>
    const float LINE_POS_Z = 10;
    /// <summary>
    /// 线段的点的数量
    /// </summary>
    const int LINE_POS_CNT = 10;

    /// <summary>
    /// 坐标点的数组
    /// </summary>
    Vector3[] mLinePosList = new Vector3[LINE_POS_CNT];

    /// <summary>
    /// 鼠标的屏幕坐标
    /// </summary>
    Vector3 mMouseScreenPos;
    /// <summary>
    /// 是否是按下
    /// </summary>
    bool mFire = false;
    /// <summary>
    /// 上一次是否是按下
    /// </summary>
    bool mFirePre = false;
    /// <summary>
    /// 是否是刚按下
    /// </summary>
    bool mFireDown = false;
    /// <summary>
    /// 是否是抬起
    /// </summary>
    bool mFireUp = false;

    /// <summary>
    /// 坐标的起始和终止坐标点
    /// </summary>
    Vector2 mStart, mEnd;


    /// <summary>
    /// 坐标点索引
    /// </summary>
    int mLinePosIndex = 0;

    /// <summary>
    /// 线段的alpha通道值
    /// </summary>
    float mTrailAlpha = 0f;


    void Update()
    {
        // 鼠标的位置
        mMouseScreenPos = Input.mousePosition;
        mFireDown = false;
        mFireUp = false;

        mFire = Input.GetMouseButton(0);
        if (mFire && !mFirePre) mFireDown = true;
        if (!mFire && mFirePre) mFireUp = true;
        mFirePre = mFire;

        // 画线
        DrawLine();
        // 设置线段颜色,主要是设置alpha值,慢慢变淡
        SetLineColor();
    }

    void SetLineColor()
    {
        if (mTrailAlpha > 0)
        {
            // 黄色
            linerenderer.startColor = new Color(1, 1, 0, mTrailAlpha);
            // 红色
            linerenderer.endColor = new Color(1, 0, 0, mTrailAlpha);
            // 慢慢变透明
            mTrailAlpha -= Time.deltaTime * 2;
        }
    }

    /// <summary>
    /// 画线
    /// </summary>
    void DrawLine()
    {
        // 鼠标按下
        if (mFireDown)
        {
            mStart = mMouseScreenPos;
            mEnd = mMouseScreenPos;

            mLinePosIndex = 0;
            mTrailAlpha = 1;
            AddTrailPoint();
        }

        // 鼠标滑动中
        if (mFire)
        {
            mEnd = mMouseScreenPos;
            var pos1 = Camera.main.ScreenToWorldPoint(new Vector3(mStart.x, mStart.y, LINE_POS_Z));
            var pos2 = Camera.main.ScreenToWorldPoint(new Vector3(mEnd.x, mEnd.y, LINE_POS_Z));
            // 滑动距离超过0.1才算作一次有效的滑动
            if (Vector3.Distance(pos1, pos2) > 0.01f)
            {
                mTrailAlpha = 1;
                ++mLinePosIndex;
                // 添加坐标点到数组中
                AddTrailPoint();
            }

            mStart = mMouseScreenPos;
        }

        // 将坐标数组赋值给LineRenderer组件
        SetLineRendererPos();
    }

    /// <summary>
    /// 添加坐标点到数组中
    /// </summary>
    void AddTrailPoint()
    {
        if (mLinePosIndex < LINE_POS_CNT)
        {
            for (int i = mLinePosIndex; i < LINE_POS_CNT; ++i)
            {
                mLinePosList[i] = Camera.main.ScreenToWorldPoint(new Vector3(mEnd.x, mEnd.y, LINE_POS_Z));
            }
        }
        else
        {
            for (int i = 0; i < LINE_POS_CNT - 1; ++i)
            {
                mLinePosList[i] = mLinePosList[i + 1];
            }
            mLinePosList[LINE_POS_CNT - 1] = Camera.main.ScreenToWorldPoint(new Vector3(mEnd.x, mEnd.y, LINE_POS_Z));
        }
    }

    /// <summary>
    /// 将坐标数组赋值给LineRenderer组件
    /// </summary>
    void SetLineRendererPos()
    {
        for (int i = 0; i < LINE_POS_CNT; ++i)
        {
            linerenderer.SetPosition(i, mLinePosList[i]);
        }
    }
}
3、运行测试

运行Unity,测试效果如下:
在这里插入图片描述

  • 23
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
实现line renderer写字效果的方法通常是将字体转换为线条的形式,并使用Line Renderer组件在屏幕上渲染出来。以下是一个基本的实现示例: ```csharp using System.Collections; using System.Collections.Generic; using UnityEngine; public class WriteText : MonoBehaviour { public Font font; public Material material; public float lineWidth = 0.1f; public int fontSize = 32; public string text = "Hello World"; private LineRenderer lineRenderer; void Start() { lineRenderer = gameObject.AddComponent<LineRenderer>(); lineRenderer.material = material; lineRenderer.useWorldSpace = false; CharacterInfo charInfo; font.RequestCharactersInTexture(text, fontSize, FontStyle.Normal); Vector3[] positions = new Vector3[text.Length * 2]; int[] indices = new int[(text.Length - 1) * 2]; for (int i = 0; i < text.Length; i++) { font.GetCharacterInfo(text[i], out charInfo, fontSize); positions[i * 2] = new Vector3(charInfo.minX, 0, 0); positions[i * 2 + 1] = new Vector3(charInfo.maxX, 0, 0); if (i > 0) { indices[(i - 1) * 2] = i * 2 - 1; indices[(i - 1) * 2 + 1] = i * 2; } } lineRenderer.positionCount = positions.Length; lineRenderer.SetPositions(positions); lineRenderer.startWidth = lineWidth; lineRenderer.endWidth = lineWidth; lineRenderer.numCapVertices = 5; lineRenderer.numCornerVertices = 5; lineRenderer.SetIndices(indices, MeshTopology.Lines, 0); } } ``` 在这个示例中,我们首先在Start函数中创建了一个Line Renderer组件并将其附加到该GameObject上。然后,我们使用Font类中的RequestCharactersInTexture函数将字体中的字符加载到纹理中。接下来,我们计算每个字符的位置,并将其作为一个线条的两个顶点添加到positions数组中。最后,我们将indices数组设置为适当的线段索引,以便Line Renderer可以正确地绘制线条。 请注意,此示例中的代码仅用于演示目的。如果您要实现更复杂的文本渲染效果,例如文字曲线或3D字体,您需要使用更高级的技术和算法。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林新发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值