百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

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

bigegpt 2024-08-10 12:15 2 浏览

在中创建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

相关推荐

5分钟搭建公网https网页文件服务器,免费权威TLS证书

请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习前言本文主要讲解如何快速搭建一个https网页文件服务器,并免费申请权威机构颁发的tls证...

nginx负载均衡配置(nginx负载均衡配置两个程序副本)

Nginx是什么没有听过Nginx?那么一定听过它的“同行”Apache吧!Nginx同Apache一样都是一种WEB服务器。基于REST架构风格,以统一资源描述符(UniformResources...

19《Nginx 入门教程》Nginx综合实践

今天我们将基于Nginx完成两个比较有用的场景,但是用到的Nginx的配置非常简单。内部Yum源搭建内部Pip源搭建1.实验环境ceph1centos7.6内网ip:172.16....

Nginx性能调优与优化指南(nginx优化配置大全)

Nginx性能调优需要结合服务器硬件资源、业务场景和负载特征进行针对性优化。以下是一些关键优化方向和具体配置示例:一、Nginx配置优化1.进程与连接数优化nginxworker_process...

C++后端开发必须彻底搞懂Nginx,从原理到实战(高级篇)

本文为Nginx实操高级篇。通过配置Nginx配置文件,实现正向代理、反向代理、负载均衡、Nginx缓存、动静分离和高可用Nginx6种功能,并对Nginx的原理作进一步的解析。当需...

【Nginx】史上最全的Nginx配置详解

Nginx服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里,http块又包括http全局块和server块。Nginx是非常重要的负载均衡中间件,被广泛应用于大型...

【Nginx】Nginx 4种常见配置实例(nginx基本配置与参数说明)

本文主要介绍nginx4种常见的配置实例。Nginx实现反向代理;Nginx实现负载均衡;Nginx实现动静分离;Nginx实现高可用集群;Nginx4种常见配置实例如下:一、Nginx反向代理配...

使用nginx+allure管理自动化测试报告

allure在自动化测试中经常用来生成漂亮的报告,但是网上及官网上给出的例子都仅仅是针对单个测试用例文件的形式介绍的,实际使用中,自动化测试往往需要包含不止一个产品或项目,本文介绍如何使用nginx+...

nginx配置文件详解(nginx配置文件详解高清版)

Nginx是一个强大的免费开源的HTTP服务器和反向代理服务器。在Web开发项目中,nginx常用作为静态文件服务器处理静态文件,并负责将动态请求转发至应用服务器(如Django,Flask,et...

SpringCloud Eureka-服务注册与发现

1.Eureka介绍1.1学习Eureka前的说明目前主流的服务注册&发现的组件是Nacos,但是Eureka作为老牌经典的服务注册&发现技术还是有必要学习一下,原因:(1)一些早期的分布式微服...

微服务 Spring Cloud 实战 Eureka+Gateway+Feign+Hystrix

前言我所在项目组刚接到一个微服务改造需求,技术选型为SpringCloud,具体需求是把部分项目使用SpringCloud技术进行重构。本篇文章中介绍了Eureka、Gateway、Fe...

深度剖析 Spring Cloud Eureka 底层实现原理

你作为一名互联网大厂后端技术开发人员,在构建分布式系统时,是不是常常为服务的注册与发现而头疼?你是否好奇,像SpringCloudEureka这样被广泛使用的组件,它的底层实现原理到底是怎样的...

热爱生活,喜欢折腾。(很热爱生活)

原文是stackoverflow的一则高票回答,原文链接可能之前也有人翻译过,但是刚好自己也有疑惑,所以搬运一下,个人水平有限所以可能翻译存在误差,欢迎指正(如侵删)。尽管classmethod和st...

GDB调试的高级技巧(详细描述gdb调试程序的全过程)

GDB是我们平时调试c/c++程序的利器,查起复杂的bug问题,比打印大法要好得多,但是也不得不说,gdb在默认情况下用起来并不是很好用,最近学习到几个高级点的技巧,分享下:一美化打印先上个例子...

Arduino 实例(二十三)Arduino 给Python 编译器发送信息

1首先Python需要安装Pyserial库,在命令提示符中输入pipintallpyserial若是遇到提示‘pip‘不是内部或外部命令,也不是可运行的程序或批处理文件,则需要设置环境变...