2016-09-16 2 views
0

Я работаю над простым игровым движком только для его опыта. Однако я понял, что я понятия не имею, как экспортировать пользовательскую игру пользователя в качестве собственного автономного исполняемого файла. Например (это не мой фактический игровой движок, он просто обеспечивает простую ссылку для обсуждения), предположим, что мы имели следующий очень простой код:Создание файла CUSTOM exe в C++

#include "stdafx.h" 
#include <iostream> 
#include <string> 

using namespace std; 

void RunGame(string question, string answer) 
{ 
    string submission; 
    cout << question << endl; 
    getline(cin, submission); 
    if (submission == answer) 
     cout << "Correct!"; 
    else 
     cout << "Wrong!"; 
} 

int main() 
{ 
    string question; 
    string answer; 

    cout << "Enter Question:" << endl; 
    getline(cin, question); 
    cout << "Enter Answer:" << endl; 
    getline(cin, answer); 


    RunGame(question, answer); 
} 

В этом примере пользователь получает создать свой собственный настроенный бит мелочи, а затем можно сразу же проверить его, когда вызывается RunGame. Теперь я хочу иметь возможность сохранить свою игру с информацией о мелочах, которую они предоставили в виде собственного .exe (в основном это будет выполняться после вызова RunGame и далее). Как мне это сделать?

Чтобы быть ясным, это не вопрос о том, что является самым простым и быстрым способом сделать игру. Он ищет, как создать автономный исполняемый файл из кода.

+0

Вы пытались помещать данные Клиента в файл данных, а не в исполняемый файл? –

+0

Почему вы хотите, чтобы мелочи исполнялись? Собираетесь ли вы * выполнить * данные о мелочах? * (Обычно данные не выполняются, но читаются или записываются программой.) * –

+0

Файл данных может быть установлен вместе с исполняемым файлом. Многие программы установки могут создавать установки, которые включают исполняемые файлы и файлы данных. –

ответ

1

Построение исполняемого файла нетривиально. Сначала вам необходимо выполнить ABI целевых операционных систем, чтобы он мог найти точку входа вашей программы. Следующим шагом будет решение о том, как ваша программа будет иметь доступ к системным ресурсам: вероятно, вы захотите, чтобы исполняемый файл реализовал динамическую компоновку, чтобы иметь доступ к общим библиотекам, и вам нужно загрузить различные DLL или. поэтому файлы вам понадобятся. Все инструкции, которые вам нужно написать для этого, будут отличаться от ОС к ОС, вам может потребоваться ввести логику для определения точной платформы и принятия обоснованных решений, и вам нужно будет варьироваться от 32 до 64 бит.

На этом этапе вы готовы начать выдавать машинные инструкции для своей игры.

Разумная альтернатива здесь (как это сделано Unity) для обеспечения «пустого» исполняемого файла вашим двигателем. Сам ваш движок будет общей библиотекой (.dll или .so), а пустой исполняемый файл будет просто оболочкой, которая загружает общую библиотеку и вызывает в ней функцию с указателем на что-то в этом разделе данных.

Создание исполняемого файла пользователя будет включать загрузку соответствующего пустого места, внесение в него изменений для конкретной платформы, чтобы указать размер раздела данных, которое вы предназначили для его предоставления, и записать ваши данные в соответствующем формате.Или вы могли бы просто иметь пробел, который имеет встроенную копию структуры исходной, в котором вы пишете значения, так же, как заполнение структуры в памяти:

struct GameDefinition { 
    constexpr size_t AuthorNameLen = 80; 
    char author_[AutherNameLen+1]; 
    constexpr size_t PublisherNameLen = 80; 
    char publisher_[PublisherNameLen+1]; 
    constexpr size_t GameNameLen = 80; 
    char name_[GameNameLen+1]; 
    constexpr size_t QuestionLen = 80; 
    constexpr size_t AnswerLen = 80; 
    char question_[QuestionLen+1]; 
    char answer_[AnswerLen+1]; 
}; 

static GameDefinition gameDef; 

#include "engine_library.h" // for run_engine 

int main() { 
    run_engine(&gameDef); 
} 

Вы бы скомпилировать этот againsst общих библиотек заглушки для ваш движок и испускайте его как исполняемый файл, тогда вы будете искать подробные сведения о исполняемом формате для конкретной платформы, найдите в нем позицию «gameDef». Вы читали пустоту в памяти и записывали ее с заменой определения «gameDef» на тот, который основан на пользовательском вводе.

Но то, что многие двигатели делают, просто отправляет или требует от пользователя установки компилятора (Unity полагается на C#). Поэтому вместо того, чтобы настраивать исполняемые файлы и выполнять все эти сумасшедшие вещи, специфичные для платформы, они просто выводят программу C/C++ и компилируют ее.

// game-generator 
bool make_game(std::string filename, std::string q, std::string a) { 
    std::ostream cpp(filename + ".cpp"); 
    if (!cpp.is_open()) { 
     std::cerr << "open failed\n"; 
     return false; 
    } 
    cpp << "#include <engine.h>\n"; 
    cpp << "Gamedef gd(\"" << gameName << "\", \"" << authorName << \");\n"; 
    cpp << "int main() {\n"; 
    cpp << " gd.q = \"" << q << \"\n"; 
    cpp << " gd.a = \"" << a << \"\n"; 
    cpp << " RunGame(gd);\n"; 
    cpp << "}\n"; 
    cpp.close(); 

    if (!invoke_compiler(filename, ".cpp")) { 
     std::cerr << "compile failed\n"; 
     return false; 
    } 
    if (!invoke_linker(filename)) { 
     std::cerr << "link failed\n"; 
     return false; 
    } 
} 

Если «RunGame» не является частью вашего двигателя, но поставляемый пользователь, то вы могли бы излучать, что в качестве части коды CPP. В противном случае, намерение здесь состоит в том, что он звонит в вашу библиотеку.

Под Linux вы можете скомпилировать это с

g++ -Wall -O3 -o ${filename}.o ${filename}.cpp 

, а затем

g++ -Wall -O3 -o ${filename} ${filename}.o -lengine_library 

, чтобы связать его с библиотекой вашего двигателя.

+0

Не знаете, насколько это было умение делать это на моем телефоне, надеюсь, что это разборчиво. – kfsone

+0

Примечание: Компилятор Visual Studio и т. Д. - автономные приложения, которые не встроены в визуальный ide. «Invoke_compiler» и «invoke_linker» - это функции, которые вам нужно написать, они могут быть такими же простыми, как «std :: string args =» g ++ -Wall -o »...; system (args.c_str()); 'для linux и' #ifdfef WIN32', который выполняет эквивалент Windows, но вы, вероятно, захотите посмотреть на более мелкий контроль над дочерними процессами. – kfsone

1

Вы не хотите этого делать. Лучше всего сохранить мелочи в каком-то пользовательском формате (например, .txt, .dat, ..).

Тогда игра просто обрабатывает эти данные.

Так что сначала подумайте о формате внутри .txt, например.

Давайте сначала скажем, номер, указывающий, какая именно запись. Второе следует за вопросом, и после этого следует ответ. Это, вы должны решить для себя.

Пример пустяков-data.txt

1 
How old is actor X from show Y? 
32 years 
2 
... 
... 

#include <iostream> // std::cout, std::endl 
#include <fstream> // std::ifstream, std::ofstream 
using namespace std; 
int main() 
{ 
    // create file 
    ofstream ofile("trivia-data.txt"); 

    // define your data 
    int num_of_question = 1; 
    string question, answer; 
    getline(cin, question); 
    getline(cin, answer); 

    // write your data to the file 
    ofile << num_of_question << '\n'; 
    ofile << question << '\n'; 
    ofile << answer << '\n'; 

    // close the file 
    ofile.close(); 

    return 0; 
} 

Теперь, когда вы создали данные, которые вы просто должны строить свою программу так, как вы хотели бы, чтобы представить это. Вместо того, чтобы писать в файл, вы должны прочитать из файла и распечатать вопросы и сравнить ответы, а что нет. Посмотрите std::ifstream для чтения вашего файла.

С самого начала вы можете спросить своего пользователя, хочет ли он создать викторину или сыграть ту, которая уже существует.


Edit:

Поскольку это звучит очень похоже на домашнее задание, я просто предоставить некоторые псевдо-код.

я бы на подходе, как это (псевдо-код):

print "Would you like to create(c) or play(p) a quiz? Answer(c/p): " 
input = get_input() // 'c' or 'p' 
if input == 'c' 
    // now do what I posted with some loops to create a couple of questions 
else 
    print "Please provide an URL to the quiz-data you would like to play: " 
    url = get_input() // C:/test.txt 
    // read in data, print out questions, do comparisons and print answers etc 

Это гораздо проще, чем ваш подход, и это также делает возможным для других, чтобы создавать тесты не только вы.

+1

Я пытался убедить OP этого маршрута, но OP настаивает на использовании исполняемого файла. :-( –

+0

@ThomasMatthews да, я просто это увидел. О хорошо. –

3

Если вы действительно хотите хранить данные внутри самого .exe:

Исполняемый имеет заголовок, который определяет его размер, границы и другие полезные вещи для операционной системы, так, по существу, операционную систему знает, где начинается и заканчивается раздел кода и данных, и, наконец, использует эту информацию для загрузки .exe в память, когда ее просят запустить.

Поскольку операционная система знает (помимо размера файла .exe в), где исполняемый файл на самом деле заканчивается, это также означает, что любые данные, вставленные после Исполняемых в «рассчитывается» конец (по заголовкам) не будет отрицательно повлиять на его двоичный файл. Он по-прежнему будет загружаться и выполняться просто отлично.

Это свойство можно использовать для объединения данных после окончания исполняемого файла.

Я оставлю вас с этим тестом, используя в комплекте приложения WordPad как 'Windows хозяина' для некоторых других данных:

  • Перейти к C: \ Windows и скопировать write.exe (WordPad) в другую папку, чтобы мы могли экспериментировать, не повредив ничего.

  • Принесите в эту папку другой файл, любой файл будет делать. В моем примере, файл данных будет PDF под названием «myfancyfile.pdf»

  • Теперь откройте командную строку и используйте команду COPY сшить оба файла вместе, убедившись, что .exe приходит первым:

    copy /B write.exe+myfancyfile.pdf mynewprogram.exe 
    
    • /B флаг у копии означает «двоичную копию», поэтому по существу оба файла были склеены без какого-либо текста или преобразования данных.
  • Попробуйте запустить «mynewprogram.exe». Реализовать это работает просто отлично :-)

Самомодифицирующийся ваш exe-файл с данными не только возможно, это не будет отрицательно влиять функциональность. Сказав это, это все еще уродливый способ сохранить данные.

Удачи в кодировании вашего решения.

+2

OP также может изменять глобальные строки/массивы, если он добавляет какой-то маркер, чтобы найти их внутри '.exe'. – HolyBlackCat

+0

Как программа знает, где appened data is? –

+0

@HolyBlackCat Спасибо, с этим и комментарием kfsone выше Я думаю, что у меня есть мой ответ. – ArcaneLight

Смежные вопросы