Coder Social home page Coder Social logo

iwiniwin / luakit Goto Github PK

View Code? Open in Web Editor NEW
151.0 2.0 41.0 329 KB

Lua核心工具包,包含对面向对象,组件系统(灵活的绑定解绑模式),mvc分模块加载,事件分发系统等常用模式的封装。同时提供打印,内存泄漏检测,性能分析等常用工具类。

Lua 95.76% C 4.24%
lua kit framework behavior dump design-pattern oop component

luakit's Introduction

LuaKit

Lua核心工具包,提供对面向对象,组件系统,mvc模块化加载,事件分发系统等常用模式的封装。同时提供打印,内存泄漏检测,字符串操作等常用工具类。 PS:添加了注释的Lua源码可以参考这里

LuaKit部分特性介绍如下,用法/测试用例请参考这里

Contents

打印复杂表结构

dump支持按照指定格式打印任意类型的数据 dump_to_file支持将数据序列化到文件

local data = {
    key1 = 34,
    key2 = "str",
    key3 = {
        key4 = {
            key5 = 56
        },
        key6 = 78
    }
}
dump(data, "this is a dump test")

输出结果如下:

- "this is a dump test" = {
-     "key1" = 34
-     "key2" = "str"
-     "key3" = {
-         "key4" = {
-             "key5" = 56
-         }
-         "key6" = 78
-     }
- }

组件系统

游戏开发中很多功能无法单纯靠继承实现,因为类继承会导致难以轻易改变结构,功能全都向上依赖,子类的数据爆炸,大量冗余数据和方法导致内存消耗过大。而采用组件系统,组件才是功能的携带者,可以实时增减,动态为对象增减功能。对象绑定组件就可以拥有该组件提供的功能,解绑组件则移除对应功能,通过组合构建拥有完整功能的对象,更加灵活解耦。

例如: Fly组件提供飞的能力,鸟对象绑定Fly组件就可以飞,移除Fly组件就不能飞

local ComponentBase = require("core.component.component_base")
local ComponentExtend = require("core.component.component_extend")

local A = class()
ComponentExtend(A)

-- 组件1
local Component1 = class(ComponentBase)
Component1.exportInterface = {
    {"test1"},
}
function Component1:test1( ... )
    dump("call test1 ...")
end

-- 组件2
local Component2 = class(ComponentBase)
Component2.exportInterface = {
    {"test2"},
}
function Component2:test2( ... )
    dump("call test2 ...")
end

local a = new(A)

a:bind_component(Component1)  -- 对象a绑定组件1 拥有test1方法
a:bind_component(Component2)  -- 对象a绑定组件2 拥有test2方法
a:test1()
a:test2()

a:unbind_component(Component1)  -- 解绑组件1 丧失test1方法
-- a:test1()  -- 报错 attempt to call method 'test1' (a nil value)

事件分发系统

基于观察者模式封装的一套事件分发系统

local EventSystem = new(require("core.event.event_system"))
local Event = require("core.event.event")

-- 简单用法
EventSystem:on("test", function ( ... )
    dump({...})
end)

EventSystem:emit("test", "param1", "param2")

-- 高级用法
local A = class()
function A:on_key_down( key )
    dump(key, "key name A")
end
EventSystem:on(Event.KeyDown, A.on_key_down, {target = A})

local B = class()
function B:on_key_down( key )
    dump(key, "key name B")

    return true  -- 可以中断事件派发
end

-- 后注册的事件通过提高优先级可以保证先被调用
EventSystem:on(Event.KeyDown, B.on_key_down, {target = B, priority = 2})

EventSystem:emit(Event.KeyDown, "Ctrl")

EventSystem:off_all(B)  -- 通过target取消注册

EventSystem:emit(Event.KeyDown, "Ctrl")

高级用法中,第一次emit时,首先触发B,B的回调返回true中断了派发,导致A的回调不会被执行,所以只打印了key name B 第二次emit时,B已经被off_all,不会触发B的回调,自然也没有人再中断事件的派发,所以只打印了key name A

输出结果如下所示:

- dump from: E:\Project\LuaKit\test.lua:155: in function 'func'
- "<var>" = {
-     1 = "param1"
-     2 = "param2"
- }
- dump from: E:\Project\LuaKit\test.lua:170: in function 'func'
- "key name B" = "Ctrl"
- dump from: E:\Project\LuaKit\test.lua:164: in function 'func'
- "key name A" = "Ctrl"

面向对象封装

基于Lua原表提供了class, new, delete等面向对象中**中的常用函数

local Class1 = class()
function Class1:ctor( ... )
    dump("Class1:ctor")
end
function Class1:dtor( ... )
    dump("Class1:dtor")
end

-- Class2集成于Class1
local Class2 = class(Class1)
function Class2:ctor( ... )
    dump("Class2:ctor")
end
function Class2:dtor( ... )
    dump("Class2:dtor")
end
-- 实例化对象
local c1 = new(Class1)
local c2 = new (Class2)
-- 销毁对象
delete(c1)
delete(c2)

分模块加载

分模块加载是一种模块化设计**,通过配置文件,实现对模块的按需加载。再结合mvc,可以将一个大系统,看做由多个子模块组合而成。配置了指定模块,则系统拥有该模块的功能,取消配置则不会加载该模块。

local ModuleConfig = {}

ModuleConfig.Module1 = {
    file = "mvc.module1.test1_view",
    initOrder = 2,  -- 配置模块加载顺序
}

ModuleConfig.Module2 = {
    file = "mvc.module2.test2_view",
    initOrder = 1,
}

return ModuleConfig

性能分析

通过LuaKit提供的profile工具,可以获取函数的调用情况,调用次数,调用时间,子函数调用时间等信息,以此来分析是否存在异常的函数调用或耗时操作。在需要进行性能优化时十分有用。

local new_profiler = require("utils.profiler")
local profiler = new_profiler("call")
profiler:start()  -- 开启性能分析

local function aaa(  )
    for i = 1, 10000000 do

    end
end
local function ttt(  )
    aaa()
end
ttt()
-- 同时支持分析协程内的函数调用情况
local co = coroutine.create(function ( ... )
    aaa()
end)
coroutine.resume(co)

profiler:stop()  -- 停止性能分析
-- 输出分析结果到文件
profiler:dump_report_to_file("profile.txt")

分析结果部分内容如下

Total time spent in profiled functions: 0.113s
Total call count spent in profiled functions: 12
Lua Profile output created by profiler.lua. author: iwiniwin 

-----------------------------------------------------------------------------------
| FILE                            : FUNCTION         : TIME   : %     : Call count|
-----------------------------------------------------------------------------------
| L:E:\Project\LuaKit\test.lua:61 : aaa              : 0.1130 : 100.0 :         2 |
| L:E:\Project\LuaKit\test.lua:71 : unknow           : 0.0580 : 51.3  :         1 |
| C:resume@=[C]:-1                : resume           : 0.0580 : 51.3  :         1 |
| L:E:\Project\LuaKit\test.lua:66 : ttt              : 0.0550 : 48.7  :         1 |
| C:insert@=[C]:-1                : insert           : ~      : ~     :         1 |
| C:sethook@=[C]:-1               : sethook          : ~      : ~     :         2 |
| C:coroutine_create@=[C]:-1      : coroutine_create : ~      : ~     :         1 |
| L:.\utils\profiler.lua:122      : stop             : ~      : ~     :         1 |
| C:clock@=[C]:-1                 : clock            : ~      : ~     :         1 |
| L:.\utils\profiler.lua:106      : create           : ~      : ~     :         1 |
-----------------------------------------------------------------------------------

--------------------- L:aaa@@E:\Project\LuaKit\test.lua:61 ---------------------
Call count:            2
Time spend total:       0.1130s
Time spent in children: 0.0000s
Time spent in self:     0.1130s

内存泄漏检测

对于游戏开发而言,内存泄露往往是最容易忽视的问题,很多开发者并不知道自己的代码是否存在内存泄露。此类问题可以借助MemoryMonitor来检测,具体原理是借助lua的弱引用,把某个需要观察的对象加入到弱表,如果不存在外部引用,那么在gc时候,弱表上的该对象也就自然消失,如果弱表还存在该对象,说明外部仍存在引用。

local MemoryMonitor = require("utils.memory_monitor")
local memoryMonitor = new(MemoryMonitor)

a = {}
function test( ... )
    local b = {xxx = "xxx"}
    a.b = b
    memoryMonitor:add_to_leak_monitor(b, "b")  --将b添加到内存检测工具,此时a没有被释放掉 则b也释放不掉
end
test()

-- 由于a在引用b,因此b存在内存泄漏
memoryMonitor:update()  -- 这里会打印日志

-- a不再引用b,b也被释放
a = nil
memoryMonitor:update()  -- 没有内存泄漏,这里不会打印日志

第一次update时存在内存泄漏,输出如下所示

存在以下内存泄漏:    
b@table: 02C5F7A8 = table: 02C5F7A8
请仔细检查代码!!!

luakit's People

Contributors

iwiniwin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.