内容为学习siki学院课程后做的笔记,感兴趣可以查看原课程。
制作水滴
水体是由一个个水滴构成的,所以先实现一个水滴。
2D Object -> Sprites ->Circle创建一个2D circle作为一个水滴,调整到适合大小,修改颜色为蓝色。
添加三个Sorting Layers,用于控制显示的先后顺序,下面的优先级高,显示在前面,水滴的Sorting Layers改为Water。
添加Circle Collider 2D,Rigidbody 2D,Trail Renderer三个组件。
Circle Collider 2D的碰撞体范围改小一些,使得多个水滴接触时有相溶的感觉。
Rigidbody 2D主要是添加重力效果,新建一个2D物理材质添加到这个Rigidbody 2D的材质上,修改弹性为0.2,使得它落到障碍物上时有一点弹性。
Trail Renderer用于实现水滴掉落时拖尾的效果,修改颜色和水滴一致,调整拖尾线的宽度,前面粗后面细,Time是拖尾存在时间,改短一点即可,材质使用默认材质。
将这个水滴保存为prefab。
水龙头生成水
弄一个简单场景,上面水龙头用来指示出水的地方,下面的Square用做障碍物,添加Box Collider 2D,Sorting Layers改为Block,新建如下脚本挂在相机上。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class WaterSimulation : MonoBehaviour
{
//水龙头
public GameObject tap;
//水滴
public GameObject water;
public int waterNum;
private Vector3 _tapPos;
private WaitForSeconds _waitForSeconds = new WaitForSeconds(0.02f);
void Start()
{
_tapPos = tap.transform.position;
}
private void OnGUI()
{
if (GUI.Button(new Rect(0, 0, 100, 50),"生成水"))
{
StartCoroutine(SpawnWater());
}
}
private IEnumerator SpawnWater()
{
for (int i = 0; i < waterNum; ++i)
{
Vector3 pos = new Vector3(Random.Range(_tapPos.x - 0.03f, _tapPos.x - 0.03f),
_tapPos.y - 0.3f, 0);
Instantiate(water, pos, Quaternion.identity, transform);
yield return _waitForSeconds;
}
}
}
杯子接水
场景中添加一个杯子,Sorting Layers改为Glass,加上刚体和Edge Colloder 2D,刚体质量改大一些,防止被水冲走,边缘碰撞器由线段组成,可以自由调整成任何形状,首尾不需要相连。
在场景中添加一个圆和菱形,分别添加Circle Collider 2D和Polygon Collider 2D,都添加Rigidbody 2D,圆的mass设为50,菱形的mass设为1,质量大的不容易被推动。
铰链
新建两个Square和一个Circle,分别添加对应的Collider ,置于一个空物体下面,在根节点上添加Rigidbody 2D和Hinge Joint 2D,铰链的Anchor要对齐到圆中心。
铰链可以使两个有刚体的GameObject产生相互作用,发生碰撞时会有旋转的效果。
使用LineRenderer绘制障碍物
原理是在LineRenderer相邻点之间添加碰撞体,根节点上添加刚体,补充上面代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class WaterSimulation : MonoBehaviour
{
//水龙头
public GameObject tap;
//水滴
public GameObject water;
public int waterNum;
public LineRenderer lineRenderer;
private Vector3 _tapPos;
private WaitForSeconds _waitForSeconds = new WaitForSeconds(0.02f);
private Camera _camera;
private List<Vector2> _pointList = new List<Vector2>();
private HashSet<Vector2> _pointHashSet = new HashSet<Vector2>();
private bool _canDraw = true;
void Start()
{
_tapPos = tap.transform.position;
lineRenderer.positionCount = 0;
_camera = Camera.main;
}
private void OnGUI()
{
if (GUI.Button(new Rect(0, 0, 100, 50),"生成水"))
{
StartCoroutine(SpawnWater());
}
}
private IEnumerator SpawnWater()
{
for (int i = 0; i < waterNum; ++i)
{
Vector3 pos = new Vector3(Random.Range(_tapPos.x - 0.03f, _tapPos.x - 0.03f), _tapPos.y - 0.3f, 0);
Instantiate(water, pos, Quaternion.identity, transform);
yield return _waitForSeconds;
}
}
private void Update()
{
if (Input.GetMouseButton(0) && _canDraw)
{
//鼠标的位置从屏幕空间转换到世界空间
Vector2 pos = _camera.ScreenToWorldPoint(Input.mousePosition);
if (!_pointHashSet.Contains(pos))
{
_pointHashSet.Add(pos);
_pointList.Add(pos);
//添加点
int pointCount = ++lineRenderer.positionCount;
lineRenderer.SetPosition(pointCount - 1, pos);
//在两点之间添加碰撞体
if (pointCount > 1)
{
Vector2 point1 = _pointList[pointCount - 2];
Vector2 point2 = _pointList[pointCount - 1];
GameObject go = new GameObject("Collider");
go.transform.parent = lineRenderer.transform;
//碰撞体中心在两点之间
go.transform.localPosition = (point1 + point2) / 2;
var boxCollider = go.AddComponent<BoxCollider2D>();
//碰撞体长度等于两点之间连线的长度,宽度等于线的宽度
boxCollider.size = new Vector2((point2 - point1).magnitude, lineRenderer.startWidth);
//碰撞体的右侧朝向线的方法
go.transform.right = (point2 - point1).normalized;
}
}
}
if (Input.GetMouseButtonUp(0))
{
_canDraw = false;
if (lineRenderer.gameObject.GetComponent<Rigidbody2D>() == null)
lineRenderer.gameObject.AddComponent<Rigidbody2D>();
}
}
}