如何从外部资源中获取信息

How to pull information from an external source into a game

本文关键字:获取 信息 资源 从外部      更新时间:2023-10-16

我正试图找到一种方法,通过电子表格导入统计数据到一个正在进行的游戏?下面是我正在处理的内容:

例如,现在……咒语,为了给他们命名,设置属性,等等,并能够通过数字呼叫他们,在实际代码中有这样的东西:

    void spell(int & eMoney, int eSpell[10])
{
    using namespace std;
    char spellname[10][25] = {"Minor Heal", "Fire Shard", "Lightening Shard", "Ice Shard", "Magic Barrier", "Essence Of Life", 
"Earth Shard", "Wind Shard", "Insigma", "Weaken"};
    int spellcost[10] = {50, 80, 80, 80, 100, 100, 80, 80, 120, 80};

这一切都很好,很好,它工作…但这是一个现在和以后的问题……我希望能够使用电子表格,比如CSV文件,这样我就可以有一个电子表格,比如咒语、剑、俱乐部……我计划拥有一个非常大的选择,更理想的情况是能够编辑单个文件的列和行,并让实际游戏在需要时从外部文件中提取信息……但我不知道该怎么做?我愿意接受任何意见。

下面是我现在如何调用法术信息的一个例子:

case 2:
            do
            {
                cout << "Which spell would you like to cast?nn";
                for(x=0;x<10;x++)
                    cout << x+1 << ". " << spellname[x] << ": " << eSpell[x] << " left" << endl;
                cout << "11. Leavenn>> ";
                cin >> decision;
                system("cls");
            }
            while((decision<1)&&(decision>11)||(eSpell[decision-1]==0));
            switch(decision)

这是我脑子里的一个电子表格的例子?从A1开始:

Type        sName   mDmg    sPrice
Spell   1   Minor Heal  10  100
Spell   2   Fire Shard  12  100
Spell   3   Lightening Shard    12  200
Spell   4   Ice Shard   12  150
Spell   5   Magic Barrier   10  130
Spell   6   Essence Of Life 15  10
Spell   7   Earth Shard 12  120
Spell   8   Wind Shard  12  230
Spell   9   Insigma 12  90
Spell   10  Weaken  12  100

另一个例子:

当前代码:

char monsters[16][25] = {"Wolf", "Bear", "Bandit", "Traveler", "Gargoyle", "Knight", "Warlock", "Mammoth", "Cyclops", "Unicorn", "Dragon", "Your Mother", "Demon", "Jesus", "Satan", "God"};
    //monster strengths
    int monsterdamagemax[16] = {32, 42, 53, 53, 65, 65, 75, 75, 85, 85, 90, 90, 95, 95, 110, 110};
    int monsterdamagemin[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int monsterdefensemax[16] = {2, 7, 13, 13, 20, 20, 25, 25, 35, 35, 40, 40, 45, 45, 55, 55};
    int monsterdefensemin[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int monsterhealth[16] = {32, 52, 73, 73, 95, 95, 118, 118, 142, 142, 167, 167, 193, 193, 220, 220};
    int monsterspeed[16] = {7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15};
    int monstergold[16] = {20, 30, 41, 41, 53, 53, 66, 66, 80, 80, 95, 95, 110, 110, 125, 125};

理想情况下,我希望能够从CSV文件中获得所有这些,如:

mID mName   mDmgMax mDmgMin mDefMax mDefMin mHp mSpeed  mGold
1   Wolf    32  0   2   0   32  7   20
2   Bear    42  0   7   0   52  8   30
3   Bandit  53  0   13  0   73  9   41
4   Traveler    53  0   13  0   73  9   41
5   Gargoyle    65  0   20  0   95  10  53
6   Knight  65  0   20  0   95  10  53
7   Warlock 75  0   25  0   118 11  66
8   Mammoth 75  0   25  0   118 11  66
9   Cyclops 85  0   35  0   142 12  80
10  Unicorn 85  0   35  0   142 12  80
11  Dragon  90  0   40  0   167 13  95
12  Your Mother 90  0   40  0   167 13  95
13  Demon   95  0   45  0   193 14  110
14  Jesus   95  0   45  0   193 14  110
15  Statan  110 0   55  0   220 15  125
16  God 110 0   55  0   220 15  125

写一个小的基于命令的应用程序,为你创建记录,在你的"主"程序是游戏,你只需要读取这些记录。

结构示例-

struct monster
{
  int mID;
  char mName[25]; //from your code
  int mDmgMax;
  //and these as well mDmgMin mDefMax mDefMin mHp mSpeed  mGold
};
这个"助手"程序中的

逐个读取记录中的每个数据项(如mName),并插入到这个结构中。将结构写入monsters.dat文件

std::ofstream fout;
fout.open("monsters.dat", std::ios::app | std::ios::binary);    
fout.write( (char*) &monsterInstance, sizeof(monsterInstance) );
fout.close();

这将简单地附加记录。(我跳过了错误检查和读取数据。)为了更方便,这个程序应该能够显示当前的怪物,添加怪物,删除怪物(通过进入mID)。

在主程序中读取这样的记录应该是一件容易的事。

如果要保存大量基于表的数据,可以考虑使用SQLite。它有一些有趣的成本和收益。

缺点(也许)是SQL。它可能会更复杂,根据你的搜索算法,可能会更慢。它也不能手工编辑,你需要一些东西来打开数据库(有免费的工具可用)。

从好的方面来说,你可以获得数据库的所有排序和过滤功能(任何你需要的东西,比如spell='fireball' AND damage < 5),而且SQLite (很容易存储游戏数据,而且可能比你自己的代码快得多)。您可以将所有数据存储在一个文件中,以便于部署或修改,每种类型(武器,咒语,字符等)都有唯一的表,并且不涉及服务器(SQLite是一个单独的DLL)。

关系数据库擅长处理一致形式的数据表,这正是你在游戏环境中所拥有的(每种对象类型都有几个字段,没有太多变化,可能有些空白,具有各种数据类型)。尽管SQLite是最小的数据库,但它可以在极短的时间内处理数千行,所以你不必担心你的游戏数据变得笨拙(这在纯文本表文件中很快就会发生,比如NWN(2)的2DA格式)。

有一个学习曲线,但你确实在将来获得一些简单性(添加一个新的对象类型是一个新的表和查询,而不是大量的代码)和一个非常稳定的数据格式和加载/保存库。根据你的需要,这可能值得一试。

正如问题评论所指出的,如果您真的想要处理CSV文件,您应该选择<fstream>。使用这种方法,getline应该足以满足您的需要。

我使用Boost来解析我使用的CSV文件。下面是一个简单的例子。

我同意peachykeen的观点,SQLite可能更适合你,但也许这将帮助你开始。

#include <iostream>
#include <fstream>
#include <vector>
#include <boost/tokenizer.hpp>
#include <boost/token_functions.hpp>
typedef std::vector<std::string> csvLine;
typedef std::vector<csvLine> csvLines;
typedef boost::tokenizer<boost::escaped_list_separator<char> > csvTokenizer;
csvLines ReadCSVFile(const std::string& fileName)
{
    csvLines retVec;
    std::ifstream inFile(fileName.c_str());
    if(inFile)
    {
        std::string fileLine;
        while(std::getline(inFile, fileLine))
        {
            csvTokenizer lineTokens(fileLine);
            retVec.push_back(csvLine(lineTokens.begin(), lineTokens.end()));
        }
        inFile.close();
    }
    return retVec;
}
int main(int argc, char** argv) 
{
    csvLines lines(ReadCSVFile(argv[1]));
    for(csvLines::iterator lineIt = lines.begin(); lineIt != lines.end(); ++lineIt)
    {
        for(csvLine::iterator tokenIt = (*lineIt).begin(); tokenIt != (*lineIt).end(); ++tokenIt)
        {
            std::cout << *tokenIt << " ";
        }
        std::cout << std::endl;
    }
    return 0;
}