2016-09-16 71 views
0

我正在研究一個簡單的遊戲引擎,只是爲了體驗它。不過,我意識到,我不知道如何將用戶的自定義遊戲作爲自己的獨立可執行文件導出。例如(這不是我的實際遊戲引擎,它只是提供了一個討論一個簡單的參考),假設我們有下面的代碼非常簡單:在C++中創建一個CUSTOM exe文件

#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或者.dll文件。所以你需要的文件。您需要爲此編寫的所有說明將隨操作系統而變化,您可能需要引入邏輯來檢測確切的平臺並做出明智的決策,而且您需要改變32位和64位。

此時您已準備好開始爲遊戲發佈機器說明。

這裏的一個合理的替代方法是(由Unity完成)爲您的引擎提供一個「空白」可執行文件。你的引擎本身就是一個共享庫(.dll或.so),空白的可執行文件只是一個加載共享庫的包裝器,並在其中調用一個指向其數據部分的指針的函數。

生成您的用戶可執行文件將包括加載適當的空白文件,對其進行特定於平臺的修改,以告知其打算提供的數據部分的大小,並以適當的格式編寫數據。或者,你可以簡單地擁有一個具有在其中你寫值的原始結構的嵌入式副本,就像在內存填充一個struct空白:

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」的定義。

但是很多引擎做的僅僅是運輸或要求用戶安裝一個編譯器(團結依靠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閱讀您的文件。

在開始時,您可以詢問您的用戶他是想創建一個測驗還是玩一個已經存在的測驗。


編輯:

因爲這聽起來很像功課我只是提供一些僞代碼。

我會去這樣的(僞代碼)的方法:

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文件的大小),其中可執行實際上結束,這也意味着 .exe文件的「計算」結束(通過頭)後粘貼任何數據都不會產生負面影響的二進制文件。它仍然會加載並執行得很好。

您可以在可執行文件結束後濫用此屬性來連接數據。

我將離開你與這個測試,使用Windows的捆綁寫字板應用程序爲‘其他一些數據主機’:

  • 轉到C:\ WINDOWS和複製WRITE.EXE(寫字板)到另一個文件夾,所以我們可以試驗而不會損壞任何東西。

  • 帶上該文件夾的另一個文件,任何文件都可以。在我的例子中,數據文件將一個PDF稱爲「myfancyfile.pdf」

  • 現在,打開一個命令提示符並使用COPY命令這兩個文件拼接在一起,確保該.exe至上:

    copy /B write.exe+myfancyfile.pdf mynewprogram.exe 
    
    • 副本的/B標誌的意思是「二進制複製」,所以基本上這兩個文件都粘貼在一起,沒有任何形式的文本或數據轉換。
  • 嘗試運行「mynewprogram.exe」。實現它運行得很好:-)

自我修改您的.exe數據不僅可行,它不會負面影響功能。話雖如此,但它仍然是一個難以持久數據的方式。

爲您的解決方案編碼很有趣。

+2

OP也可以修改全局字符串/數組,如果他在'.exe'中添加了某種標記來查找它們的話 – HolyBlackCat

+0

程序如何知道上傳的數據是? –

+0

@HolyBlackCat謝謝你,以上和kfsone的評論上面我想我有我的答案 – ArcaneLight

相關問題