¿Qué estás buscando?
Games

Imprevisiblemente divertido: El valor de la aleatoriedad en el diseño de juegos

EDUARDO ORIZ / UNITY TECHNOLOGIESSenior Content Marketing Manager
Apr 11, 2022|10 minutos
Imprevisiblemente divertido: El valor de la aleatoriedad en el diseño de juegos
Para tu comodidad, tradujimos esta página mediante traducción automática. No podemos garantizar la precisión ni la confiabilidad del contenido traducido. Si tienes alguna duda sobre la precisión del contenido traducido, consulta la versión oficial en inglés de la página web.

Aprende a inyectar aleatoriedad en tu juego para mantener a los jugadores enganchados y ansiosos por la siguiente escena. Este es el segundo post de Christo Nobbs en su serie sobre el diseño de sistemas, ampliando sus contribuciones a El libro de jugadas del diseñador de juegos de Unity. Echa un vistazo al libro electrónico para obtener más información sobre cómo crear prototipos, crear y probar la jugabilidad en Unity.

En su anterior entrada del blog, Christo se refirió a cómo los diseñadores pueden crear sistemas en sus juegos que den lugar a una jugabilidad intrigante e inesperada. En este post profundiza con ejemplos sobre cómo configurar la aleatorización.

Imagen con fondo morado claro de la portada del Ebook GamePlay & Design
La aleatorización, junto con otros temas relacionados, se tratan en el libro electrónico gratuito The Unity game designer playbook.
Deja un rastro de pistas visuales para tus jugadores

Puede incitar a los jugadores a explorar más a fondo los sistemas de su mundo de juego e idear experiencias únicas para ellos, con indicaciones visuales. El post anterior, Sistemas que crean ecosistemas: Diseño de juego emergente, esbozó un espacio sandbox en el que todo está hecho y construido de madera con la posibilidad de propagación impredecible del fuego. Basémonos en este ejemplo y demos a los jugadores la posibilidad de talar árboles con un hacha.

Supongamos que el paisaje en el que se encuentran los jugadores es llano. No saben en qué dirección caerá el árbol cuando lo talen. ¿Y si algunos árboles estuvieran muertos pero aún en pie? Podrían caer en cualquier momento. Un elemento imprevisible como éste en el juego sobresaltará a los jugadores e intensificará su ambiente de juego.

Puedes añadir cualquier número de señales visuales para mostrar a los jugadores que los árboles que caen son peligrosos en este mundo y mantenerlos alerta. Las pistas ayudarán a los jugadores a distinguir entre los árboles más peligrosos y los que están sanos y son menos peligrosos. Tendrán que elegir cómo sopesar los riesgos: ¿Sería más sensato buscar leña en los árboles que ya han caído y evitar que te hieran los árboles muertos que están a punto de caer?

Como diseñador, asegúrate de determinar dónde se producen estas reacciones sistémicas en cadena y de diseñarlas para que sirvan de apoyo cuando los jugadores las desencadenen, como la caída impredecible de árboles, su incendio y, por tanto, la propagación de un caos delicioso.

Generar sorpresa con Unity.Engine.Random

La clase de scripting Random en Unity es una clase estática que le proporciona enfoques para generar datos aleatorios en un juego. Esta clase tiene el mismo nombre que la clase System.Random de .NET Framework y sirve a un propósito similar, pero difiere en algunos aspectos clave - uno de ellos es que es entre un 20% y un 40% más rápida que System.Random.

A continuación se muestran las propiedades estáticas y métodos disponibles con la clase Random:

Propiedades estáticas

  • insideUnitCircle: Devuelve un punto aleatorio dentro o sobre un círculo de radio 1,0 (sólo lectura)
  • insideUnitSphere: Devuelve un punto aleatorio dentro o sobre una esfera de radio 1.0 (sólo lectura)
  • onUnitSphere: Devuelve un punto aleatorio en la superficie de una esfera con radio 1.0 (sólo lectura)
  • Rotación: Devuelve una rotación aleatoria (sólo lectura)
  • rotaciónUniforme: Devuelve una rotación aleatoria con distribución uniforme (sólo lectura)
  • estado: Obtiene o establece el estado interno completo del generador de números aleatorios
  • valor: Devuelve un flotador aleatorio dentro de [0.0..1.0] (el rango es inclusivo) (sólo lectura)

Métodos estáticos

  • ColorHSV: Genera un color aleatorio a partir de los rangos HSV y alfa
  • InitState: Inicializa el estado del generador de números aleatorios con una semilla
  • Alcance: Devuelve un flotador aleatorio dentro de [minInclusive..maxInclusive] (el rango es inclusivo)

La entrada anterior del blog exploró el papel de las palancas de diseño y el uso de ScriptableObjects para almacenar esos valores. Usted puede reemplazar esos valores con rangos apropiadamente diseñados usando Random.Range de Unity, que devuelve un flotador aleatorio dentro de [minInclusive..maxInclusive] (el rango es inclusivo). Cualquier valor flotante dado entre ellos, incluyendo tanto minInclusive como maxInclusive, aparecerá aproximadamente una vez cada 10 millones de muestras aleatorias.

Con este enfoque puede extraer un valor del intervalo establecido para su resultado. Tendrás que probar varios rangos para encontrar el que funcione para tus objetivos de juego, pero, de nuevo, asegúrate de que diseñas para el rango definido que has establecido.

Imagen de un robot blanco vigilando los incendios de ramas de árboles en un bosque
Infórmate sobre los sistemas modulares en la primera entrada del blog de nuestra serie para diseñadores de juegos.
Una aventura aleatoria en el bosque

La aleatoriedad mejora la inmersión. Por ejemplo, supongamos que cada árbol tiene una salud fija de 100 y que cada golpe de hacha le resta 25 puntos de salud. Esta tarea pronto se volverá predecible y, por tanto, aburrida. Incluso si le das a los árboles un rango de salud de 76 a 100, cualquier árbol estará a cuatro golpes de caer. Pero probar con un rango menor de, digamos, 75 a 76 proporciona una mayor variedad de resultados de juego, ya que un árbol tardará entre tres y cuatro golpes en caer.

Otra forma de hacer interesante este escenario es indicar los cambios de salud mediante señales visuales claras en lugar de barras de salud. De este modo, el jugador aprenderá, a través del juego, cuántos golpes de hacha son necesarios para que caiga un árbol. Las señales visuales añaden cierta imprevisibilidad limitada que puede equilibrarse y ajustarse al objetivo de juego. Utilizar la clase Aleatorio en lugar de un valor fijo permite transformar una tarea monótona en una tarea divertida.

Para ampliar este ejemplo, podrías elegir eliminar un valor aleatorio entre 15 y 25 puntos de salud por cada golpe de hacha. Esto hace que los jugadores no puedan predecir fácilmente cuántos golpes necesitarán para talar un árbol. Tendrán que basarse más en pistas visuales para saber cuándo va a caer un árbol; pistas como el tamaño de los trozos que vuelan del árbol o las grietas que se forman en el tronco, las ramas que caen, los efectos sonoros, etc.

No sabrán con exactitud cuándo caerá cada árbol, pero con el tiempo, a medida que los jugadores talen más árboles, podrán hacer conjeturas y, en última instancia, mejorar sus posibilidades de supervivencia.

Captura de pantalla de los ajustes de Daño por Impacto Aleatorio en el Inspector
En el libro de jugadas del diseñador de juegos de Unity, encontrarás ejemplos de cómo crear palancas y visualizar campos en el Inspector. En esta imagen, la Intensidad de Daño es el valor aleatorio que afecta al Valor de Daño final - se muestra con el atributo Rango.

La aleatoriedad pretende ofrecer a los jugadores retos impredecibles que les empujen a calcular el riesgo y gestionar el resultado.

Veamos algunos ejemplos más de cómo utilizar la clase Random.

Ponderación de aleatorios en un juego de cartas

Imagina un juego de cartas con un enemigo IA que juega su carta basándose únicamente en el movimiento del jugador. Este evento se convertiría rápidamente en predecible sin aleatoriedad, ya que devolvería el mismo resultado cada vez.

Incluso fijar la probabilidad en el 50% es una aleatorización demasiado simple y pronto resultaría obvia para el jugador. En su lugar, intenta añadir capas de aleatoriedad basadas en las acciones de los jugadores. De este modo se crearán sistemas intrincados que ofrecerán algo más dinámico que elegir entre dos cartas de una reserva, o si se elige o no esa carta en lugar de una de las muchas de la reserva existente.

Puedes añadir niveles de dificultad a la mesa de juego haciendo que el enemigo favorezca ciertas cartas sobre otras; decisiones basadas en un valor que se le haya dado, o en lo completa que sea su composición antes de atacar, por ejemplo. Una carta de jefe puede multiplicar su capacidad de daño cuando se juega con otras cartas de poder, por lo que el enemigo espera a tener en la mano una cierta variedad de cartas de poder para aumentar la dificultad para el jugador. Se puede añadir "peso" a dicha composición aumentando o disminuyendo la probabilidad de que la carta de jefe se juegue con otras cartas de poder determinadas.

Imagen del juego de cartas Heartstone
Hearthstone, de Blizzard Entertainment, sigue siendo uno de los juegos de cartas más populares. Se lanzó en 2014 y está hecho con Unity.
Ruido Perlin

Puedes utilizar la aleatoriedad de diferentes formas para tus juegos. El ruido Perlin, por ejemplo, tiene cualidades naturales y genera ruido de gradiente a partir de una semilla. Prueba a utilizarlo en Cinemachine para crear una sensación de cámara más orgánica para las cámaras de seguimiento en tercera persona.

Captura de pantalla del algoritmo de ruido Perlin en Cinemachine
Aproveche el algoritmo de ruido Perlin de Cinemachine para crear un movimiento de cámara más orgánico.

Para probar el ruido Perlin, echa un vistazo a los paquetes Starter Assets - Third-person Character Controller, o Gaia en la Tienda de Activos, junto con la documentación sobre cómo utilizar Mathf.PerlinNoise.

Imagen de la textura muestreada con ruido Perlin (puntos blancos y negros difuminados)
Vea esta textura muestreada con ruido Perlin. En lugar de valores totalmente aleatorios en cada punto, el ruido consiste en "ondas" con valores que aumentan y disminuyen gradualmente a lo largo del patrón. El ruido puede utilizarse como base para efectos de textura y animación, generar mapas de altura del terreno, etc.
Atacar a los agentes de IA

En una entrevista, Chris Butcher, uno de los principales ingenieros de Halo 2 de Bungie Studios, habló de la IA del juego: "El objetivo no es crear algo impredecible. Lo que quieres es una inteligencia artificial que sea coherente para que el jugador pueda darle determinadas entradas. El jugador puede hacer cosas y esperar que la IA reaccione de una determinada manera".

Imagen de un robot verde de pie en medio de un terreno lowpoly fuera de edificios cúbicos
Estos activos están disponibles a través del pack Starter Assets - Third-person Character Controller de la Tienda de Activos.

Teniendo esto en cuenta, ¿cómo deberías configurar los agentes de la IA para que tu juego siga pareciendo impredecible y vivo?

Una forma de experimentar con esto es combinar Starter Assets con herramientas de IA de la Asset Store, como A* Pathfinding Project Pro, una herramienta que permite mover un agente de IA a un punto determinado.

Una vez que el agente de la IA se mueve hacia el jugador, éste espera ser atacado. ¿Y si, en cambio, se inicia una conversación? ¿Y si añadimos más PNJ que se muevan y se integren en el espacio para darle más vida? Estos PNJs podrían elegir puntos que se les dieran linealmente, uno a uno, o mejor aún, elegir puntos lógicos basados en un conjunto de reglas usando la clase Aleatorio.

Digamos que tienes un agente IA que dispara al jugador con un débil arco y flecha. Por desgracia para el agente de la IA, tiene que estar a cierta distancia del personaje porque el alcance máximo para disparar es de 10 metros. La IA se coloca frente al jugador, a 10 metros de distancia, y dispara. No es una configuración emocionante ni ideal, sobre todo si añades un segundo tirador que lucha por la misma posición en el NavMesh.

Para un escenario más interesante, elige una zona en la que el enemigo deba acercarse al jugador. Hazlo usando Random.insideUnitCircle, pasando el resultado vector2 a un vector3 para los ejes X y Z, y luego aprovecha RandomRange para ambos para obtener un área con un radio mínimo y máximo alrededor del jugador.

Captura de pantalla del script utilizado para que un agente de IA seleccione un punto de ataque cerca del personaje principal.
El script utilizado para que un agente de IA seleccione un punto de ataque cerca del personaje principal.
captura de pantalla de las palancas de diseño en el Inspector
Las palancas de diseño permiten ajustar con precisión el comportamiento de la IA desde el Inspector.

El agente de la IA debe elegir un punto dentro de un rango aceptable alrededor del jugador y disparar, en lugar de acercarse al jugador. Para añadir más emoción al juego con una codificación mínima, aplica esto a todos los agentes de la IA para que ataquen al jugador desde múltiples ángulos. La acción de la IA es predecible hasta cierto punto porque sabes que los agentes necesitan estar a cierta distancia para atacar, pero no puedes predecir los ángulos desde los que atacarán.

imagen de un espacio lowpoly con una cruz blanca sobre un círculo gris y verde
El punto rojo simboliza dónde irá el agente enemigo.

Puedes ampliar este ejemplo dando a tus agentes de IA la capacidad de atacar en un combate cuerpo a cuerpo. Utiliza el mismo punto aleatorio del jugador con un radio más cerrado. De este modo, los agentes de la IA eligen entre un conjunto de ataques cuando llega el momento de atacar.

El jugador sabe que puede ser atacado por una formación cuerpo a cuerpo, pero ¿desde qué dirección? ¿Habría un ataque por encima del brazo? ¿O un amplio giro de izquierda a derecha? Tendrían que leer la telegrafía de la animación para determinar lo que se les viene encima.

Editor de Unity

Este escenario puede volverse complejo si tienes varios PNJ enemigos destinados a atacar al jugador al mismo tiempo. Pero si nos fijamos en Far Cry 2 de Ubisoft, por ejemplo, el jugador no es atacado por todos los enemigos al mismo tiempo. Diferentes enemigos atacarán en diferentes momentos, de forma aleatoria. Puedes aprender más sobre este ejemplo y otros escenarios de IA en este vídeo de Game Maker's Toolkit.

Si se intentara reproducir de forma realista en el juego los resultados de las acciones realizadas en el mundo real, se necesitarían ecuaciones complejas y polifacéticas o un agente ML bien entrenado. Al final, todo puede parecer fuera de lugar, llevar mucho tiempo y gastos técnicos de implementación, y seguir siendo difícil de equilibrar y controlar con comprensión, si la arquitectura es deficiente.

Sin embargo, al utilizar la clase Random de Unity, los diseñadores de juegos pueden crear resultados creíbles para sus escenas con un control estricto de los niveles de emoción, en menos tiempo del que tardarían de otro modo. La aleatoriedad, por supuesto, no siempre es apropiada. La previsibilidad sigue siendo esencial. Pero si se colocan en las zonas adecuadas, en los momentos más oportunos, pueden ofrecer experiencias únicas a sus jugadores que les hagan querer jugar una y otra vez.