赞
踩
当角色进入水中时,水会根据角色下降的速度大小受力,进而让水面下降
当角色跳出水中时,水会根据角色出水的速度大小受力,水面会有少数上升
角色再水中移动时,会对周围水面产生影响,类似出水时的受力
水面会根据受力,上下波动,并且随着时间波动衰减,类似橡皮筋
水面波动会向周围扩散,并衰减,最终趋于平静
水面的绘制使用MeshRender 和Mesh Filter绘制
使用教程可以参考
1.绘制水上面部分的顶点和下面部分的顶点
- //顶点,length是水面长度,quality是顶点数量
- float interval_length = length/quality;
- //分开设置数组前一部分是上顶点,后一半是下顶点
- //上面顶点
- for (int i = 0; i < quality; i++) {
- vertices[i] = new Vector3(i * interval_length, width, 0);
- }
- //下面顶点
- for (int i = quality; i < 2*quality; i++) {
- vertices[i] = new Vector3((i-quality) * interval_length, 0, 0);
- }
2.如果看了上面mesh的博客,就知道需要把这些点连接成一个顺时针的三角形,这样才能再正面显示出来
从下顶点遍历,绘制三角形,每个下顶点顺时针绘制两个三角形
- Vector2[] uvs = new Vector2[vertices.Length];
- for (int i = 0; i < vertices.Length; i++) {
- uvs[i] = new Vector2(vertices[i].x/length,vertices[i].y/width);
- }
- //绘制水
- public void DrawWater(float length,float width,int quality) {
- //材质
- gameObject.GetComponent<MeshRenderer>().material = mat;
- //顶点
- float interval_length = length/quality;
- //分开设置数组前一部分是上顶点,后一半是下顶点
- //上面顶点
- for (int i = 0; i < quality; i++) {
- vertices[i] = new Vector3(i * interval_length, width, 0);
- }
- //下面顶点
- for (int i = quality; i < 2*quality; i++) {
- vertices[i] = new Vector3((i-quality) * interval_length, 0, 0);
- }
- //设置三角形
- int anglescount = (quality*2-2)*3;
- triangles = new int[anglescount];
-
- int current=0;
- for (int i = quality; i < 2 * quality - 1; i++) {
-
- triangles[current++] = i;
- triangles[current++] = i-quality;
- triangles[current++] = i-quality+1;
-
- triangles[current++] = i;
- triangles[current++] = i - quality + 1;
- triangles[current++] = i + 1;
- }
-
- Vector2[] uvs = new Vector2[vertices.Length];
- for (int i = 0; i < vertices.Length; i++) {
- uvs[i] = new Vector2(vertices[i].x/length,vertices[i].y/width);
- }
-
- Mesh mesh = GetComponent<MeshFilter>().mesh;
- mesh.Clear();
- mesh.RecalculateNormals();
- mesh.RecalculateTangents();
- mesh.vertices = vertices;
- mesh.triangles = triangles;
- mesh.uv = uvs;
- }

因为水面是由很多个顶点组成,所以只需要对水面的顶点进行变换,在重新绘制顶点即可模拟水面的变化。
在这里每个顶点移动只在Y轴(上下)进行偏移,不进行左右移动
所以只需要模拟每个顶点的运动规律就可以实现水面动画
1.因为只对水面部分的顶点进行模拟,设置一个水面顶点变化速度的数组
2.当物体落入水中,跳出水中,在水中移动时,根据距离和力的大小赋予数组初速度。
3.然后每帧让顶点位置+对应变化速度,进行顶点偏移
4.速度数组会时刻收到与速度相反的力,可以理解为水面张力,目的就是让水面恢复平静,所以在设置每个位置对应的加速度,与速度方向相反
5.速度受加速度和阻力的影响持续衰减,最终减少为0
6.扩散,从左遍历,每一个顶点变换速度+上相邻右边顶点的差值,再从右边遍历,每一个顶点变换速度+上相邻左边顶点的差值
- /****************************************************
- 文件:WaterMeshRender.cs
- 作者:别离或雪
- 邮箱: 2946952974@qq.com
- 日期:#CreateTime#
- 功能:水面模拟
- *****************************************************/
-
- using UnityEngine;
-
- [RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
- public class WaterMeshRender : MonoBehaviour
- {
-
- [Header("水")]
- public float length;//水面长度
- public float width;//水深
- public int quality;//顶点数量
-
- public Material mat;//材质
- [Header("组件")]
- private BoxCollider2D boxCollider;
- private Bounds bounds;
- Vector3[] vertices;//顶点
- int[] triangles;//三角形
-
- float[] leftdetails;//向左扩散速度
- float[] rightdetails;//向右扩散速度
- float[] velocitys;//velocityY方向的速度
- float[] accelerated;//加速度
-
- public float damping=0.2f;//速度对恢复波动的影响力
- public float heighspeed=2f;//高度对恢复波动的影响力
- public float spread;//传播衰减值
-
- //public float MaxOffsetTop=1;//水面最大高度
- //public float MaxOffsetBottom=1;//水面最低深度
-
- public float collForce=0.1f;//物体落水力影响值
- private void Start() {
- vertices = new Vector3[quality*2];
- velocitys = new float[quality];
- accelerated = new float[quality * 2];
- leftdetails = new float[quality];
- rightdetails = new float[quality];
- DrawWater(length, width, quality);
- boxCollider = GetComponent<BoxCollider2D>();
- boxCollider.offset = new Vector2(4.8f, 0.74f);
- boxCollider.size = new Vector2(length, width);
- bounds = boxCollider.bounds;
-
- //可以自己波动范围限制
- //MaxOffsetTop = width+2;
- //MaxOffsetBottom = 0.5f;
-
- MeshRenderer meshRenderer = transform.GetComponent<MeshRenderer>();
- meshRenderer.sortingOrder = 1;
- }
- private void Update() {
- //持续绘制
- //物理
- for (int i = 0; i < quality; i++) {
- //加速度的力
- float force =heighspeed*(vertices[i].y-width)+velocitys[i]*damping;
- //顶点变换
- vertices[i].y +=velocitys[i]
- //这里可以设置力的最大最小范围
- ;
- accelerated[i] = -force;
- //速度收到加速度和阻力衰减(这个数值自行设置,这里我设置速度大小的1/5)
- velocitys[i] += accelerated[i]-velocitys[i]/5;
- }
- //水扩散和衰减
- for (int i = 0; i < quality; i++) {
- if (i > 0) {
- leftdetails[i] = spread * (vertices[i].y - vertices[i - 1].y);
- velocitys[i - 1] += leftdetails[i];
- }
- if (i < quality - 1) {
- rightdetails[i] = spread * (vertices[i].y - vertices[i + 1].y);
- velocitys[i + 1] += rightdetails[i];
- }
- }
- //重新绘制顶点
- ReDraw(vertices);
- }
- //绘制水
- public void DrawWater(float length,float width,int quality) {
- //材质
- gameObject.GetComponent<MeshRenderer>().material = mat;
- //顶点
- float interval_length = length/quality;
- //分开设置数组前一部分是上顶点,后一半是下顶点
- //上面顶点
- for (int i = 0; i < quality; i++) {
- vertices[i] = new Vector3(i * interval_length, width, 0);
- }
- //下面顶点
- for (int i = quality; i < 2*quality; i++) {
- vertices[i] = new Vector3((i-quality) * interval_length, 0, 0);
- }
- //设置三角形
- int anglescount = (quality*2-2)*3;
- triangles = new int[anglescount];
-
- int current=0;
- for (int i = quality; i < 2 * quality - 1; i++) {
-
- triangles[current++] = i;
- triangles[current++] = i-quality;
- triangles[current++] = i-quality+1;
-
- triangles[current++] = i;
- triangles[current++] = i - quality + 1;
- triangles[current++] = i + 1;
- }
- //对应坐标UV设置
- Vector2[] uvs = new Vector2[vertices.Length];
- for (int i = 0; i < vertices.Length; i++) {
- uvs[i] = new Vector2(vertices[i].x/length,vertices[i].y/width);
- }
-
- Mesh mesh = GetComponent<MeshFilter>().mesh;
- mesh.Clear();
- mesh.RecalculateNormals();
- mesh.RecalculateTangents();
- mesh.vertices = vertices;
- mesh.triangles = triangles;
- mesh.uv = uvs;
- }
- public void ReDraw(Vector3[] currentvertices) {
- //设置三角形
- int anglescount = (quality * 2 - 2) * 3;
- triangles = new int[anglescount];
-
- int current = 0;
- for (int i = quality; i < 2 * quality - 1; i++) {
-
- triangles[current++] = i;
- triangles[current++] = i - quality;
- triangles[current++] = i - quality + 1;
-
- triangles[current++] = i;
- triangles[current++] = i - quality + 1;
- triangles[current++] = i + 1;
- }
- Vector2[] uvs = new Vector2[vertices.Length];
- for (int i = 0; i < vertices.Length; i++) {
- uvs[i] = new Vector2(vertices[i].x / length, Mathf.Max(vertices[i].y / width,1));
- }
-
- Mesh mesh = GetComponent<MeshFilter>().mesh;
- mesh.Clear();
- mesh.RecalculateNormals();
- mesh.RecalculateTangents();
- mesh.vertices = currentvertices;
- mesh.triangles = triangles;
- mesh.uv = uvs;
- }
-
- private void OnTriggerEnter2D(Collider2D col) {
- Vector2 velocity = col.GetComponent<Rigidbody2D>().velocity;
- FallIn(col, velocity.y*collForce);
- Debug.Log("Enter Water");
- }
- private void OnTriggerStay2D(Collider2D col) {
- Vector2 velocity = col.GetComponent<Rigidbody2D>().velocity;
- //持续呆在水中力为上方向,这里设置速度的绝对值
- StayWater(col, Mathf.Abs(velocity.x) * collForce);
- }
- private void OnTriggerExit2D(Collider2D col) {
- Vector2 velocity = col.GetComponent<Rigidbody2D>().velocity;
- JumpOut(col,velocity.y*collForce);
- Debug.Log("Out Water");
- }
- //落入水中
- private void FallIn(Collider2D col,float force) {
- //原点,因为绘制的顶点并不是世界坐标,需要加上原点的位置才是世界坐标
- Vector2 originalpos = transform.position;
- //计算物体包围盒宽度
- float radius = col.bounds.max.x - col.bounds.min.x;
- //计算中心点
- Vector2 center = new Vector2(col.bounds.center.x,width);
- //计算每个受力的大小,赋予初始速度
- for (int i = 0; i < quality; i++) {
- //只计算X距离
- float dis = Vector2.Distance(new Vector2(originalpos.x+vertices[i].x,width), center);
- if (dis < radius) {
- velocitys[i] = force * (radius - dis) / radius;
- }
- }
- }
- //跃出水面
- private void JumpOut(Collider2D col,float force) {
- Vector2 originalpos = transform.position;
- float radius = col.bounds.max.x - col.bounds.min.x;
- Vector2 center = new Vector2(col.bounds.center.x, width);
- for (int i = 0; i < quality; i++) {
- float dis = Vector2.Distance(new Vector2(originalpos.x + vertices[i].x, width), center);
- if (dis < radius) {
- velocitys[i] = force * (radius - dis) / radius;
- }
- }
- }
- //水中移动
- private void StayWater(Collider2D col,float force) {
- //水中移动影响当前速度,不是赋予初始速度
- Vector2 originalpos = transform.position;
- float radius = col.bounds.max.x - col.bounds.min.x;
- Vector2 center = new Vector2(col.bounds.center.x, width);
- for (int i = 0; i < quality; i++) {
- float dis = Vector2.Distance(new Vector2(originalpos.x + vertices[i].x, width), center);
- if (dis < radius) {
- velocitys[i] += (force) * dis /5;
- }
- }
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。