Close
    Search Search

    Tutorial: Creación de un sistema de colocación de muebles

    Página de tutoriales Este artículo es un tutorial intermedio.Todos los tutoriales · Tutoriales de secuencias de comandos

    Esta publicación fue escrita originalmente por EgoMoose en Scripting Helpers. El tutorial original se puede encontrar aquí.

    Una de las solicitudes más comunes que recibo para temas de publicaciones de blog es un sistema de colocación de decoración que ahorre. Me he apartado de este tema en el pasado, ya que no existe una forma única "correcta" de hacerlo. Dicho esto, creo que es un buen ejercicio que deben realizar todos los desarrolladores de juegos y potencialmente colocará un papel en una futura publicación de blog que planeo escribir.



    Además de cambiar las cosas, también me tomaré el tiempo para explicar y usar la programación orientada a objetos (OOP), ya que no solo es mi estilo preferido, sino también algo que Roblox usa para sus scripts principales.

    Muy bien, ¡entremos en ello!

    Programación orientada a objetos

    La programación orientada a objetos se trata de clases de escritura que, en este contexto, es un sinónimo muy elegante de la palabra "plano". Luego, podemos usar estos planos para crear objetos que tengan ciertas propiedades y métodos.

    Si algunas de estas palabras le suenan familiares, bueno, es porque lo son. Los objetos con los que interactúas, como Tutorial: Creación de un sistema de colocación de mueblesPartes, Tutorial: Creación de un sistema de colocación de mueblesHumanoides Tutorial: Creación de un sistema de colocación de mueblesMotor6Ds, y así sucesivamente, son por diseño del paradigma OOP. Estos objetos tienen propiedades y métodos que cuando se combinan definen cómo interactúan con nuestro juego.

    Las propiedades se utilizan para definir las "características" de un objeto. Por ejemplo, una pieza tiene una propiedad llamada Tamaño que, como su nombre indica, define qué tan grande o pequeño es el objeto. A su vez, estas propiedades a menudo juegan un papel en el comportamiento y las acciones asociadas con dicho objeto que se define mediante métodos. Por ejemplo, el método : GetMass () devuelve la masa de la pieza que, entre otras cosas, varía con el tamaño. Por tanto, podemos ver aquí un ejemplo de una conexión clara entre métodos y propiedades.



    Ahora que tenemos parte de la terminología y un ejemplo, me gustaría discutir más a fondo la distinción entre clases y objetos. Una clase define las propiedades y métodos que tendrá un objeto. Por ejemplo, sabemos que todas las partes van a tener una propiedad de posición, así que la definimos en nuestra clase. El valor real de la propiedad de posición variará entre objetos individuales, pero el concepto general de una pieza que conocemos tendrá una propiedad llamada Posición con un Vector3 como su valor. De manera similar, cuando escribimos los métodos de nuestra clase, es posible que no conozcamos los valores literales de cada propiedad, pero como sabemos que esos valores existirán, podemos tratarlos casi como parámetros de función.

    La diferencia entre OOP y un enfoque más funcional para la misma tarea se puede ver en el ejemplo de código a continuación.

    local part = Instance.new ("Part") part.Size = Vector3.new (1, 2, 10) part.Material = Enum.Material.Wood print (part: GetMass ()) - 6.9999998807907 - vs: local función getMass (tamaño, material) - masa = volumen * densidad volumen local = tamaño.x * tamaño.y * tamaño.z densidad local = PhysicalProperties.new (material) .Densidad retorno volumen * densidad final impresión (getMass (part. Tamaño, material de la pieza)) - 6.9999998807907

    Ignorando el hecho de que el método está integrado y, por lo tanto, no tenía que definirse, la única diferencia era que en el enfoque funcional teníamos que insertar las propiedades de la pieza como argumentos manualmente. En el caso del método, no tuvimos que insertar ningún argumento porque Lua sabía que estábamos llamando a un método en un objeto específico y, por lo tanto, podíamos obtener las propiedades necesarias directamente de él. Un método es solo el nombre que le damos a las funciones que se aplican a un objeto específico. Un ejemplo de cómo podría verse esto sería este:



    función Parte: GetMass () volumen local = self.Size.x * self.Size.y * self.Size.z densidad local = PhysicalProperties.new (self.Material) .Density return volume * density end

    Puede notar que el código anterior hace referencia a algo llamado yo y es comprensible que esto parezca surgir de la nada. En Lua, cuando llamas a un método, el primer argumento que se pasa es SIEMPRE el objeto en el que se llamó al método. Al definir un método con la función de forma sintáctica Class: MyMethod (param1, param2,…) el parámetro que representará el objeto se le da forzosamente el nombre self y no debe definirse entre paréntesis como cualquier otro parámetro adicional. Entonces, si ejecuté somePart: GetMass (), entonces el argumento que reemplazaría a self sería somePart.

    Como nota al margen, ya sea por preferencia personal o por estar familiarizado con otros idiomas que usan otra palabra clave que no sea yo como este, algunos programadores pueden preguntarse si hay alguna forma de utilizar un nombre de parámetro diferente. Esto es posible, y el código equivalente sería el siguiente:

    - el argumento self todavía se pasa, pero su nombre de parámetro ya no está oculto y se puede cambiar función Part.GetMass (self) local volume = self.Size.x * self.Size.y * self.Size.z local densidad = PhysicalProperties.new (self.Material) .Density return volume * density end - todavía llamado como un método normal print (somePart: GetMass ())

    Sin embargo, sería mi recomendación personal que no lo haga, ya que puede resultar confuso para los demás desde una perspectiva de legibilidad.

    Muy bien, entonces, ¿cómo escribimos una clase? La última pieza del rompecabezas es algo llamado constructor. Un constructor crea un objeto de la clase y nos lo devuelve con un conjunto de propiedades completadas. Un constructor muy común que creo (?) Todas las clases integradas tienen es .nuevo() pero otros ejemplos pueden ser Vector3.FromNormalId or CFrame.Angles. Una clase puede tener varios constructores y se pueden nombrar casi cualquier cosa. A veces, cuando escribimos estos constructores, tienen parámetros que nos ayudan a completar las propiedades y otras veces no. Depende completamente de usted como programador y depende de lo que sea la clase.



    Veamos cómo el personal de Roblox podría escribir un constructor en Lua y desglosaremos las partes a partir de ahí. Aquí hay un ejemplo de cómo se puede copiar el Vector3 constructor de clases.

    local Vector3 = {} Vector3 .__ index = Vector3 - función constructora Vector3.new (x, y, z) local self = setmetatable ({}, Vector3) self.x = x o 0 self.y = yo 0 self. z = zo 0 devuelve fin propio

    Para algunos de ustedes esto podría tener perfecto sentido y para algunos de ustedes puede que no. La diferencia clave entre los que entienden y los que no deben estar familiarizados con las metatablas. Este es un gran tema en sí mismo, pero afortunadamente, solo necesitamos comprender un aspecto del metamétodo __index para comprender este código.

    La mejor explicación "simplificada" que he escuchado de las meta-tablas es "eventos, pero para tablas" y esto es particularmente aplicable al metamétodo __index. El metamétodo __index se "activa" cuando una clave que no existe en una tabla se indexa, es decir, se lee, no se escribe.

    t local = {gatos = 10; perros = 32; } gatos locales = t.cats - no disparado b / c existe valor para la clave perros locales = t.dogs - no disparado b / c existe valor para la clave t.turtles = 60 - no disparado porque estamos escribiendo print (t.hamsters) - el valor b / c disparado no existe para la clave

    Normalmente, los metamétodos "dispararán" una función y el metamétodo __index también puede funcionar de esta manera. Sin embargo, si en lugar de establecer una función en el metamétodo __index, establece otra tabla, cuando el metamétodo __index se "activa", trata el proceso como tal:

    • La tabla se indexó con key => ¿La clave se corresponde con un valor nulo en la tabla?
      • Sí => ¿La clave se corresponde con un valor no nulo en la tabla del metamétodo __index?
        • Sí => Devuelve ese valor
        • No => Devolver nulo

    Esto es bastante útil para nosotros ya que nos permite establecer valores predeterminados para las claves y no tener que redefinirnos y repetirnos constantemente al hacer copias. En el caso del código anterior, lo usamos de manera que self, la tabla que regresamos de nuestro constructor, tendrá acceso a todos los constructores y métodos que adjuntamos a la tabla Vector3.

    Digamos que agregamos el siguiente método al código anterior, luego creamos un objeto y ejecutamos el método en él:

    función Vector3: Magnitud () local x, y, z = self.x, self.y, self.z return math.sqrt (x * x + y * y + z * z) end local v = Vector3.new (1 , 2, 3) imprimir (v: Magnitud ())

    El proceso se trata como tal:

    • v se indexó con la tecla Magnitud => ¿La clave corresponde a un valor nulo en v?
      • Sí => ¿La clave se corresponde con un valor no nulo en Vector3?
        • Sí => Devuelve ese valor (el método de magnitud)

    Por lo tanto, se llama al método: Magnitude () en v, que tiene valores reales para las propiedades x, y y z y, como tal, obtenemos el resultado correspondiente.

    Hay mucho más que decir sobre la programación orientada a objetos y lo que he explicado apenas ha arañado la superficie. Algunos otros lenguajes te obligan a usar OOP y tienen un conjunto de características mucho más rico en comparación con Lua. Si desea explorar más la POO en Lua, le recomiendo que lea la siguiente publicación en los foros de desarrollo.

    Dicho todo esto, la pregunta que aún no he respondido es "¿Por qué usar OOP?". Mi respuesta: personalmente lo disfruto, ya que me obliga a organizar mi código de una manera modular y reutilizable que se puede combinar para una variedad de tareas complejas. Dicho esto, hay aspectos positivos y negativos para todo, así que use lo que funcione para usted.

    Añade un comentario de Tutorial: Creación de un sistema de colocación de muebles
    ¡Comentario enviado con éxito! Lo revisaremos en las próximas horas.