Свой скриптовый движок для игр средствами С++ и Lua (часть — 1)

в 9:13, , рубрики: c++, engine, Gamedev, Lua

Предисловие

Возможно у вас наступал такой момент, что хотелось написать свой движок для игр, или просто вы хотели узнать, как такое реализовать, но по каким — то причинам вам это не удавалось.
Ну что ж, тема довольно обширная, поэтому я начинаю серию уроков по написанию своего 2д игрового движка, и поверьте он будет не хуже того же Love2d, именно такого стиля и будет наш движок.

Что нужно?

  • Средние знания С++(на нем и будем писать двигатель).
  • Базовые знания Lua (для описания игровой логики).

Как все устроено?

Вся игровая логика будет программироваться в файле, например — «main.lua».
Движок будет читать этот файл и исполнять действия описанные в этом файле.
Вывод графики будет с помощью SDL 2.0, физика — Box2D, аудио — OpenAl, скриптинг — Lua.
IDE — Microsoft Visual Studio любой версии.

Нарисовал схему

Свой скриптовый движок для игр средствами С++ и Lua (часть — 1) - 1

Начинаем!

Сначала надо скачать:

  1. Lua
  2. SDL 2.0
  3. Box2D (надо будет скомпилировать самому)
  4. OpenAL

Скачайте и переместите все файлы в отдельную папку, например — «Engine SDK».
Открываем MVS, создаем «пустое» консольное приложение, далее добавляем файл — «main.cpp».
Заполняем пока таким образом:

int main()
{
return 0;
}

Компилируем, если скомпилировалось, идем дальше.
Жмем «Project -> project properties»
Выбираем «C/C++ -> General» и добавляем дополнительные папки включения (указывайте путь где вы извлекли из архива Lua).
Указываем путь к «include» Lua.
Свой скриптовый движок для игр средствами С++ и Lua (часть — 1) - 2

После этого заходим «Linker ->General» и добавляем путь к либе.
Свой скриптовый движок для игр средствами С++ и Lua (часть — 1) - 3

Применяем и изменяем «main.cpp»

int main(int argc, char * argv[])
{
return 0;
}

Компилируем, идем дальше.
Далее нам нужно создать отдельный заголовочный файл, в котором будет основная часть движка.
Добавляем файл «Engine.h»
И сразу заполняем его таким образом.

#include<iostream>
#include<lua.hpp>
#pragma comment(lib,"lua53") // на момент написания статьи версия Lua 5.3.
using namespace std;
class Lua
{
private:
	lua_State * lua_state;
public:
	void Init()  // инициализируем и подключаем модули.
	{
		lua_state = luaL_newstate();
		static const luaL_Reg lualibs[] =
		{
			{ "base", luaopen_base },
			{ "io", luaopen_io },
			{ "os",luaopen_os },
			{ "math",luaopen_math },
			{ "table",luaopen_table },
			{ "string",luaopen_string },
			{ "package",luaopen_package },
			{ NULL, NULL }
		};
		for (const luaL_Reg *lib = lualibs; lib->func != NULL; lib++)
		{
			luaL_requiref(lua_state, lib->name, lib->func, 1);
			lua_settop(lua_state, 0);
		}
	}
	void Open(const char*filename) // открываем файл с кодом (main.lua)
	{
		luaL_openlibs(lua_state);
		if (luaL_dofile(lua_state, filename))
		{
			const char*error = lua_tostring(lua_state, -1);
		}
	}
	void Close() // закрываем
	{
		lua_close(lua_state);
	}
	void Reg_int(int value, char*name) 
	{
		lua_pushinteger(lua_state, value);
		lua_setglobal(lua_state, name);
	}

	void Reg_double(double value, char*name)
	{
		lua_pushnumber(lua_state, value);
		lua_setglobal(lua_state, name);
	}

	void Reg_bool(bool value, char*name)
	{
		lua_pushboolean(lua_state, value);
		lua_setglobal(lua_state, name);
	}
	void Reg_string(char*value, char*name)
	{
		lua_pushstring(lua_state, value);
		lua_setglobal(lua_state, name);
	}
	void Reg_function(lua_CFunction value, const char*name) // регистр нашей функции
	{
		lua_pushcfunction(lua_state, value);
		lua_setglobal(lua_state, name);
	}
	int Get_int(int index) // берем числовой аргумент из функции
	{
		return (int)lua_tointeger(lua_state, index);
	}
	double Get_double(int index) 
	{
		return lua_tonumber(lua_state, index);
	}
	char* Get_string(int index)
	{
		return (char*)lua_tostring(lua_state, index);
	}
	bool Get_bool(int index)
	{
		return lua_toboolean(lua_state, index);
	}
	void Return_int(int value) // возвращаем числовое значение из функции
	{
		lua_pushinteger(lua_state, value);
	}
	void Return_double(double value)
	{
		lua_pushnumber(lua_state, value);
	}
	void Return_string(char*value)
	{
		lua_pushstring(lua_state, value);
	}
	void Return_bool(int value)
	{
		lua_pushboolean(lua_state, value);
	}
	int Call_load() // вызываем при старте
	{
		lua_getglobal(lua_state, "Load");
		lua_call(lua_state, 0, 1);
		return 0;
	}
	int Call_update() // вызываем пока работает приложения
	{
		lua_getglobal(lua_state, "Update");
		lua_call(lua_state, 0, 1);
		return 0;
	}
	int Call_draw()
	{
		lua_getglobal(lua_state, "Draw"); // вызываем после "Update"
		lua_call(lua_state, 0, 1);
		return 0;
	}
};
Lua lua;// lua экземпляр

Компилируем, если нет ошибок, идем дальше, если же есть, значит вы где- то накосячили.
Изменяем «main.cpp»

include "Engine.h"
int main(int argc, char * argv[])
{
lua.Init();
lua.Open("main.lua");
lua.Call_load();
lua.Close();
return 0;
}

Компилируем, если без ошибок, двигаемся дальше.
Создаем в папке проекта текстовый файл «main.lua».
Заполняем его так:

function Load()
print("Lua inited!")
end

function Update()

end

function Draw()

end

Компилируем, бросаем «lua5*.dll» в папку проекта, запускаем, и Оппа!
В консоле вывело «Lua inited!»
По сути мы написали простой Lua — интерпретатор.
В второй части приступим к выводу графики.

Автор: Wolf_Black

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js