Skip to content

Instantly share code, notes, and snippets.

@kurapica
Last active July 22, 2022 09:54
Show Gist options
  • Save kurapica/03f244cc96b9bde3671fbd4b0fa80969 to your computer and use it in GitHub Desktop.
Save kurapica/03f244cc96b9bde3671fbd4b0fa80969 to your computer and use it in GitHub Desktop.
require "PLoop" (function(_ENV)
-- Declare the namespace
_G.Defold = namespace "Defold"
-- Register it as global, so can be easily accessed
Environment.RegisterGlobalNamespace(Defold)
-- Define the base script class
__Sealed__()
class "Script" (function(_ENV)
local go = _G.go
-- Define useful methods
function Delete(self) go.delete() end
function GetPosition(self) return go.get_position() end
function SetPosition(self, pos) return go.set_position(pos) end
-- Define the abstract method to be override
__Abstract__() function OnUpdate(self) end
__Abstract__() function OnMessage(self, id, message, sender) end
__Abstract__() function OnReload(self) end
__Abstract__() function OnFinal(self) end
-- A property to hold the script target
property "ScriptTarget" {}
-- The constructor to hold the script target
function __ctor(self, script)
self.ScriptTarget = script
end
end)
-- An attribute to declare the class property to be script property
__Sealed__()
class "__ScriptAttr__" (function(_ENV)
extend "IInitAttribute" "IAttachAttribute"
-- Modify the property definition so the value will be get/set in the script target
function InitDefinition(self, target, targettype, definition, owner, name, stack)
if not Class.IsSubType(owner, Script) then
error("The __ScriptAttr__ can only be used on sub class of Defold.Script", stack + 1)
end
-- Modify the propety's get/set
definition.get = function(self)
return self.ScriptTarget[name]
end
definition.set = function(self, value)
self.ScriptTarget[name] = value
end
end
-- Attach a data so the Script.Install can diff the script property with common property
function AttachAttribute(self, target, targettype, owner, name, stack)
return true
end
-- The attribute can only be used on property
property "AttributeTarget" { set = false, default = AttributeTargets.Property }
end)
-- Define the script install script
__Static__()
function Script.Install(func)
-- Gets the call environment
local env = getfenv(2)
local scriptClass
if Class.Validate(func) then
scriptClass = func
elseif type(func) == "function" or type(func) == "table" then
-- Generate the class from the definition
local ok
ok, scriptClass = pcall(class, func)
if not ok then
error(scriptClass, 0)
end
else
error("Usage: Defold.Script.Install(script) - the script must be a class or definition", 2)
end
if not Class.IsSubType(scriptClass, Script) then
error("Usage: Defold.Script.Install(script) - the script must be sub class of Defold.Script", 2)
end
-- Generate the script properties
for name, prop in Class.GetFeatures(scriptClass) do
if Property.Validate(prop) and Attribute.HasAttachedData(__ScriptAttr__, prop, scriptClass) then
env.go.property(name, prop:GetDefault())
end
end
-- Create the script class in the init
env.init = function(self) self.__inner = scriptClass(self) end
-- Check if need update, use GetNormalMethod to ignore the abstract method
if Class.GetNormalMethod(scriptClass, "OnUpdate") then
env.update = function(self, dt) return self.__inner:OnUpdate(dt) end
end
-- Check if need on_message
if Class.GetNormalMethod(scriptClass, "OnMessage") then
env.on_message = function(self, id, msg, sender) return self.__inner:OnMessage(id, msg, sender) end
end
-- Check if need on_reload
if Class.GetNormalMethod(scriptClass, "OnReload") then
env.on_reload = function(self) return self.__inner:OnReload() end
end
-- Check if need final
if Class.GetNormalMethod(scriptClass, "OnFinal") then
env.final = function(self) return self.__inner:OnFinal() end
end
end
end)
@kurapica
Copy link
Author

The usage

-- test.script
require "main"

Defold.Script.Install(function(_ENV)
    inherit "Defold.Script"

    function OnUpdate(self)
        self.Health = self.Health - 1

        if self.Health <= 0 then
            self:Delete()
        end
    end

    -- Declare the script properties
    __ScriptAttr__()
    property "Health" { type = Number, default = 100 }
end)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment