赞
踩
内容为学习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相邻点之间添加碰撞体,根节点上添加刚体,补充上面代码如下:
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>(); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。