Desarrollando un Mundo en Movimiento

*Este contenido se traduce usando la IA (Beta) y puede contener errores. Para ver esta página en inglés, haz clic en aquí.

Crear movimiento en cualquier entorno dentro de una experiencia ayuda a que se sienta más inmersivo y realista para nuestro mundo, ya sea que eso sea del movimiento del árbol ambiental, de las puertas reactivas de la interacción del jugador o incluso de las cajas que se mueven cuando se chocan contra

Creando la Tormenta

La tormenta pasó por muchas iteraciones antes de que nos decidiéramos por lo que hay en The Mystery of Duvall Drive. Al principio, pensamos en la tormenta como un pilar de obsidiana gigante, y en las siguientes iteraciones consideramos que era un portal gigante al espacio corrupto. Después de experimentar con muchos diferentes tormentas con apariencias y sentimientos únicos para ellos, nos acalmamos con una tormenta con un "ojo" central más pequeño porque:

  • La tormenta debería dar a los jugadores una sensación de impacto de este evento en el mundo , incluida la caída de árboles y el vuelo de escombro.
  • El vórtice giratorio de la nube misma debería dar a los jugadores una vista del portal central sin revelar nada . Esto fomentaría a los jugadores para investigar más cerca para ver qué está sucediendo.
  • El punto de luz más apretado nos permitiría enfocarnos en la composición de la casa, que es tanto el personaje principal como donde se encuentra la mayor parte del juego.

Para hacer que la tormenta se sienta dinámica, agresiva y siempre cambiante dentro de su entorno, ambiente, usamos los siguientes sistemas y características:

  1. TweenService > Para el movimiento de nubes.
  2. Cambios de iluminación - Para crear la nube para crear un rayo.
  3. Rayos - Para la "iluminación volumétrica" y los rayos.
  4. Emisores de partículas > - Para los escombros que vuelan hasta el portal y vuelan alrededor debido al viento.
  5. Animaciones > - Para los árboles que están soplando en el viento.

Añadir nubes con texturas

Mientras que las nubes dinámicas son geniales para las nubes de alta altitud y realistas, necesitábamos algo que se sintiera dramático y que pudiéramos

Úna malla de nube única.
¡Mallas de nube en capas sin sus texturas!

Dado que cada malla de nube necesitaba ser masiva para completamente rodear la casa y transmitir lo enorme que era la tormenta, sabíamos que necesitábamos azulejar la textura que queríamos usar en las mallas individuales para que se repitiera repetidamente en toda la superficie de la malla. Probamos los materiales que hicimos para la nube en estas partes simples, y luego los aplicamos a la voluta!

A diferencia de los emisores de partículas o los rayos, las mallas nos permitían poder rebotar la luz de cada malla, lo que era importante cuando queríamos implementar el rayo y el trueno entre nubes. También modelamos en la torsión para que el rebotar de la luz tuviera la apariencia de profundidad. Esto era importante especialmente en situaciones donde las exigencias de rendimiento de la experiencia hicieron que los niveles de rendimiento de la superficie de nuestro objeto de apariencia se vieran afectados.

Una vez que comenzamos a agregarle iluminación, necesitamos agregar detalles a las meshes para que reaccionen mejor a la iluminación!

Mallas de nube giratorias

Luego de que nos satisfeiriéramos con la apariencia visual general de las nubes, necesitábamos que se pusiera en marcha! Teníamos las formas generales de cada capa de nube en su lugar, ¡pero tomó algo de prueba y error para asegurarnos de que el efecto giratorio se vea bien en la práctica. Inicialmente intentamos usar 约束 para introducir velocidad que conduciría

Queríamos un método fácil de usar para rotar instancias que fueran demasiado lejos para ser interactuables, como las nubes, o demasiado pequeñas o decorativas para ser importantes

Como en muchos casos en la demostración, usamos una etiqueta LocalSpaceRotation para que pudiéramos administrar las instancias afectadas en Studio usando un plugin de etiqueta de instancia. Utilizamos solo un solo LocalScript que manejó todas las instancias etiquetadas usando el plugin de etiqueta de instancia.


local function Init()
for _, obj in CollectionService:GetTagged("LocalSpaceRotation") do
if obj:IsDescendantOf(workspace) then
SetupObj(obj)
end
end
end
CollectionService:GetInstanceAddedSignal("LocalSpaceRotation"):Connect(function(obj)
objInfoQueue[obj] = true
end)
CollectionService:GetInstanceRemovedSignal("LocalSpaceRotation"):Connect(function(obj)
if objInfo[obj] then
objInfo[obj] = nil
if objInfoQueue[obj] then
objInfoQueue[obj] = nil
end
end
end)
Init()

obj

Hemos rotado las instancias en la función Update conectada a heartbeat. Hemos obtenido el padre transform (


local parentTransform
if parentObj:IsA("Model") then
if not parentObj.PrimaryPart then
-- la parte principal aún no puede ser transmitida
continue -- espera a que la parte principal se replica
end
parentTransform = parentObj.PrimaryPart.CFrame
else
parentTransform = parentObj.CFrame
end
curObjInfo.curAngle += dT * curObjInfo.timeToAngle
local rotatedLocalCFrame = curObjInfo.origLocalCFrame * CFrame.Angles( curObjInfo.axisMask.X * curObjInfo.curAngle, curObjInfo.axisMask.Y * curObjInfo.curAngle, curObjInfo.axisMask.Z * curObjInfo.curAngle )
if obj:IsA("Model") then
obj.PrimaryPart.CFrame = parentTransform * rotatedLocalCFrame
else
obj.CFrame = parentTransform * rotatedLocalCFrame
end

Comprobamos para un válido Model.PrimaryPart para ser configurado para manejar la transmisión. Si se llamó una actualización en nuestro objeto mientras un Model.PrimaryPart (que puede apuntar a un malla hija) aún no estaba transmitido, simplemente nos saltaríamos la actualización. El sistema actual es una segunda iteración de la

Diseñando Golpes de Relámpago

Debido a que Studio no ofrece un generador de rayos de la caja, y el sistema de partículas tenía algunas limitaciones que no funcionarían para los golpes de rayo del héroe, tuvimos que ser creativos con una solución para los golpes de rayo del héroe. Decidimos en dos sistemas principales para hacer que los rayos del héroe se vuelvan texturizados por el audio y los efectos de sincronización con el audio y el postprocesado,

Características de las luces

Usamos generalmente una herramienta de secuenciador o cronómetro para impulsar el tiempo de un efecto de perforación de iluminación como este, pero ya que Studio no ofrece esta funcionalidad, decidimos escribir scripts que controlarían el tiempo de un golpe de perforación de iluminación. El scripting de este efecto es bastante simple, pero logra los siguientes objetivos importantes:

  1. Los elementos de los golpes de rayo, como sus texturas, brillo y retrasos, se aleatorizan con cada golpe.
  2. Los cambios de audio y post FX están sincronizados con los golpes FX.
  3. Los jugadores que estén en el área corrupta no podrían ver o escucharles.

Tenemos un Script lado del servidor que calcula varios parámetros y tiempo, los envía a todos los clientes y espera por un tiempo aleatorio:


local function LightningUpdate()
while true do
task.wait(rand:NextNumber(3.0, 10.0))
local info = CreateFXData()
lightningEvent:FireAllClients(info)
end
end

Dentro de CreateFXData, rellenamos la estructura de información para que todos los clientes obtengan los mismos parámetros.

En el lado del cliente ( LightningVFXClient ) comprobamos si este cliente debe ejecutar el FX:


local function LightningFunc(info)
-- no hay FX en el interior
if inVolumesCheckerFunc:Invoke() then
return
end
-- no FX cuando no estés en el mundo "normal"
if not gameStateInfoFunc:Invoke("IsInNormal") then
return
end

Además, ejecutamos la secuencia para establecer texturas, posiciones y brillo, correr a los adolescentes y usar task.wait(number) . Los parámetros aleatorios son de la estructura de información que recibimos del servidor, y algunos números están fijados.


beam.Texture = textures[info.textIdx]
beamPart.Position = Vector3.new(info.center.X + og_center.X, og_center.Y, info.center.Y + og_center.Z)
-- Borrar
beam.Brightness = 10
ppCC.Brightness = maxPPBrightness
ppBloom.Intensity = 1.1
bottom.Position = top.Position
tweenBrightness:Play()
tweenPPBrightness:Play()
tweenPPBrightness:Play()
tweenBottomPos:Play()
tweenBrightness.Completed:Wait()
-- sonido, audio
if audioFolder and audioPart then
if audioFolder.Value and audioPart.Value then
audioUtils.PlayOneShot(audioObj, audioFolder.Value, audioPart.Value)
end
end
task.wait(info.waitTillFlashes)
-- and so on

Para verificar si un jugador está en el interior, usamos una función de ayudante inVolumesCheckerFunc, que va sobre los volúmenes predeterminados que se aproximan a las áreas interiores y verifica si la posición del jugador está dentro de cualquiera de ellos (PointInABox). Podríamos haber usado la detección basada en el toque, pero encontramos que cuando un

Para ver si un jugador está en áreas corruptas, invocamos una función de ayudante gameStateInfoFunc , que comprueba el estado actual del juego. Para jugar un sonido aleatorio desde una carpeta, también usamos una función de ayudante PlayOneShot . Para los rayos de trueno en sí mismos, estos fueron super fáciles de crear en Photoshop; creamos una línea con curva, luego

Utilizando sistemas de emisores de partículas

Los héroes rayos son apoyados por un sistema de partículas que sugiere un rayo distante al crear la impresión de una capa de nubes en el fondo que captura la luz del rayo distante, o iluminación de nube a nube. Logramos este efecto a través de un sistema de partículas muy simple que muestra una nube de cartelera en el período de nube del núcleo principal. El sistema emite un período de partículas de nube aleatoriamente con una curva de transparencia aleatorizada:

Haciendo que los árboles salgan en la viento

Luego de que tuvimos las nubes y el rayo funcionando de la manera que queríamos, necesitamos agregar dos otros componentes principales de una tormenta: el viento y la lluvia. Estos elementos presentaron algunos desafíos, incluida la necesidad de trabajar dentro de los límites actuales de nuestros sistemas de física y efectos especiales. Por ejemplo, hacer que los árboles se muevan con el viento no es

Sabíamos que realmente vender el efecto del viento y la lluvia, necesitábamos que los árboles mismos se herramienta de movimiento. Hay algunas formas en que puedes hacer esto dentro del motor, incluyendo mover partes usando plugins que están disponibles públicamente, usar TweenService o animar modelos directamente. Para nuestros propósitos, las animaciones nos dieron la capacidad

Comenzamos por cáscara varios árboles del Paquete de Modelos de Fin - Recursos Forestales . Ya que estos árboles ya existían, y nuestra experiencia tuvo lugar en el noroeste del Pacífico, nos ahorró algo de tiempo al principio de tener que crear cada aplicación de modeladode árbol.

El paquete Bosque contiene varios tipos de árboles, que pueden ahorrarle tiempo en sus propias experiencias.

Luego de que elegimos nuestros árboles, sabíamos que necesitábamos hidratarlos. Hidratar una malla es el acto de agregar articulaciones (o huesos) a una malla en otra aplicación de modelado 3D, como Blender o Maya, luego aplicar el efecto a esas articulaciones

Sabíamos que queríamos ahorrar tiempo y reutilizar la misma animaciones, por lo que construimos nuestra primera rígida de árbol y asegurarnos de que los nombres compartidos fueran genéricos porque queríamos usar estos nombres en los rígidos para las otras árboles. También sabíamos que necesitáb

Las árboles tienen uniones primarias, secundarias y terciarias para que pudiéramos tener un movimiento creíble al ser soplados por el viento.

Una vez que hayamos creado nuestras articulaciones/huesos, era hora de crear una animación de prueba para moverse por todas las articulaciones y huesos en Studio para ver si se movía de la manera que queríamos. Para hacer esto, tuvimos que importar el árbol en Studio a través de la configuración personalizada

La misma jerarquía dentro de Studio.

¡Después de que estuviéramos contentos con los resultados en ese árbol, era hora de probar la misma animación en un árbol diferente! Ya sabíamos que era la misma animación entre los diferentes modelos de árbol para cada introducirde árbol, ¡así que solo nos aseguramos de que nuestra animación se vea como si fuera lo suficientemente genérica para trabajar entre un alto árbol de Redwood y un robusto árbol de Beechwood!

La animación que importamos en el árbol de Redwood.

Para hacer esto, tomamos el árbol de Beechwood de ese Pack del Bosque y construimos un rig similar, utilizando el mismo nombre exacto para las juntas. Esto fue para que la animación que habíamos importado anteriormente se pudiera aplicar a este árbol también. ¡Dado que las animaciones se basaban en juntas giratorias, no importaba cuán grande, pequeña, alta o ancha era la árbol!

El árbol de Beechwood tiene el mismo nombre exacto para sus articulaciones, solo no es la misma cantidad. Esto está bien ya que el sistema de animación solo aplicará animaciones a esas articulaciones específicas que coinciden con el nombre en él! Por esta razón, ¡podríamos aplicar las mismas animaciones a cualquier cosa que coincida con los nombres de las articulaciones!

Luego de que creamos y pielemos el árbol de Beechwood, podríamos importarlo y aplicar la animación exacta. Esto significaba repetir y editar solo se necesitaba hacer en un archivo, y también se guardó en el rendimiento con menos animaciones cuando se ejecuta la experiencia.

¡Usando el Editor de Animación, podríamos aplicar la misma animación de árbol de rojo a árbol de abedul!

Una vez que tuvimos todos los tipos de árboles que queríamos animar, los hicimos en paquetes para que pudiéramos seguir editando y actualizando mientras jugábamos varias de las animaciones alrededor de la zona principal de la experiencia. ¡Dado que sabíamos que tenían un costo de rendimiento, los usamos con parcimonia alrededor de la casa donde la animación era más valiosa! En el futuro, a medida que esto se vuelve más rentable

Usamos árboles animados inmediatamente alrededor de la casa donde el vórtice era más fuerte y el efecto visual era el más impactante para los jugadores.

Haz Debris de Tormenta

Queríamos que el agua pareciera pesada, y para que la niebla y los residuos soplaran a través de los árboles. Para hacer esto, configuramos algunas partes invisibles para actuar como volúmenes de partículas con hijos emisores de partículas inmediatamente debajo de las grandes nubes de tormenta. Debido al límite de contaminantes en Studio

Usamos varios volúmenes para obtener tanto la cantidad de lluvia, como la cubierta específica de lluvia que queríamos.

The rain particles leveraged a new particle emitter property ParticleEmitter.Squash that allows you to make a particle longer, or squatter. It is particularly useful for rain because it meant we didn't need a large rain textura, just stretch

Un valor de calabaza de 3 comienza a estirar la textura más largo.
Un valor de Squash de 20 estira las partículas mucho más tiempo, pero también necesitamos aumentar el valor de Tamaño.

Para el mal, la niebla y las hojas que están volando, era mucho más simple añadir un solo volumen de mayor tamaño cubriendo menos áreas porque no necesitábamos una tonelada de partículas que corrieran a la vez. Comenzamos por configurar un volumen y obtuvimos la frecuencia de las partículas donde queríamos que estén.

Terminó habiendo algunos volúmenes de partículas, así que no tuvimos partículas entrando a la casa, y porque no sentimos que necesitaban moverse a través de los árboles como la niebla lo hizo.
El volumen de la partícula de niebla era mucho mayor desde que las partículas eran grandes, y no necesitábamos ser tan precisos con la ubicación.

Después de eso, hicimos nuestras luces de plástico y texturas de viento, y establecimos que las partículas se giraran y se moverían de manera más natural, y comenzaran a diferentes velocidades. Esto significó que las partículas de mayor tamaño interactuarían más naturalmente y no parecerían tan como una textura repetitiva, especialmente dado su tamaño.

Partícula de niebla
Partícula de hoja

El resultado fue una gran acción entre los árboles en movimiento, la ventana que se rompe y el rayo para crear el efecto de la tormenta que rodea el ojo central de la tormenta.

Configurando el Ojo de la Tormenta

El ojo de piedra con un núcleo brillante está destinado a dar a los jugadores la primera pista de que hay algo siniestro y arcano que está ocurriendo en la casa que deben explorar más a fondo. Ya que nuestra escena es oscura y el ojo está muy arriba en el cielo, fue importante crear una silueta de piedra falsa creíble, pero no era tan

Configurar la iluminación final en tu escena temprano te ahorrará mucho trabajo. No podrías ver los detalles de la superficie con la iluminación final de nuestra escena, por lo que no era necesario pasar el tiempo poniéndolos allí!

La distancia desde el jugador también significó que podíamos confiar en un mapa normal para los detalles de la superficie del ojo, ¡para que el malla es solo una esfera plana! Esculpimos los detalles en un malla de alta resistencia y horneamos su mapa normal en una esfera mucho más baja, para que pudiéramos obtener todo ese detalle sin el costo de rendimiento masivo.

Escultura de alta poligonalidad
Malla de bajo rendimiento.
La malla de bajo polígono con la información normal de la escultura de polígono alto cocinada en

Con el fin de añadirle un sentimiento sobrenatural a los ojos y de resaltar su presencia, decidimos crear un magma aspecto, looky neón que se filtra a través de sus grietas. Mientras no hay canal emisor para la apariencia de la super

La pintura de vértice en la esfera interior. Creamos un gradiente que era el más ligero alrededor del ojo para dar una mayor sensación de profundidad y de interés visual.

Otro desafío que enfrentamos al crear el ojo fue impuesto por nuestro uso de streaming combinado con la distancia del ojo del jugador. Dado la centralidad de esta est

Pudimos añadir movimiento al ojo y sus anillos gracias a la misma script que usamos para rotar las mallas del mundo. Para un toque final, decidimos añadir una pista a la presencia de otro mundo más

La imagen que usamos para crear una ilusión de un mundo más allá de las nubes. Cuando los jugadores están lejos de algo, ¡una simple imagen puede ser suficiente para crear la ilusión de más profundidad y complejidad en tu escena!

Haciendo que la almacenamiento de Expansión

Una de las cosas más divertidas para producir fueron los espacios corruptos, en los que podíamos subvertir las expectativas de los jugadores de la realidad al cambiar literalmente el espacio alrededor de ellos. Por ejemplo, en el rompecabezas del padre queríamos emular un momento similar a una pesadilla donde no importa lo rápido que ejecutar, el espacio se siente como si fuera más largo. Decidimos hacer una pantry que se expandiría para que se alejara de los jugadores mientras busc

Configuramos esto con un simple movimiento de las paredes, y un diseño inteligente de nuestras habitaciones que aparecería en ambos lados de la panadería. En el estado normal de la habitación, la panadería era un simple pasillo, ¡pero en el espacio corrupto, era realmente mucho más larga con varios alas y una pared falsa!

El estado corrupto de la biblioteca de la cocina.
La pared falsa se aleja de los jugadores.

La pared falsa era un grupo de modelos que nosotros moveríamos de vuelta el momento que los jugadores entraran a un volumen de disparo, que era una parte transparente antes en la pantry que ellos caminarían a través. Ese disparador también se usó en un script similar a los usados en todas nuestras puertas, que llamó el TweenService para mover desde un punto de inicio a otro. Usamos volúmenes de partes para contar la operación de tweening donde

El volumen de la parte activa una pared falsa detrás de ésta para moverse hacia su punto de destino. Se hace visible en esta imagen con un tinte amarillo.
Target_Closed fue una parte de objetivo genérica que usamos en todas nuestras puertas para donde deben rotar. Aquí se repurió para decirle a la pared del pasillo a dónde ir.

Dado que TweenService es un sistema tan general, todo nuestro modelo de datos de pared tenía que contener los mismos componentes. Por ejemplo, la siguiente imagen es un ejemplo de un script de puerta general que llama un sonido definido por un "valor" debajo del aplicación de modelado"Grow_Wall".

Ese mismo script, con algunas modificaciones en el siguiente ejemplo de código, también activó el audio para el movimiento de la almazara. ¡Esto añadió mucho al movimiento!


local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local model = script.Parent
local sound = model.Sound.Value
local trigger = model.Trigger
local left = model.TargetL_Closed
local right = model.TargetR_Closed
local tweenInfo = TweenInfo.new(
model.Speed.Value, --Tiempo/Velocidad de la Puerta
Enum.EasingStyle.Quart, --Estilo de alivio
Enum.EasingDirection.InOut, --EasingDirection
0, --Repetir Cuenta
false, --Reverse true
0 --Retrasar
)
local DoorState = {
["Closed"] = 1,
["Opening"] = 2,
["Open"] = 3,
["Closing"] = 4,
}
local doorState = DoorState.Closed
local playersNear = {}
local tweenL = TweenService:Create(left, tweenInfo, {CFrame = model.TargetL_Open.CFrame})
local tweenR = TweenService:Create(right, tweenInfo, {CFrame = model.TargetR_Open.CFrame})
local tweenLClose = TweenService:Create(left, tweenInfo, {CFrame = model.TargetL_Closed.CFrame})
local tweenRClose = TweenService:Create(right, tweenInfo, {CFrame = model.TargetR_Closed.CFrame})
local function StartOpening()
doorState = DoorState.Opening
sound:Play()
tweenL:Play()
tweenR:Play()
end
local function StartClosing()
doorState = DoorState.Closing
--aplicación de modelado["Puerta"]:Jugar()
tweenLClose:Play()
tweenRClose:Play()
end
local function tweenOpenCompleted(playbackState)
if next(playersNear) == nil then
StartClosing()
else
doorState = DoorState.Open
end
end
local function tweenCloseCompleted(playbackState)
if next(playersNear) ~= nil then
StartOpening()
else
doorState = DoorState.Closed
end
end
tweenL.Completed:Connect(tweenOpenCompleted)
tweenLClose.Completed:Connect(tweenCloseCompleted)
local function touched(otherPart)
if otherPart.Name == "HumanoidRootPart" then
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
--imprimir ("toc")
playersNear[player] = 1
if doorState == DoorState.Closed then
StartOpening()
end
end
end
end

Una vez que tuvimos la pared falsa en movimiento hacia la parte trasera de la habitación, necesitábamos el resto del contenido para moverlo con ella. Para hacer eso, necesitábamos todos los artículos sueltos en el almacén para ser soldados a la pared a medida que se movía. Al usar Contrapesos Con限aciones, pudimos soldar fácilmente todos los objetos en el almacén para moverlos como un solo objeto

Haciendo la Casa del Árbol Corrupta

Studio es un fantástico motor basado en física que puedes usar para crear todo, desde una puerta pendulante hasta una plataforma giratoria. Con nuestra demostración, queríamos usar la física para crear un sentido de realismo en un conjunto de ambientes de otro tipo. Usando solo algunas limitaciones , puedes crear algunas carreras de obstáculos dentro de tus propias experiencias!

Constricciones son un grupo de motores basados ​​físicamente que alinean objetos y limitan comportamientos. Por ejemplo, puede usar una limitación de caña para conectar a los objetos para mantenerlos a una distancia f

El rompecabezas del hijo comenzó con los jugadores en la misma habitación, pero todo estaba al revés.

Una vez que los jugadores llegaron al área principal del rompecabezas, se encontraron con un familiar paisaje en Roblox: un curso de obstáculos. Este particular curso de obstáculos consistió en varias plataformas giratorias y paredes giratorias, junto con "áreas seguras" que progresaban la historia. Nos enfocaremos en los elementos giratorios/giratorios.

La apariencia de mente paralítica ocultó el hecho de que el juego aquí era muy simple.

¿Por qué usamos limitaciones aquí? Porque TweenService o otros métodos no moverían al jugador mientras estuvían de pie. Sin que el objeto se mueva el jugador, alguien podría saltar en una plataforma y girará desde debajo de ellos. En lugar, queríamos que los jugadores navegaran a través de una plataforma giratoria mientras

Podrías ver a tus amigos girar mientras intentas navegar por el obstáculo también.

Para hacer esto, primero tuvimos que usar recursos de nuestro kit actual y agregar cualquier nuevo contenido para un efecto visual. Hicimos algunas paredes y plataformas incompletas con agujeros en ellas para contar la historia de la abuela que construyó la casa del árbol. Debido a que no queríamos crear un montón de piezas de base y piezas de valla únicas, creamos 4 piezas de base y piezas de valla separadas. Esto nos permitió mezclar y comb

Sabíamos que ya que estábamos utilizando restricciones, no podríamos anclar estas mallas porque no se moverían incluso con la presencia de un límite / motor que las impulsaba. La

Ahora era el momento de configurar el comportamiento real de la limitación del eje mismo, y agregar los accesorios que actuarían como la orientación de la parte y la limitación juntos. Colocamos el accesorio giratorio en el Motor_Turn, que las piezas de Bisagraestaban soldadas a, y otro accesorio

Para mantener las plataformas girando a una velocidad constante, entonces configuramos las propiedades HingeConstraint.AngularVelocity, HingeConstraint.MotorMaxAcceleration y HingeConstraint.MotorMaxTorque a valores que permitirían el movimiento y evitarían la interrupción si un jugador se saltaba sobre él.

Attachment0 era básicamente el ancla para la articulación y Attachment1 representaba la articulación misma. Tuvimos la articulación giratoria constante, pero también puedes usar un límite de articulación para las puertas.

Ahora necesitábamos hacer las paredes giratorias. Las paredes necesitaban girar en su centro aparente, y sabíamos que queríamos que pudieran manejar cualquier orientación relativa al resto del nivel. Como las plataformas, construimos estas para que todas las paredes estén desancoradas y soldadas a la Motor_Turn.

Queríamos reutilizar tantas de las mallas de la casa del árbol real para ahorrar ejecución, así que seguimos un camino similar al de las plataformas. Se hicieron varios tipos de pared que podían agarrarse juntos en diferentes combinaciones para alguna variante.

Usamos Texture objetos por encima de SurfaceAppearance objetos para añadir algo de variación a nuestros materiales de base. Text

Puedes ver tanto el comportamiento similar como configurar para la limitación de la articulación, y también cómo usamos objetos Texture .

Una vez que probamos algunas plataformas y paredes giratorias, hicimos varias variaciones y jugamos con su colocación para asegurarnos de que el recorrido de obstáculos fuera desafiante, sorprendente y también limpio donde el jugador necesitaba ir! Tomó algo de ajuste para ambos sus valores y posiciones para que funcionaran bien. Tuvimos varios puntos donde las plataformas y paredes se golpeaban entre sí o los alreded

Si no estás seguro de qué objetos físicos estás golpeando, puedes alternar Colisión de fidelidad desde el widget Opciones de visualización en la esquina superior derecha de la ventana de vista 3D.

A close up view of the 3D viewport with the Visualization Options button indicated in the upper-right corner.
Cuando la visualización de colisión está deshabilitada, puede ver la representación de geometría normal que se muestra en el juego.
Cuando la visualización de colisión está habilitada, puedes ver que las hojas de los árboles no tienen colisiones, por lo que no interferirán con las plataformas giratorias o las paredes.

Como puede ver a continuación, las ventajas/ventanas de la puerta están visibles, pero los detalles más pequeños, como los sub-paneles, no lo son. Esto se debe a que la propiedad CollisionFidelity para las paredes estaba configurada como Caja. No necesitábamos la precisión para estos paneles, por lo que para ahorrar costos de rendimiento, est