2011-06-14 12 views
7

Vengo del desarrollo tradicional de juegos que usa los principios de OOP y de lo que he visto se puede imitar usando LUA una vez que se sabe lo que se está haciendo. En algunas de las publicaciones de códigos, descubrí cómo se puede usar la clase directora y crear archivos que tengan una función nueva(), etc.Corona LUA y OOP Design

Lo que estoy buscando es una forma de administrar mis armas. Tengo un jugador y un oponente y preferiría tener una clase de armas, digamos weaponCanon. Lo que he hecho es:

-- private vars here 
local power 
local canonSprite 
local whatever 

local someFunction = function() 
... 
end 

-- Private stuff here 
local weaponCanon = {} 

weaponCanon.fire = function(atX, atY) 
... 
end 

weaponCanon.reset = function() 
... 
end 

return weaponCanon 

Luego, en mi código de nivel yo simplemente:

local weaponCanon = require("weaponCanon") 
weaponCanon.fire(100, 100) 

Esto funciona muy bien y me permite utilizar una y la mentalidad "privado" "público" al codificar mi armas. El problema es que si quiero que el jugador y el oponente para una Canon:

local playerWeapon = require("weaponCanon") 
local opponentWeapon = require("weaponCanon") 

Esto simplemente devuelve el mismo objeto en lugar de una nueva instancia de ese objeto. Así que solo tengo un arma Caan en la ubicación oponente del arma. Esto es obviamente lo que quiero/necesito ahora.

Nuestro juego tiene muchas armas y sería bueno tener solo una versión de cada archivo con un ajuste que nos diga si es el arma del oponente o el arma del jugador. La alternativa es copiar cada archivo y crear un weaponPlayerCanon y un weaponOpponentCanon pero me estremezco ante la idea de modificar un archivo y tener que cambiar más de 2 archivos cada vez.

¿Cómo puedo hacer que devuelva una instancia y cuál es la estructura del archivo LUA para hacerlo?

Gracias o cualquier y toda la ayuda

-d

+0

Estoy muy al tanto de: http://lua-users.org/wiki/LuaModuleFunctionCritiqued y aquí es donde obtuve mi diseño, pero en realidad no resuelve mi problema a menos que pase por alto algo ... –

+0

Creo que lo que se ha perdido es que necesita datos y lógica.Por lo tanto, necesita una nueva función para proporcionar la "tabla" que contenga la configuración de su arma que luego proporcionaría como parámetro para la función de fuego, por lo que disminuye el valor de potencia de la mesa pasada por la pistola. El Capítulo 15 de PIL debería orientarte en la dirección correcta http://www.lua.org/pil/15.html –

+0

Lo que has hecho aquí me dice algo que estaba planeando probar eventualmente, así que gracias por salvarme el problema. – jhocking

Respuesta

5

supongo que están tratando de modelar una clase con el archivo de origen. Esto significa que también debe tener una función para crear una nueva instancia de esa clase a menos que desee que compartan todo su estado.

Algo a lo largo de las líneas (no probado):

local WeaponCannon = {} 
WeaponCannon.__index = WeaponCannon 
function WeaponCannon:new() 
    return setmetatable({}, self) 
end 

function WeaponCannon:fire(x, y) 
    -- Do something via the self reference and arguments (x, y) 
end 

return WeaponCannon 

Y en su código de llamada (también no probado):

require('WeaponCannon') 
local playerWeapon = WeaponCannon:new() 
local opponentWeapon = WeaponCannon:new() 
+0

gracias por todas las respuestas, creo que todas fueron excelentes soluciones ... esta me acaba de llevar a lo que quería hacer. –

+0

Oye, en este ejemplo, ¿cómo tendrías variables/funciones privadas? ¿O eso no existe a menos que use una biblioteca? –

+0

Si son funciones de utilidad que no tienen estado, simplemente colócalas en el archivo fuente y no las devuelvas. Cualquier variable local que no expongas en la tabla también es privada. Como ejemplo 'function f() local a = 5; return {getA = function() return a end, setA = function (new_a) a = new_a end} end'. La variable local 'a' solo se expone a través de' getA' y 'setA'. – ponzao

0

No hay objetos aquí- que acaba de tener un montón de mundial datos. Realmente necesitas hacer instancias.

function NewWeapon(arg) 
    return { 
     fire = function(self, atX, atY) 
      print(self.var) 
     end, 
     var = arg, 
    } 
end 

NewWeapon(3):fire(1, 2) 
NewWeapon(7):fire(3, 5) 
7

Si más adelante se inicia necesidad de herencia (es decir, LaserCannon es una subclase de Arma) que probablemente tendrá que utilizar metatablas más profundamente.

Hay muchas bibliotecas que le permitirán hacer "oop en la parte superior de Lua". Se puede ver una muy buena lista aquí:

http://lua-users.org/wiki/ObjectOrientedProgramming

Soy el autor de middleclass.Con mi lib, que tendría que hacer algo como esto:

local Weapon = class('Weapon') 

function Weapon:initialize(a,b,c) 
    self.x,self.y,self.z = a,b,c 
end 

function Weapon:fire(x,y) 
... 
end 

LaserCannon sería fácil de implementar - que acaba de pasar un segundo parámetro a la clase:

local LaserCannon = class('LaserCannon', Weapon) 

function LaserCannon:initialize(a,b,c,d) 
    self.w = d 
    Weapon.initialize(self, a,b,c) -- superclass' constructor 
end 

function LaserCannon:foo() 
... 
end 

Usted puede utilizar de esta manera:

require 'middleclass' -- so you can use "class" 
LaserCannon = require 'laser_cannon' 

local playerWeapon = LaserCannon:new() -- a laser 
local opponentWeapon = Weapon:new() -- a regular generic weapon 

opponentWeapon:fire(100,200) -- typical use 
playerWeapon:fire(100, 200) -- LaserCannon inherits fire from Weapon 
playerWeapon:foo() -- LaserCannon-exclusive 

Esto es con la clase media, que es la que yo prefiero, ya que la hice. Otras bibliotecas en la página que mencioné antes ofrecen características similares.

+0

He estado mirando su biblioteca y me gusta mucho. Puedo cambiar a eso pronto. He estado haciendo algunas pruebas pero me encontré con un gran problema. Lo estoy usando para Corona SDK y me encontré con una situación en la que necesito establecer una función onCollision para ser llamada. Normalmente yo sólo lo haría: self.canonBall.collision = onWeaponCollision self.canonBall: addEventListener ("colisión", self.canonBall) Sin embargo, onWeaponCollision no funcionará. ¿Hay alguna manera de hacer esto con tu biblioteca? Lea más al: http://stackoverflow.com/questions/6363671/middleclass-problems –

+1

respondió a esa pregunta :) – kikito

1

Aunque crea una nueva tabla para el objeto de arma, no crea nuevas variables. Cualquier variable declarada en la parte superior de su módulo así son esencialmente variables estáticas (es decir, variables compartidas por todas las instancias de una clase). Para crear variables que son exclusivas de ese objeto, necesita crearlas en la tabla, algo así como:

weaponCannon = {} 
weaponCannon.power = 10 

Y de todos modos sólo se crea un objeto una vez, se necesita una función "constructor" que crea las tablas:

function new() 
    local weaponCannon = {} 
    weaponCannon.power = 10 
end 


por cierto, dos otras cosas que aren Está directamente relacionado con su respuesta, pero puede ser una modificación muy útil para su código. En primer lugar, el uso de dos puntos en lugar de un período para llamar a funciones en un método le permitirá utilizar la palabra clave "auto" dentro del método, algo así como:

function weaponCannon:fire() 
    --this is only a test 
    print(self.power) 
end 

continuación

local playerWeapon = require("weaponCanon") 
playerWeapon:fire() 

En segundo lugar, en realidad se puede utilizar objetos de visualización en forma de tablas, en lugar de tener que crear una mesa vacía y luego pegar el objeto de visualización en esa mesa vacía:

weaponCannon = display.newImage("cannon.png") 
weaponCannon.power = 10 

tenga en cuenta que no se puede establecer el meta-t capaz si haces esto sin embargo. Encuentro que este enfoque parece más lógico y prefiero no usar meta-tablas, pero esa es su decisión.

0

Me gusta la respuesta de ponzao. Sin embargo cambiaría a:

local WeaponCannon = {} 

function WeaponCannon:new() 
    local instance = {} 
    setmetatable(instance, {__index = WeaponCannon}) 
    -- setup your new instance here 
    return instance 
end 

function WeaponCannon:fire(x, y) 
    -- Do something via the self reference and arguments (x, y) 
end 

return WeaponCannon 

Y en su código de llamada:

local WeaponCanon = require('WeaponCannon') 
local playerWeapon = WeaponCannon:new() 
local opponentWeapon = WeaponCannon:new() 

Lo que yo he cambiado:

  • creado una variable de instancia local para permitir la instalación antes de devolverlo
  • Forma más compacta de configurar el metatable
  • Use una variable para la clase whe n llamando al código