【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗

文章目录

      • 一、前言
      • 二、思考
      • 三、验证我们的思考
        • 1、创建物体挂组件
        • 2、设置组件参数
        • 3、运行测试
        • 4、结论
      • 四、撸起袖子写代码
        • 1、Line.cs
        • 2、LinesDrawer.cs
      • 五、场景
      • 六、最终运行效果

一、前言

嗨,大家好,我是新发,我又来科普了,相信很多人玩过物理画线小游戏,比如下面这样子:
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第1张图片
使用Unity如何实现物理画线功能呢?今天就来教大家。

最后的实现效果如下:

本工程已上传到GitHub,感兴趣的同学可自行下载学习。
GitHub地址:https://github.com/linxinfa/UnityPhysicsDrawLine
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第2张图片

二、思考

物理画线的核心就是:物理+画线。
物理:
想要有物理特性,最简单的做法就是挂碰撞体(Collider)和刚体(Rigidbody)组件。
画线:
可以使用LineRenderer组件来实现画线功能。

三、验证我们的思考

1、创建物体挂组件

创建一个空物体,重命名为Line,挂上EdgeCollider2DRigidbody2DLineRenderer组件。
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第3张图片

2、设置组件参数

设置一下LineRenderer组件的参数。
Position:坐标点;
Width:线宽度;
Color:线颜色(支持渐变);
Corner Vertices:拐弯处的顶点数量(让拐弯圆滑一点);
End Cap Vertices:线段头尾的顶点数量(让线段头尾圆滑一点);
Use World Space:是否使用世界坐标(不要勾选);
Materias:材质球。
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第4张图片

设置一下EdgeCollider2D组件的参数。
Edge Radius:边界碰撞体的半径。
Points:边界碰撞体的坐标点(要与LineRenderer的点一致)。
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第5张图片

边界碰撞体设置完之后效果如下:
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第6张图片
最后是Rigidbody2D组件的参数。主要是Gravity Scale:重力缩放值;这个值越大,物体受到的重力越大,掉落的加速度就越大。
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第7张图片

3、运行测试

为了模拟掉落到地上的效果,我们加个地面。
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第8张图片
运行测试效果如下:
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第9张图片

4、结论

理论存在,实践验证成功。那么,接下来就是如何使用代码来实现鼠标画线了,关键的点就是把鼠标的坐标设置为线的点。

四、撸起袖子写代码

两个脚本,一个Line.cs负责线段的绘制,一个LinesDrawer.cs负责检测鼠标和生成线段与点。

1、Line.cs

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

/// 
/// 线脚本
/// 
public class Line : MonoBehaviour
{
     
    public LineRenderer lineRenderer;
    public EdgeCollider2D edgeCollider;
    public Rigidbody2D rigidBody;

    /// 
    /// 点数组
    /// 
    [HideInInspector] public List<Vector2> points = new List<Vector2>();
    [HideInInspector] public int pointCount = 0;

    /// 
    /// 画线过程中点与点的最小距离
    /// 
    float pointsMinDistance = 0.1f;

    float circleColliderRadius;

    /// 
    /// 添加点
    /// 
    /// 
    public void AddPoint(Vector2 newPoint)
    {
     
        if (pointCount >= 1 && Vector2.Distance(newPoint, GetLastPoint()) < pointsMinDistance)
            return;

        points.Add(newPoint);
        ++pointCount;

        // 添加圆形碰撞
        var circleCollider = this.gameObject.AddComponent<CircleCollider2D>();
        circleCollider.offset = newPoint;
        circleCollider.radius = circleColliderRadius;


        // Line Renderer
        lineRenderer.positionCount = pointCount;
        lineRenderer.SetPosition(pointCount - 1, newPoint);


        // 边界碰撞体的点
        if (pointCount > 1)
            edgeCollider.points = points.ToArray();
    }


    /// 
    /// 获取最后一个点
    /// 
    /// 
    public Vector2 GetLastPoint()
    {
     
        return lineRenderer.GetPosition(pointCount - 1);
    }

    /// 
    /// 是否启用物理特性
    /// 
    public void UsePhysics(bool usePhysics)
    {
     
        rigidBody.isKinematic = !usePhysics;
    }

    /// 
    /// 设置线颜色
    /// 
    /// 
    public void SetLineColor(Gradient colorGradient)
    {
     
        lineRenderer.colorGradient = colorGradient;
    }

    /// 
    /// 设置画线的点与点之间的最小距离
    /// 
    /// 
    public void SetPointsMinDistance(float distance)
    {
     
        pointsMinDistance = distance;
    }

    /// 
    /// 设置线宽度
    /// 
    /// 
    public void SetLineWidth(float width)
    {
     
        lineRenderer.startWidth = width;
        lineRenderer.endWidth = width;

        circleColliderRadius = width / 2f;
        edgeCollider.edgeRadius = circleColliderRadius;
    }
}

2、LinesDrawer.cs

using UnityEngine;

/// 
/// 画线控制器
/// 
public class LinesDrawer : MonoBehaviour
{
     
    public GameObject linePrefab;

    public LayerMask cantDrawOverLayer;
    int cantDrawOverLayerIndex;

    [Space(30)]
    public Gradient lineColor;
    public float linePointsMinDistance;
    public float lineWidth;

    Line currentLine;
    Camera cam;

    private void Start()
    {
     
        cam = Camera.main;
        cantDrawOverLayerIndex = LayerMask.NameToLayer("CantDrawOver");
    }

    private void Update()
    {
     
        if (Input.GetMouseButtonDown(0))
            BeginDraw();
        if (null != currentLine)
            Draw();
        if (Input.GetMouseButtonUp(0))
            EndDraw();
    }

    // 画线逻辑-----------------------------------------------------------------------

    // 开始画线
    void BeginDraw()
    {
     
        // 实例化线预设
        currentLine = Instantiate(linePrefab, this.transform).GetComponent<Line>();
        // 设置参数
        currentLine.UsePhysics(false);
        currentLine.SetLineColor(lineColor);
        currentLine.SetPointsMinDistance(linePointsMinDistance);
        currentLine.SetLineWidth(lineWidth);


    }

    // 画线进行中
    void Draw()
    {
     
        var pos = cam.ScreenToWorldPoint(Input.mousePosition);
        // 防止线与线之间交叉
        RaycastHit2D hit = Physics2D.CircleCast(pos, lineWidth / 3f, Vector2.zero, 1f, cantDrawOverLayer);
        if (hit)
            EndDraw();
        else
            currentLine.AddPoint(pos);
    }

    // 画线结束
    void EndDraw()
    {
     
        if (null == currentLine) return;
        if (currentLine.pointCount < 2)
        {
     
            Destroy(currentLine.gameObject);
        }
        else
        {
     
            currentLine.gameObject.layer = cantDrawOverLayerIndex;
            currentLine.UsePhysics(true);
            currentLine = null;
        }
    }
}

五、场景

将原来的Line保存为预设,并挂上Line脚本,赋值对应的变量。
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第10张图片
添加一个LayerCantDrawOver,目的是防止画线的时候线与线交叉(也可以防止线与其他被标记为CantDrawOver层的物体交叉)。
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第11张图片
在场景中创建一个空物体,重命名为LineDrawer,并挂上LineDrawer脚本,赋值对应的参数。
【游戏开发实战】TapTap物理画线游戏,教你使用Unity实现2D物理画线功能,看到我为你画的彩虹了吗_第12张图片

六、最终运行效果

你可能感兴趣的:(Unity3D,unity,物理画线,physics,drawline,2d)