官术网_书友最值得收藏!

Preparing a basic file structure for the game engine

When programming a larger project, it's always important to keep it maintainable. One of the common practices is to keep a modular structure. Modular structure can be achieved by keeping files separated in certain directories.

Lua language uses a require function to include modules in your script files. This function uses a default list of paths where it tries to find the module file. The Lua modules can be written as plain Lua scripts or use a form of binary library, which is OS and CPU architecture dependent. This is especially troublesome if want to include binary libraries for all supported operating systems and CPU architectures in one project.

A default set of paths might not always be appropriate for your project, mainly if you bundle many third-party modules with it.

This recipe shows how to set up the Lua interpreter so that it can find correct files in a systematic and user-definable way. This recipe should be used at the beginning of your main Lua script file so that further calls to the require function in Lua will use your file path structure.

Getting ready

You can use a directory structure as shown in the following diagram. If you intend to implement your application for multiple platforms, always pide platform-specific files into separate directories.

The Lib directory contains all the Lua module files and binary libraries.

However, each operating system uses its own file naming convention for binary libraries. The Lua language doesn't have an easy way to obtain the OS name. For this purpose, you can download and use the Lua script module os_name.lua from https://gist.github.com/soulik/82e9d02a818ce12498d1.

You should copy this file into your project directory so that the Lua interpreter can find it.

How to do it…

The require function in the Lua language uses a set of default paths defined in package.path and package.cpath string variables. With your new directory structure, you'd have to change those two variables manually for each operating system, which could be cumbersome.

Instead, you can define a Lua script to build up these two string variables from a generic list of paths for both Lua script files and binary libraries.

In the first step, you need to create a list of directories:

-- A list of paths to lua script modules
local paths = {
  '{root}/{module}',
  '{root}/lib/{module}',
  '{root}/lib/external/{module}',
  '{root}/lib/external/platform-specific/{platform}/{module}',
}
-- A list of paths to binary Lua modules
local module_paths = {
  '?.{extension}',
  '?/init.{extension}',
  '?/core.{extension}',
}

Strings enclosed with curly brackets will be substituted with the following values:

Binary module filename extensions that are platform dependent are also set in a table:

-- List of supported OS paired with binary file extension name
local extensions = {
  Windows = 'dll',
  Linux = 'so',
  Mac = 'dylib',
}

Now, you need to set root_dir which is the current working directory of the application and the current platform name as follows:

-- os_name is a supplemental module for
-- OS and CPU architecture detection
local os_name = require 'os_name'

-- A dot character represent current working directory
local root_dir = '.'
local current_platform, current_architecture = os_name.getOS()

local cpaths, lpaths = {}, {}
local current_clib_extension = extensions[current_platform]

Before you start building the path list, you need to check whether the current platform has defined binary module extensions as follows:

if current_clib_extension then
  -- now you can process each defined path for module.
  for _, path in ipairs(paths) do
    local path = path:gsub("{(%w+)}", {
      root = root_dir,
      platform = current_platform,
    })
    -- skip empty path entries
    if #path>0 then
      -- make a substitution for each module file path.
      for _, raw_module_path in ipairs(module_paths) do
        local module_path = path:gsub("{(%w+)}", {
          module = raw_module_path
        })
        -- add path for binary module
        cpaths[#cpaths+1] = module_path:gsub("{(%w+)}", {
          extension = current_clib_extension
        })
        -- add paths for platform independent lua and luac modules
        lpaths[#lpaths+1] = module_path:gsub("{(%w+)}", {
          extension = 'lua'
        })
        lpaths[#lpaths+1] = module_path:gsub("{(%w+)}", {
          extension = 'luac'
        })
      end
    end
  end
  -- build module path list delimited with semicolon.
  package.path = table.concat(lpaths, ";")
  package.cpath = table.concat(cpaths, ";")
end

With this design, you can easily manage your module paths just by editing paths and module_paths tables.

Keep in mind that you need to execute this code before any require command.

How it works…

This recipe builds content for two variables that are used in the require function—package.path and package.cpath.

Both variables use a semicolon as a delimiter for inpidual paths. There's also a special character—the question mark which is substituted with the module name. Note that the path order might not be as important in this case as with our default list of paths. The path order might cause problems if you expect to use a module out of the project directory structure. Therefore, a customized set of paths from this recipe should always be used before the default set of paths.

The Lua language allows the use of hierarchical structure of modules. You can specify a submodule with package names delimited by a dot.

require 'main_module.submodule'

A dot is always replaced with the correct directory separator.

主站蜘蛛池模板: 文化| 连云港市| 皋兰县| 拜泉县| 丹阳市| 卢龙县| 天水市| 新乡市| 容城县| 桃源县| 阿合奇县| 曲阜市| 宁河县| 忻州市| 侯马市| 宜宾县| 清水县| 阿尔山市| 霍林郭勒市| 青阳县| 德钦县| 吴堡县| 宣化县| 吉木萨尔县| 比如县| 瓮安县| 八宿县| 泌阳县| 嘉祥县| 双牌县| 常山县| 道真| 江城| 湘阴县| 吴桥县| 巨鹿县| 黔江区| 安义县| 台北县| 舒城县| 合阳县|