文章目录
一、前言二、思考三、验证我们的思考1、创建物体挂组件2、设置组件参数3、运行测试4、结论四、撸起袖子写代码1、Line.cs2、LinesDrawer.cs五、场景六、最终运行效果一、前言
嗨,大家好,我是新发,我又来科普了,相信很多人玩过物理画线小游戏,比如下面这样子:
使用Unity
如何实现物理画线功能呢?今天就来教大家。
最后的实现效果如下:
本工程已上传到GitHub
,感兴趣的同学可自行下载学习。
GitHub
地址:/linxinfa/UnityPhysicsDrawLine
二、思考
物理画线的核心就是:物理+画线。
物理:
想要有物理特性,最简单的做法就是挂碰撞体(Collider
)和刚体(Rigidbody
)组件。
画线:
可以使用LineRenderer
组件来实现画线功能。
三、验证我们的思考
1、创建物体挂组件
创建一个空物体,重命名为Line
,挂上EdgeCollider2D
、Rigidbody2D
和LineRenderer
组件。
2、设置组件参数
设置一下LineRenderer
组件的参数。
Position
:坐标点;
Width
:线宽度;
Color
:线颜色(支持渐变);
Corner Vertices
:拐弯处的顶点数量(让拐弯圆滑一点);
End Cap Vertices
:线段头尾的顶点数量(让线段头尾圆滑一点);
Use World Space
:是否使用世界坐标(不要勾选);
Materias
:材质球。
设置一下EdgeCollider2D
组件的参数。
Edge Radius
:边界碰撞体的半径。
Points
:边界碰撞体的坐标点(要与LineRenderer
的点一致)。
边界碰撞体设置完之后效果如下:
最后是Rigidbody2D
组件的参数。主要是Gravity Scale
:重力缩放值;这个值越大,物体受到的重力越大,掉落的加速度就越大。
3、运行测试
为了模拟掉落到地上的效果,我们加个地面。
运行测试效果如下:
4、结论
理论存在,实践验证成功。那么,接下来就是如何使用代码来实现鼠标画线了,关键的点就是把鼠标的坐标设置为线的点。
四、撸起袖子写代码
两个脚本,一个Line.cs
负责线段的绘制,一个LinesDrawer.cs
负责检测鼠标和生成线段与点。
1、Line.cs
using System.Collections;using System.Collections.Generic;using UnityEngine;/// <summary>/// 线脚本/// </summary>public class Line : MonoBehaviour{public LineRenderer lineRenderer;public EdgeCollider2D edgeCollider;public Rigidbody2D rigidBody;/// <summary>/// 点数组/// </summary>[HideInInspector] public List<Vector2> points = new List<Vector2>();[HideInInspector] public int pointCount = 0;/// <summary>/// 画线过程中点与点的最小距离/// </summary>float pointsMinDistance = 0.1f;float circleColliderRadius;/// <summary>/// 添加点/// </summary>/// <param name="newPoint"></param>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 RendererlineRenderer.positionCount = pointCount;lineRenderer.SetPosition(pointCount - 1, newPoint);// 边界碰撞体的点if (pointCount > 1)edgeCollider.points = points.ToArray();}/// <summary>/// 获取最后一个点/// </summary>/// <returns></returns>public Vector2 GetLastPoint(){return lineRenderer.GetPosition(pointCount - 1);}/// <summary>/// 是否启用物理特性/// </summary>public void UsePhysics(bool usePhysics){rigidBody.isKinematic = !usePhysics;}/// <summary>/// 设置线颜色/// </summary>/// <param name="colorGradient"></param>public void SetLineColor(Gradient colorGradient){lineRenderer.colorGradient = colorGradient;}/// <summary>/// 设置画线的点与点之间的最小距离/// </summary>/// <param name="distance"></param>public void SetPointsMinDistance(float distance){pointsMinDistance = distance;}/// <summary>/// 设置线宽度/// </summary>/// <param name="width"></param>public void SetLineWidth(float width){lineRenderer.startWidth = width;lineRenderer.endWidth = width;circleColliderRadius = width / 2f;edgeCollider.edgeRadius = circleColliderRadius;}}
2、LinesDrawer.cs
using UnityEngine;/// <summary>/// 画线控制器/// </summary>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();elsecurrentLine.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
脚本,赋值对应的变量。
添加一个Layer
:CantDrawOver
,目的是防止画线的时候线与线交叉(也可以防止线与其他被标记为CantDrawOver
层的物体交叉)。
在场景中创建一个空物体,重命名为LineDrawer
,并挂上LineDrawer
脚本,赋值对应的参数。
六、最终运行效果
【游戏开发实战】TapTap物理画线游戏 教你使用Unity实现2D物理画线功能 看到我为你画的彩虹了吗