Corona LUA和面向对象设计

所以,我来自使用面向对象编程原则的传统游戏开发领域,从我所见,你可以通过了解 LUA 来模拟这种编程方式。在一些代码发布中,我发现你可以使用 director 类,并创建具有 new() 函数等的文件。我正在寻找一种管理武器的方法。我有一个玩家和一个对手,我希望只有一个武器类,比如 weaponCanon。我所做的是:

-- 此处为私有变量
local power
local canonSprite
local whatever

local someFunction = function()
...
end

-- 此处为私有内容
local weaponCanon = {}

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

weaponCanon.reset = function()
...
end

return weaponCanon

然后我只需要在我的关卡代码中如下调用:

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

这很好用,可以让我在编写武器代码时使用“私有”和“公共”的心态。问题在于,如果我希望玩家和对手拥有加农炮:

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

它只会返回相同的对象,而不是新实例。所以只有在 opponentWeapon 处我得到一个 weaponCanon。这显然不是我想要或需要的。我们的游戏中有很多武器,有一个方法是只有一个每个文件版本,并使用一个设置告诉我们它是对手武器还是玩家武器。另一种方法是复制每个文件,并创建 weaponPlayerCanon 和 weaponOpponentCanon,但我想到每次修改一个文件并必须更改 2+ 个文件就会毛骨悚然。

我该如何使其返回实例,以及如何构造 LUA 文件?感谢你提供的任何帮助!

-d

原文链接 https://stackoverflow.com/questions/6345365

点赞
stackoverflow用户206020
stackoverflow用户206020

我猜你想用你的源文件建立一个类的模型。这意味着除非你希望它们共享所有状态,否则你还应该有一个函数来创建该类的新实例。

如下所示(未经测试):

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

function WeaponCannon:fire(x, y)
  -- 通过 self 引用和参数(x,y)执行某些操作
end

return WeaponCannon

在你的调用代码中(同样未经测试):

require('WeaponCannon')
local playerWeapon = WeaponCannon:new()
local opponentWeapon = WeaponCannon:new()
2011-06-14 16:17:46
stackoverflow用户298661
stackoverflow用户298661

这里没有对象 - 你只有一堆全局数据。你真的需要创建实例。

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)
2011-06-14 16:25:41
stackoverflow用户312586
stackoverflow用户312586

如果您后来需要继承(即,LaserCannon 是 Weapon 的子类),您可能需要更深入地使用元表。

有很多库可以让您在 Lua 上进行“面向对象编程”。您可以在此处查看非常好的列表:

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

我是 middleclass 的作者。使用我的库,您需要执行以下操作:

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 - 您只需向类传递第二个参数:

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

您可以像这样使用它:

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

这是使用我喜欢的 middleclass 做的。我之前提到的页面上的其他库提供类似的功能。

2011-06-15 07:27:24
stackoverflow用户686008
stackoverflow用户686008

虽然你为武器对象创建了一个新的表,但并没有创建新的变量。在模块顶部声明的任何变量都是静态变量(即,所有类实例共享的变量)。要创建唯一于该对象的变量,需要在表中创建它们,例如:

weaponCannon = {}
weaponCannon.power = 10

而且你只需要创建一个对象,需要一个“构造函数”来创建表:

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


顺便提一下,与你的答案没有直接相关性的两件非常有用的修改代码。首先,在方法中使用冒号而不是句号调用函数将允许您在方法内使用“self”关键字,例如:

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

然后

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

其次,您实际上可以将显示对象用作表,而不必创建一个空表,然后将显示对象放入该空表中:

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

请注意,如果这样做,您无法设置元表。我发现这种方法看起来更合乎逻辑,因此不喜欢使用元表,但这是您的决定。

2011-06-15 11:54:51
stackoverflow用户511299
stackoverflow用户511299

我喜欢ponzao的回答。但是我会对它进行更改:

local WeaponCannon = {}

function WeaponCannon:new()
  local instance = {}
  setmetatable(instance, {__index = WeaponCannon})
  -- 在这里设置你的新实例
  return instance
end

function WeaponCannon:fire(x, y)
  -- 通过self引用和参数(x,y)进行某些操作
end

return WeaponCannon

在您的调用代码中:

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

我做出了以下更改:

  • 创建本地实例变量以允许在返回实例之前进行设置
  • 更紧凑的设置元表的方法
  • 在调用代码时使用一个变量来表示类
2013-05-17 09:56:00