Unity 水体效果模拟

内容为学习siki学院课程后做的笔记,感兴趣可以查看原课程。

制作水滴

水体是由一个个水滴构成的,所以先实现一个水滴。
2D Object -> Sprites ->Circle创建一个2D circle作为一个水滴,调整到适合大小,修改颜色为蓝色。
Unity 水体效果模拟_第1张图片
添加三个Sorting Layers,用于控制显示的先后顺序,下面的优先级高,显示在前面,水滴的Sorting Layers改为Water。
添加Circle Collider 2D,Rigidbody 2D,Trail Renderer三个组件。
Unity 水体效果模拟_第2张图片
Circle Collider 2D的碰撞体范围改小一些,使得多个水滴接触时有相溶的感觉。
Unity 水体效果模拟_第3张图片
在这里插入图片描述
Rigidbody 2D主要是添加重力效果,新建一个2D物理材质添加到这个Rigidbody 2D的材质上,修改弹性为0.2,使得它落到障碍物上时有一点弹性。
Unity 水体效果模拟_第4张图片
Trail Renderer用于实现水滴掉落时拖尾的效果,修改颜色和水滴一致,调整拖尾线的宽度,前面粗后面细,Time是拖尾存在时间,改短一点即可,材质使用默认材质。
Unity 水体效果模拟_第5张图片
将这个水滴保存为prefab。

水龙头生成水

Unity 水体效果模拟_第6张图片
弄一个简单场景,上面水龙头用来指示出水的地方,下面的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;
        }
    }
}

杯子接水

Unity 水体效果模拟_第7张图片
场景中添加一个杯子,Sorting Layers改为Glass,加上刚体和Edge Colloder 2D,刚体质量改大一些,防止被水冲走,边缘碰撞器由线段组成,可以自由调整成任何形状,首尾不需要相连。
Unity 水体效果模拟_第8张图片
Unity 水体效果模拟_第9张图片
在场景中添加一个圆和菱形,分别添加Circle Collider 2D和Polygon Collider 2D,都添加Rigidbody 2D,圆的mass设为50,菱形的mass设为1,质量大的不容易被推动。

铰链

Unity 水体效果模拟_第10张图片
新建两个Square和一个Circle,分别添加对应的Collider ,置于一个空物体下面,在根节点上添加Rigidbody 2D和Hinge Joint 2D,铰链的Anchor要对齐到圆中心。
Unity 水体效果模拟_第11张图片
铰链可以使两个有刚体的GameObject产生相互作用,发生碰撞时会有旋转的效果。

使用LineRenderer绘制障碍物

Unity 水体效果模拟_第12张图片
原理是在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>();
        }
    }
}

你可能感兴趣的:(物理,unity)