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

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.

主站蜘蛛池模板: 襄城县| 陇川县| 聂拉木县| 仙桃市| 巨野县| 兰西县| 吉水县| 兴义市| 五莲县| 繁昌县| 玉田县| 泗阳县| 登封市| 双鸭山市| 博客| 吕梁市| 策勒县| 富阳市| 永仁县| 南漳县| 阳高县| 扶沟县| 凤凰县| 河南省| 平安县| 西畴县| 西藏| 瑞丽市| 贵溪市| 大丰市| 久治县| 安图县| 安康市| 甘谷县| 札达县| 曲阜市| 特克斯县| 刚察县| 永吉县| 天峻县| 饶河县|