< Volver 

Blocks Simulator: Build

2021-04-11

La herramienta de construir tiene una ventana de ajustes con vista previa en 3D y un bloque fantasma que se ajusta a la cuadrícula contra la cara que apuntas. Este artículo cubre el almacén de atributos detrás de la ventana, la vista previa, la regla de ajuste y por qué queda al ras en unas caras y se mete en otras, y cómo crea el bloque el servidor.

LuauRobloxGameplayUINetworking
Ir a vista rápida

Un bloque fantasma y una ventana llena de ajustes.

La ventana Build Settings: forma, tipo de bloque, 28 materiales, vista previa en 3D, transparencia, reflectancia y las opciones Anchored y Protected

Resumen. La herramienta de construir (Q) abre Build Settings, donde eliges el tipo del bloque (bloque, cuña, esquina o truss), su forma (bloque, cilindro o esfera, para los bloques normales), uno de 28 materiales, su transparencia y su reflectancia, y si queda anclado y protegido. Una vista previa en 3D gira con los ajustes actuales. En el mundo, un bloque fantasma translúcido sigue al mouse, ajustado a una cuadrícula y apoyado contra la cara que apuntas, y al hacer clic se pone uno de verdad. Este artículo cubre cómo las secciones de la ventana comparten su estado a través de los atributos de un BindableFunction, cómo la vista previa cambia la clase de su parte, la regla de ajuste del fantasma y una asimetría que tiene, y lo que hace el servidor para crear el bloque.

1. El problema

Poner un bloque en una cuadrícula necesita tres cosas: una posición bajo el mouse, ajustada; un desplazamiento para que el bloque nuevo quede apoyado contra la cara en vez de hundido hasta la mitad; y las propiedades que eligió el jugador. La ventana que guarda esas propiedades está dividida en secciones que son scripts separados, así que también necesitan un lugar donde compartir su estado.

2. Los ajustes como un almacén pequeño

new.exe tiene un BindableFunction llamado DataCollector.cmd, con un BindableFunction llamado GetData.cmd y un BindableEvent llamado Signal.js adentro. El almacén son los atributos del propio DataCollector.cmd. Cada sección de la ventana escribe con collector:Invoke(property, value) y lee con getter:Invoke(property). El script que responde, DataCatch, guarda el valor como atributo, se lo aplica a la parte de la vista previa y dispara Signal.js para que el bloque fantasma se reconstruya. El estado inicial también vive en esos atributos: tipo Part, material SmoothPlastic, forma Block, anclado y protegido activados, sin transparencia ni reflectancia.

Lo que lo mantiene corto es que los atributos se llaman igual que las propiedades de la parte, así que aplicarle un cambio a la vista previa es

ok, err = pcall(function()
	prepart[property] = value;
end)

y un fallo imprime el código 0xA6 por el mismo canal de logs que usa el servidor. Cambiar el tipo es la excepción, porque un Part no se puede convertir en un WedgePart. En ese caso DataCatch destruye la parte de la vista previa, clona una plantilla de la clase nueva y le copia todos los atributos, saltándose Protected y Type, que no son propiedades, y Shape salvo que la clase nueva sea Part, la única de las cuatro que la tiene. Mientras el tipo no sea Part, la sección de forma se cubre con una sombra y fuerza Block.

La transparencia y la reflectancia son sliders. Mientras se mantiene el mouse presionado en uno, en cada frame calcula

t=clamp⁡(x−x0w, 0, 1)

a partir de la x del mouse y del borde izquierdo x0 y el ancho w de la barra, mueve la perilla a t y escribe t en el almacén.

Cada botón de material tiene un ViewportFrame con una parte pequeña girando en ese material, y un toggle las tiñe con un color que le queda a cada una. Al pasar el mouse por un material aparece su nombre en un tooltip que sigue al mouse y se ajusta al texto con TextService:GetTextSize.

3. La vista previa

La vista previa es un ViewportFrame cuya cámara tiene un campo de visión de 10°. Un campo tan cerrado se comporta como un teleobjetivo: la parte tiene que estar lejos de la cámara para caber en el cuadro, y la perspectiva casi desaparece, así que el bloque se ve parecido a un dibujo técnico. La rueda del mouse hace zoom moviendo el campo de visión entre 7° y 15°. En cada frame la parte gira alrededor de su eje vertical

Δθ=velocidad1.5⋅π180⋅60Δt

donde la velocidad es el campo Rotation Speed, de 0 a 3, y Δt es la duración del frame. El 60Δt hace que la velocidad sea la misma con cualquier tasa de frames, como si cada frame durara un sesentavo de segundo. Antes de girar, pone en cero la orientación X y Z de la parte, para que no se salga de la vertical. La casilla Isometric detiene el giro e inclina la parte a (−45°,0°,0°). Eso es una vista inclinada y no una isométrica, que necesitaría un giro de 45° y una elevación de arctan⁡(1/2)≈35.26°.

4. El fantasma y la cuadrícula

Mientras la herramienta está activa, cada frame ubica el fantasma así:

local pos = mouse.Hit.Position
local round = {
	x = Run.GetSnapAmount(pos.X);
	y = Run.GetSnapAmount(pos.Y);
	z = Run.GetSnapAmount(pos.Z)
}
vector = Vector3.new(round.x,round.y,round.z) + Run.GetSurfaceVector(mouse.TargetSurface);
block.Position = vector

con mouse.TargetFilter apuntando al fantasma, para que el rayo del mouse lo atraviese en vez de caer en las caras del propio fantasma. GetSnapAmount ajusta cada coordenada del punto de impacto con i⌈x/i⌉, donde i es el incremento de la herramienta de mover, leído de Transform.exe, así que cambiar el incremento de mover también cambia la cuadrícula de construir. Luego suma la normal de la cara, Vector3.FromNormalId(mouse.TargetSurface), que mide 1 stud. Los bloques miden 2 studs por lado, así que 1 stud es medio bloque, y el centro del fantasma queda a medio bloque de la cara, con su cara cercana sobre la superficie. Por componente, con 𝐡 el punto de impacto y nˆ la normal de la cara:

𝐜=i⌈𝐡i⌉+nˆ

Sobre la baseplate, cuya cara superior está en y=0, el centro va a y=1 y el bloque ocupa de 0 a 2.

4.1 Huecos y solapamientos

A lo largo de la normal de la cara, ceil siempre redondea hacia +∞, apunte hacia donde apunte la cara. Eso hace que dos tipos de caras se comporten distinto cuando no están sobre la cuadrícula. Toma una cara perpendicular a X en x=L y un incremento i. La coordenada ajustada cae en algún punto de [L,L+i).

  • Si la cara apunta a +X, el objetivo está del lado −X, el centro del fantasma queda en i⌈L/i⌉+1 y su cara cercana cae en [L,L+i): al ras, o dejando un hueco menor que un incremento.
  • Si la cara apunta a −X, el objetivo está del lado +X, el centro queda en i⌈L/i⌉−1 y su cara cercana también cae en [L,L+i), que ahora está dentro del objetivo: al ras, o metida en él menos de un incremento.

Mientras todos los bloques sigan sobre la cuadrícula, L es múltiplo de i, el techo no cambia nada y los dos casos quedan al ras. Con los bloques de 2 studs por defecto y un incremento de 0.5, así es como está el juego normalmente. Cuando un bloque se escala o se mueve fuera de la cuadrícula, construir sobre su cara superior, derecha o trasera deja un hueco pequeño, y construir sobre su cara inferior, izquierda o frontal mete el bloque nuevo dentro de él. Ajustar solo las dos coordenadas a lo largo de la cara, y sacar la tercera de la posición de la cara más medio bloque, dejaría los dos casos al ras.

Hay un segundo problema. TargetSurface es una cara en los ejes del propio objetivo, pero FromNormalId se suma en los ejes del mundo, así que sobre un objetivo rotado el desplazamiento apunta para otro lado. El fantasma, por su parte, siempre sale alineado con el mundo.

5. Poner el bloque

Al hacer clic, la herramienta lee todos los ajustes del almacén y llama al servidor:

Gun:InvokeServer(vector, floatingXD, prot, material, shape, Type, trans, refl)

El remote se llama Gun en el cliente y PlaceRep en el servidor, y floatingXD es si el bloque va anclado. El servidor guarda ocho plantillas en ReplicatedStorage.Replicable, los cuatro tipos, cada uno anclado y sin anclar, nombrados con un sufijo: Partyes, Partnot, WedgePartyes y así. Elige una juntando el tipo con "yes" o "not", la clona en la carpeta .reg del jugador, le pone la posición, la forma (dentro de un pcall, porque solo Part la tiene), el material, la transparencia y la reflectancia, y le corta las últimas tres letras al nombre. Buscar por sufijo funciona como una lista blanca por accidente: un tipo que no sea uno de los cuatro no coincide con ninguna plantilla, el handler falla y no se clona nada. Las plantillas fijan el tamaño en 2 studs y el color en gris, así que todos los bloques empiezan iguales y las otras herramientas siguen desde ahí.

Si Protected está activado, el servidor envuelve el bloque con Solar3.New y guarda su dueño. Como explica el resumen general, eso cuesta una petición web por bloque y nada lo lee nunca.

6. La primera versión

La herramienta de construir que escribí como juank se llamaba Holograma. Era un Tool que creaba el fantasma al equiparse y lo destruía al desequiparse, y ya usaba la misma regla, math.ceil por coordenada más un vector unitario elegido según la cara. Escribía los seis vectores a mano con un if por cara, donde la reescritura usa FromNormalId, y su cuadrícula estaba fija en 1 stud. Al hacer clic le mandaba al servidor la posición ajustada y el vector de la cara por separado. El comentario al principio del script dice “script hecho por juank, poniendo a prueba conocimientos del mouse”.

7. Limitaciones

  • La asimetría entre caras y el desplazamiento equivocado sobre objetivos rotados, de la sección 4.1.
  • Cada escritura en el almacén dispara Signal.js, y cada una destruye y reconstruye el fantasma. Mientras arrastras el slider de transparencia, eso pasa en cada frame.
  • La cuadrícula es el incremento de la herramienta de mover, que se cambia en otra ventana.
  • El servidor acepta cualquier posición y no limita qué tan rápido se ponen bloques.

8. Lo que me dejó

Nombrar los ajustes como las propiedades es lo que conservaría. El almacén y la vista previa hablan en nombres de propiedades, así que un ajuste nuevo solo necesita su sección en la ventana y un argumento más en el servidor. La regla de ajuste viene de la primera versión y sobrevivió a la reescritura porque es correcta en el caso común, cuando todo está sobre la cuadrícula. Hacer las cuentas con números fue lo que me mostró los casos en los que no lo es.

Este texto de Mastedore. Todos los derechos reservados.