Red de conocimiento del abogados - Bufete de abogados - Cómo destruir shuriken en unidad

Cómo destruir shuriken en unidad

En este tutorial, usaremos mecanismos físicos simples para simular un cuerpo de agua dinámico en 2D. Usaremos una mezcla de renderizadores lineales, renderizadores de malla, activadores y partículas para crear este efecto de agua, lo que dará como resultado ondas y salpicaduras de agua que puedes usar en tu próximo juego. La fuente de muestra de Unity se incluye aquí, pero deberías poder realizar operaciones similares usando cualquier motor de juego con los mismos principios.

Configurar el administrador de agua

Usaremos uno de los renderizadores lineales de Unity para renderizar nuestra superficie de agua y usaremos estos nodos para mostrar las ondas continuas.

unity-water-linerenderer(de gamedevelopment)

Seguiremos la posición, velocidad y aceleración de cada nodo. Para esto usaremos matrices. Entonces, las siguientes variables se agregarán al principio de nuestra clase:

float[] posiciones x;

float[] posiciones y;

float[] velocidades;

aceleraciones flotantes[];

Cuerpo de LineRenderer;

El LineRenderer almacenará todos nuestros nodos y delineará nuestro cuerpo de agua. Todavía necesitamos el cuerpo de agua en sí, que se creará utilizando Meshes. Necesitaremos objetos para alojar estas cuadrículas.

GameObject[] meshobjects;

Mesh[] meshes;

También necesitamos colisionadores para que las cosas puedan interactuar con los cuerpos de agua:

GameObject[] colisionadores;

También almacenamos todas las constantes:

const float springconstant = 0.02f;

const float amortiguación = 0.04f;

p>

const float spread = 0.05f;

const float z = -1f;

La z en estas constantes es el desplazamiento Z que configuramos para el cuerpo de agua. Lo etiquetaremos con -1 para que se represente frente a nuestro objeto (Nota: es posible que desee ajustarlo para que esté delante o detrás del objeto según sus necesidades, luego tendrá que usar la coordenada Z para determinar la ubicación del elfo asociado).

A continuación, mantendremos algunos valores:

float baseheight;

float left

float base;

Estas son las dimensiones del agua.

Necesitaremos algunas variables públicas que se puedan configurar en el editor. Primero, usaremos el sistema de partículas para el renderizado:

public GameObject splash:

El siguiente es el material que usaremos para el renderizador lineal:

public Material mat:

Además, el tipo de malla que utilizaremos para la masa de agua principal es el siguiente:

public GameObject watermesh:

Queremos podremos alojar todos estos datos del objeto del juego, usémoslo como administrador para generar los cuerpos de agua en nuestro juego. Para hacer esto, escribiremos la función SpawnWater().

Esta función tomará las entradas del lado izquierdo, margen, vértice y fondo del cuerpo de agua:

public void SpawnWater(flotante Izquierda, flotante Ancho, flotante Superior, flotante Inferior )

{

(Aunque esto pueda parecer contradictorio, favorece un diseño de niveles rápido de izquierda a derecha)

Crear nodos

Ahora descubriremos cuántos nodos necesitamos:

int edgecount = Mathf.RoundToInt(Width) * 5

int nodecount = edgecount 1

Utilizaremos 5 nodos por unidad de ancho para un movimiento suave (puede cambiar esto para equilibrar la eficiencia con la fluidez). De esto obtenemos todos los segmentos de línea y luego necesitamos el nodo 1 al final.

Lo primero que tenemos que hacer es renderizar el cuerpo de agua con el componente LineRenderer:

Body = gameObject.AddComponentlt;LineRenderer;();

Body.material = mat;

Body.material.renderQueue = 1000;

Body.SetVertexCount(nodecount);

Body.SetWidth(0.1f, 0.1 f);

Lo que también tenemos que hacer aquí es seleccionar el material y hacerlo renderizar sobre el agua seleccionando su posición en la cola de renderizado. Establecemos los datos de nodo correctos y establecemos el ancho del segmento en 0,1.

Puedes cambiar este ancho según el grosor del segmento de línea que desees. Quizás hayas notado que SetWidth() requiere dos parámetros, que son el ancho al principio y al final del segmento de línea. Queremos que este ancho sea constante.

Ahora que hemos creado el nodo, inicializaremos todas nuestras variables de nivel superior:

xpositions = new float[nodecount]

ypositions = new; float[nodecount] ;

velocidades = new float[nodecount];

aceleraciones = new float[nodecount];

meshobjects = new GameObject[edgecount];

meshes = nueva malla[edgecount];

colliders = nuevo GameObject[edgecount];

baseheight = superior;

abajo = Bottom;

p>

left = Left;

Ya tenemos todos los arrays que controlarán nuestros datos.

Ahora necesitamos establecer los valores de nuestro array.

Comenzaremos con los nodos:

for (int i = 0; i lt; nodecount; i )

{

ypositions[i] = Top;

xposiciones[i] = Ancho izquierdo * i / recuento de bordes;

aceleraciones[i] = 0

velocidades[i] = 0; >

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

}

Aquí, configuramos todas las posiciones Y anteriores el cuerpo de agua, y luego aumente gradualmente todos los nodos juntos. Como el agua está en calma, nuestros valores de velocidad y aceleración son inicialmente 0.

Completaremos el bucle configurando cada nodo en LineRenderer (Cuerpo) en su posición correcta.

Crear la cuadrícula

Aquí es donde la cosa se vuelve complicada.

Tenemos nuestros segmentos de línea, pero no tenemos el cuerpo de agua en sí. Vamos a utilizar una malla para hacerlo de la siguiente manera:

for (int i = 0; i lt; edgecount; i )

{

mallas [ i] = new Mesh();

Ahora, la malla almacena una serie de variables. La primera variable es bastante simple: contiene todos los vértices (o esquinas).

unity-water-Firstmesh(de gamedevelopment)

Este diagrama muestra cómo se verán los fragmentos de malla necesarios. Los vértices del primer fragmento están etiquetados. Necesitamos 4 vértices en total.

Vector3[] Vértices = nuevo Vector3[4];

Vértices[0] = nuevo Vector3(xposiciones[i], yposiciones[i], z);

Vértices[1] = nuevo Vector3(xposiciones[i 1], yposiciones[i 1], z);

Vértices[2] = nuevo Vector3(xposiciones[i], abajo, z) ;

Vértices[3] = new Vector3(xpositions[i 1], bottom, z);

Ahora como puedes ver, los vértices 0 están en la esquina superior izquierda y 1 está en la esquina superior derecha, 2 es la esquina inferior izquierda y 3 es la esquina inferior derecha. Tendremos que recordarlo más tarde.

El segundo rendimiento requerido para las mallas son los UV. La malla tiene una textura y los UV seleccionan la parte de la textura que queremos capturar. En este caso sólo queremos las texturas para las esquinas superior izquierda, superior derecha, inferior derecha e inferior derecha.

Vector2[] UVs = nuevo Vector2[4];

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

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

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

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

p>

Ahora necesitamos estos datos nuevamente. La malla está formada por triángulos y sabemos que cualquier cuadrilátero está formado por dos triángulos, así que ahora necesitamos decirle a la malla cómo dibuja estos triángulos.

unity-water-Tris (de gamedevelopment)

Mira las esquinas con anotaciones de orden de nodos. El triángulo A conecta los nodos 0, 1 y 3, y el triángulo B conecta los nodos 3, 2 y 1. Entonces queremos hacer una matriz que contenga 6 números enteros:

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

Esto crea nuestro cuadrilátero. Ahora tenemos que establecer los valores de la cuadrícula.

meshes[i].vertices = Vértices;

meshes[i].uv = UVs;

meshes[i].triangles = tris;

meshes[i].uv = UVs;

meshes[i].triangles = tris;

p>

Ahora que tenemos nuestras mallas, No tengo un objeto de juego para representarlos en la escena. Así que los crearemos a partir de la casa prefabricada de malla de agua que incluye un renderizador de malla y un filtro de malla.

meshobjects[i] = Instanciar(watermesh, Vector3.zero, Quaternion.identity) como GameObject;

meshobjects[i].GetComponentlt ().mesh = meshes[; i];

meshobjects[i].transform.parent = transform;

Configuramos la malla para que sea hija del administrador del agua.

Crear efectos de colisión

Ahora también necesitamos nuestro propio colisionador:

colliders[i] = new GameObject();

colliders [i].name = "Trigger";

colliders[i].AddComponentlt;BoxCollider2D;();

colliders[i].transform.parent = transform;

colliders[i].transform.parent = transform;

p>

colliders[i].transform.position = new Vector3(Ancho izquierdo * (i 0.5f) / recuento de bordes, Arriba – 0.5f, 0);

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

colliders[i].GetComponentlt; BoxCollider2D; ().isTrigger = true;

colliders[i].AddComponentlt ;WaterDetector;();

En este punto, creamos nuestros colisionadores cuadrados y les dimos un nombre. se verían un poco más prolijos en la escena, y volverían a representar a cada uno de los hijos del administrador del agua. Establecimos su posición entre los dos nodos, establecimos su tamaño y les agregamos la clase WaterDetector.

Ahora que tenemos nuestra propia malla, necesitamos una función para actualizar a medida que se mueve el agua:

void UpdateMeshes()

{

for (int i = 0; i lt; meshes.Lenh; i )

{

Vector3[] Vértices = nuevo Vector3[4];

Vértices[0] = nuevo Vector3(xposiciones[i], yposiciones[i], z);

Vértices[1] = nuevo Vector3(xposiciones[i 1], yposiciones[i 1], z );

Vértices[2] = nuevo Vector3(xposiciones[i], abajo, z);

Vértices[3] = nuevo Vector3(xposiciones[i 1], abajo, z);

meshes[i].vertices = Vertices;

}

}

Te habrás dado cuenta de que esta función solo utiliza el código que escribimos antes. La única diferencia es que esta vez no necesitamos configurar los UV del triángulo, ya que siguen siendo los mismos.

Nuestra siguiente tarea es hacer que el agua funcione. Usaremos FixUpdate() para ajustarlos incrementalmente.

void FixUpdate()

{

Mecanismo físico de ejecución

Primero, combinaremos la ley de Hooke y el método de Euler para encontrar nuevas coordenadas. , aceleración y velocidad.

La ley de Hooke es F=kx, donde F se refiere a la fuerza generada por el flujo de agua (recuerde, modelaremos la superficie del agua como un flujo de agua), k se refiere a la constante del flujo de agua, y x es el desplazamiento. Nuestro desplazamiento será la coordenada y de cada nodo menos la altura de la base del nodo.

A continuación, agregaremos un factor de amortiguación que sea proporcional a la velocidad de la fuerza para debilitar la fuerza.

for (int i = 0; i lt; xpositions.Lenh; i)

{

fuerza de flotación = constante de resorte * (ypositions[i] – altura base ) velocidades[i]*amortiguación;

aceleraciones[i] = -fuerza;

yposiciones[i] = velocidades[i]; ] = aceleraciones[i];

Body.SetPosition(i, new Vector3(xposiciones[i], yposiciones[i], z));

}

< El método de p>Euler es simple, simplemente agregamos aceleración a la velocidad y velocidad a cada coordenada del cuadro.

Nota: asumí que cada nodo tiene una masa de 1, pero es posible que quieras usar:

aceleraciones[i] = -force/mass;

Ahora crearemos propagación de ondas.

Los siguientes nodos están adaptados del tutorial de Michael Hoffman:

float[] leftDeltas = new float[xpositions.Lenh]

float[] rightDeltas = new float[xpositions.Lenh];

Aquí vamos a crear dos matrices. Para cada nodo, verificaremos la altura del nodo anterior y la altura del nodo actual, y pondremos la diferencia entre los dos en leftDeltas.

Luego, compararemos la altura del nodo siguiente con la altura del nodo actualmente verificado y pondremos la diferencia entre los dos en rightDeltas (multiplicaremos todos los valores por una constante de propagación).

for (int j = 0; j lt; 8; j )

{

for (int i = 0; i lt; xpositions.Lenh; i )

{

if (i ; 0)

{

leftDeltas[i] = spread * (ypositions[i] – yposiciones[i-1]);

velocidades[i - 1] = leftDeltas[i];

}

if (i lt; xposiciones. Lenh – 1)

{

rightDeltas[i] = spread * (ypositions[i] – ypositions[i 1]);

velocidades[i 1 ] = rightDeltas[i];

}

}

}

Cuando recopilamos todos los datos de altura, finalmente podemos viene muy bien. No podemos ver el lado derecho del nodo más a la derecha, ni el lado izquierdo del nodo izquierdo más grande, por lo que las condiciones básicas son i 0 e i lt;

Entonces, tenga en cuenta que incluimos el código completo en un bucle y lo ejecutamos 8 veces. Esto se debe a que queremos ejecutar este proceso en pequeñas y múltiples ráfagas en lugar de una sola operación grande, lo que erosionaría la liquidez.

Agregar salpicaduras de agua

Ahora que tenemos una masa de agua que fluye, ¡el siguiente paso es hacer que salpique!

Para hacer esto, vamos a agregar una función llamada Splash(), que verificará la coordenada X del splash, así como la velocidad de lo que golpee. Hazlo público para que podamos llamarlo más tarde en el colisionador.

public void Splash(float xpos, float speed)

{

Primero, debemos asegurarnos de que las coordenadas específicas estén dentro del rango de nuestro cuerpo de agua. :

{

p>

if (xpos;= xposiciones[0] ?xpos lt;= xposiciones[xposiciones.Lenh-1])

{

Luego ajustaremos xpos, dejaremos que aparezca en una posición relativa al inicio del cuerpo de agua:

xpos -= xpositions[0];

A continuación, encontraremos los nodos que toca.

Podemos calcularlo así:

int index = Mathf.RoundToInt((xpositions.Lenh-1)*(xpos / (xpositions[xpositions.Lenh-1] – xpositions[0])));

p>

Así funciona:

Seleccionamos la posición del chapoteo respecto al borde izquierdo del cuerpo de agua (xpos).

2. Dividimos la posición derecha con respecto al borde izquierdo del cuerpo de agua.

3. Esto nos permite saber dónde está el chapoteo. Por ejemplo, un chapoteo de tres cuartas partes del camino hacia una masa de agua tendría un valor de 0,75.

4. Multiplicaremos este número por el número de aristas, lo que nos dará el nodo al que está más cercano nuestro chapoteo.

velocidades[index] = velocidad;

Ahora necesitamos establecer la velocidad del objeto que golpea la superficie del agua para que sea consistente con la velocidad del nodo, de modo que el nodo ser arrastrado profundamente por el objeto.

Sistema de partículas (de desarrollo del juego)

Nota: puedes cambiar este segmento de línea según tus necesidades. Por ejemplo, puedes sumar su velocidad a la velocidad actual o usar el impulso en lugar de la velocidad y dividirlo por la masa de tu nodo.

Ahora queremos crear un sistema de partículas que creará salpicaduras de agua. Definámoslo antes y llamémoslo "splash". Asegúrese de no confundir esto con Splash().

Primero, necesitamos configurar los parámetros de la salpicadura de agua para ajustar la velocidad del objeto:

vida útil de flotación = 0,93f Mathf.Abs(velocidad)*0.07f ;

splash.GetComponentlt;ParticleSystem;().startSpeed ​​​​= 8 2*Mathf.Pow(Mathf.Abs(velocidad), 0.5f);

splash.GetComponentlt; ParticleSystem;().startSpeed ​​​​= 9 2 * Mathf.Pow(Mathf.Abs(velocity), 0.5f);

splash.GetComponentlt;ParticleSystem;().startLifetime = toda la vida;

Aquí queremos seleccionar partículas, establecer su ciclo de vida para que no desaparezcan tan rápido como golpean el agua y establecer su velocidad en ángulo recto con respecto a su velocidad (agregando una constante para las pequeñas salpicaduras).

Es posible que estés mirando el código y pensando: "¿Por qué necesitamos configurar startSpeed ​​dos veces?". Tienes razón. El problema es que utilizamos una velocidad inicial establecida en "un número aleatorio entre". dos constantes." "Este sistema de partículas (Shuriken). Desafortunadamente, no tenemos mucho acceso programable a Shuriken, por lo que para obtener este comportamiento tenemos que establecer este valor dos veces.