李成笔记网

专注域名、站长SEO知识分享与实战技巧

在Unity中创建2D动态水体效果 unity自己怎么制作水

在中创建2D动态水体效果

在本教程中,通过简单的物理学模拟动态2D的水体。我们将混合使用线条渲染器,网格渲染器,触发器和粒子系统来实现效果。最终效果还配有浪花和飞溅,为下一个游戏做好准备。一个Unity(Unity3D)的实例已经实现了,但是你应该能在任何游戏引擎中使用相同的原理来实现。

相关文章

  • Make a Splash With Dynamic 2D Water Effects

  • How to Create a Custom 2D Physics Engine: The Basics and Impulse Resolution

  • Adding Turbulence to a Particle System

最终结果

这就是我们最终要的东西。你需要Unity浏览器插件试试。

https://ssl-webplayer.unity3d.com/download_webplayer-3.x/3.0/co/.application?installer=https%3A%2F%2Fssl-webplayer.unity3d.com%2Fdownload_webplayer-3.x%2FUnityWebPlayer.exe

建立水体管理

在Michael Hoffman的教程中讲述了如何通过溅射模拟水体表面。

我们打算让水体使用统一的渲染器,使用如此之多的节点作为连续的波浪出现。

我们需要跟踪每个节点的位置,速度和加速度。要做到这一点就要使用数组。所以在类的顶部要添加这些变量:

float[] xpositions;

float[] ypositions;

float[] velocities;

float[] accelerations;

LineRenderer Body;

LineRenderer将存储所有节点和水体轮廓,即使仍然需要水体本身;

我们将会使用网格进行创建,同时需要对象来持有这些网格。

GameObject[] meshobjects;

Mesh[] meshes;

我们也需要碰撞器以便与水体进行交互:

GameObject[] colliders;

我们将会存储所有的常量:

const float springconstant = 0.02f;

const float damping = 0.04f;

const float spread = 0.05f;

const float z = -1f;

这些常量与 Michael discussed所说的一样,通过一个参数z-即水体在z方向的偏移。我们将会使用-1以便展示对象。(你可能想要改变它,这都取决于想要出现在前面还是后面;需要通过坐标z来决定精灵放置在哪。)

下一步,我们将要持有一些变量:

Float baseheight;

float left;

float bottom;

这些都是水体的面积。

我们需要在编辑器中设置一些公共变量。首先,将粒子系统用在溅射上:

public GameObject splash:

接下来,我们将对线性渲染器使用材质(例如想要复用酸、熔岩、化学材料或者别的):

public Material mat:

另外,这种网格是水的主体:

public GameObject watermesh:

这些都是组合式的,都包含在the source files中。

public void SpawnWater(float Left, float Width, float Top, float Bottom)

我们需要一个游戏对象来保存所有这些数据,作为管理者,同时产生游戏世界中的水体。要做到这一点,我们将编写一个SpawnWater()函数。

这个函数的输入有水体的左边宽度,顶部和底部。

(尽管这似乎不一致,但在构建时展现了快速的设计水准)。

创建节点

现在要找出我们需要多少个节点:

int edgecount = Mathf.RoundToInt(Width) * 5;

int nodecount = edgecount + 1;

我们需要五个单位宽度达到光滑的运动要求。(你可以改变平滑的效率。)这里有所有行,我们需要额外节点 + 1 。

首先要做的是决定水体使用的 LineRenderer 组件:

Body = gameObject.AddComponent<LineRenderer>();

Body.material = mat;

Body.material.renderQueue = 1000;

Body.SetVertexCount(nodecount);

Body.SetWidth(0.1f, 0.1f);

还要做的就是选择材质,通过选择在渲染队列中的位置设置它在水面之上。我们已经设置正确的节点数,线的宽度设置为0.1。

可以根据你想要的线段来改变需求。你可能已经注意到,SetWidth()方法接受两个参数,这些都是在开始和结束的行宽。我们想要宽度不变。

既然我们已经创建了所有节点,那就先进行初始化操作:

xpositions = new float[nodecount];

ypositions = new float[nodecount];

velocities = new float[nodecount];

accelerations = new float[nodecount];

meshobjects = new GameObject[edgecount];

meshes = new Mesh[edgecount];

colliders = new GameObject[edgecount];

baseheight = Top;

bottom = Bottom;

left = Left;

现在我们有了各个数组及其数据。

现在设置了数组实际的值,然后将以以下节点开始:

for (int i = 0; i < nodecount; i++)

{

ypositions = Top;

xpositions = Left + Width * i / edgecount;

accelerations = 0;

velocities = 0;

Body.SetPosition(i, new Vector3(xpositions, ypositions, z));

}

这里,我们设置了所有水体y轴的坐标,然后逐步添加所有节点。最初水体的速度和加速度为零。

通过设置每个节点LineRenderer (Body)的正确位置完成循环。

创建网格

这里开始变得棘手了。

我们已经有了线条,但是没有水体本身。我们可以使用网格,这里要先创建这些:

for (int i = 0; i < edgecount; i++)

{

meshes = new Mesh();

现在,网格存储了一堆变量。第一个变量是非常简单的:它包含所有的顶点(或角)。

图中显示了我们希望网格的样子。第一段,顶点高亮。我们总共想要四个。

Vector3[] Vertices = new Vector3[4];

Vertices[0] = new Vector3(xpositions, ypositions, z);

Vertices[1] = new Vector3(xpositions[i + 1], ypositions[i + 1], z);

Vertices[2] = new Vector3(xpositions, bottom, z);

Vertices[3] = new Vector3(xpositions[i+1], bottom, z);

现在,可以在这里看到左上的顶点是0,1是右上角的,2是左下角的,3是右上角的。我们需要记住它们。

第二个网格属性需要的是UVs。网格需要纹理, UVs选择了我们需要的部分。这种情况下,我们只需要纹理的左上角,右上角,左下角和右下角。

Vector2[] UVs = new Vector2[4];

UVs[0] = new Vector2(0, 1);

UVs[1] = new Vector2(1, 1);

UVs[2] = new Vector2(0, 0);

UVs[3] = new Vector2(1, 0);

现在我们需要之前的那些数字。网格是由三角形组成的,我们知道任何四边形可以由两个三角形组成,所以需要告知网格需要绘制哪些三角形。

看看顺序标记节点的角。三角形A连接了节点0,1和3;

三角形B连接了节点3,2和0。因此我们想要创建一个六个整数的数组,如下所示:

int[] tris = new int[6] { 0, 1, 3, 3, 2, 0 };

这里创建了四边形,现在可以设值了。

meshes.vertices = Vertices;

meshes.uv = UVs;

meshes.triangles = tris;

现在有了网格,但没有游戏对象渲染场景。所以我们要从watermesh预制中进行创建,这包含了一个网格渲染器和网格过滤器。

meshobjects = Instantiate(watermesh,Vector3.zero,Quaternion.identity) as GameObject;

meshobjects.GetComponent<MeshFilter>().mesh = meshes;

meshobjects.transform.parent = transform;

我们设置了网格和水体管理器的子集,从而将事物整合。

创建碰撞

现在加入碰撞器:

colliders[i] = new GameObject();

colliders.name = "Trigger";

colliders.AddComponent<BoxCollider2D>();

colliders.transform.parent = transform;

colliders.transform.position = new Vector3(Left + Width * (i + 0.5f) / edgecount, Top - 0.5f, 0);

colliders.transform.localScale = new Vector3(Width / edgecount, 1, 1);

colliders.GetComponent<BoxCollider2D>().isTrigger = true;

colliders.AddComponent<WaterDetector>();

这里创建了盒体碰撞器,进行命名将会让代码更加清爽,子集同理。我们设置了中间节点,同时设置了大小,加入了一个 WaterDetector 类。

现在有了网格,我们需要一个函数来更新水体的移动:

void UpdateMeshes()

{

for (int i = 0; i < meshes.Length; i++)

{

Vector3[] Vertices = new Vector3[4];

Vertices[0] = new Vector3(xpositions, ypositions, z);

Vertices[1] = new Vector3(xpositions[i+1], ypositions[i+1], z);

Vertices[2] = new Vector3(xpositions, bottom, z);

Vertices[3] = new Vector3(xpositions[i+1], bottom, z);

meshes.vertices = Vertices;

}

}

您可能注意到这个函数只使用我们之前写的代码。唯一不同的是这次不需要设置tris和UVs,因为这些是保持不变的。

我们的下一个任务是使水体开始工作。我们将使用 FixedUpdate() 以增量的方式修改它们。

void FixedUpdate()

原文标题:Creating Dynamic 2D Water Effects in Unity

原文链接:https://gamedevelopment.tutsplus.com/tutorials/creating-dynamic--water-effects-in-unity--gamedev-14143

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言