有没有更优雅的方法来实现C ++游戏的“作弊代码”实现?

时间:2011-01-10 21:57:04

标签: c++ refactoring

我一直在学习C ++,潜入一个简单的2D游戏项目。我试图实现一组作弊,但我是字符串操作的新手。我确信有一种更优雅的方式来实现我想要的,而不是我的代码。

根据要求,stringBuffer只是一个包含最后12个按下字符的字符串。我在前面加了它,因为它在最后调整后调整大小,因此我的作弊必须向后。我非常喜欢字符串操作,我知道这里有些问题,我为什么要求它被查看并可能改进。

//The following code is in my keyPressed function
cheatBuffer = (char)key + cheatBuffer;
cheatBuffer.resize(12);
string tempBuffer;
string cheats[3] = {"1taehc","2taehc","3taehc"};
for(int i = 0;i < 3;i++){
    tempBuffer = cheatBuffer;
    tempBuffer.resize(cheats[i].size());
    if(cheats[i] == tempBuffer){
        switch(i){
            case 1:
                //activate cheat 1
                break;
            case 2:
                //active cheat 2
                break;
            case 3:
                //active cheat 3
                break;
        }
    }
}

代码分别是“cheat1”,“cheat2”和“cheat3”。我不禁想到这可能会好得多。任何见解将不胜感激。

5 个答案:

答案 0 :(得分:5)

您可能需要考虑使用:

std::map<std::string, std::function<void ()>>(如果你可以使用C ++ 0x)

std::map<std::string, std::tr1::function<void ()>>(如果你可以使用TR1)

std::map<std::string, boost::function<void ()>>(如果你可以使用Boost)

(当然,功能的签名可以不同)

使用C ++ 0x的示例

#include <map>
#include <functional>
#include <string>
#include <iostream>

typedef std::map<std::string, std::function<void ()>> cheat_map;

inline void cheat1()
{
    std::cout << "cheat 1 used!" << std::endl;
}

inline void cheat2()
{
    std::cout << "cheat 2 used!" << std::endl;
}

int main()
{
    cheat_map myCheats;
    myCheats.insert(std::pair<std::string, std::function<void ()>>("cheat1", std::function<void ()>(cheat1)));
    myCheats.insert(std::pair<std::string, std::function<void ()>>("cheat2", std::function<void ()>(cheat2)));

    std::string buffer;
    while (std::getline(std::cin, buffer)) {
        if (!std::cin.good()) {
            break;
        }

        cheat_map::iterator itr = myCheats.find(buffer);
        if (itr != myCheats.end()) {
            myCheats[buffer]();
        }
    }
}

输入:

notourcheat
cheat1
cheat2
cheat1

输出:

cheat 1 used!
cheat 2 used!
cheat 1 used!

Live demo

答案 1 :(得分:2)

我会将字符串存储在trie中:

http://en.wikipedia.org/wiki/Trie

(在维基百科文章中也有链接到C ++实现)。

在特里的叶子中,您可以添加有关作弊的其他数据。

当您查找字符串时,您可以使用作弊码检查字符串是否包含在trie中。如果是,则获取附加数据(例如,指向执行您想要执行的操作的函数的函数指针;或更多面向对象:指向类实例的指针,当您调用其成员函数之一时,会执行“作弊”东西“)。

答案 2 :(得分:2)

可以通过多种方式改进此代码。

使你的不可变字符串const static

static const std::string const foo[] = { "1taehc", "2taehc", "3taehc" };

因此,不必每次都在“KeyPressed”处理程序中分配它们。

将每个作弊与您可以在case声明

中使用的值相关联

我认为促进switch的所有额外逻辑都不是一个好主意。这样的事情怎么样:

const int CHEAT_ONE = 1;
const int CHEAT_TWO = 2;
const int CHEAT_THREE = 3;

static const std::pair<std::string, int> const foo[] = { 
    std::make_pair("1taehc", CHEAT_ONE),
    std::make_pair("2taehc", CHEAT_TWO),
    std::make_pair("3taehc", CHEAT_THREE),
};

通过这种方式,您可以获得一个整数,您可以将其用作每个作弊码的大小写标签。

搜索要激活的作弊

您希望能够搜索已轻松激活的作弊码。让我们分解std::pair个实例并改为使用std::map

const int CHEAT_ONE = 1;
const int CHEAT_TWO = 2;
const int CHEAT_THREE = 3;

std::pair<std::string, int> cheatcodes[] = {
    std::make_pair("1taehc", CHEAT_ONE),
    std::make_pair("2taehc", CHEAT_TWO),
    std::make_pair("3taehc", CHEAT_THREE),
};

std::map<std::string, int> cheatmap(
    cheatcodes, cheatcodes + sizeof (cheatcodes) / sizeof (cheatcodes[0]));

现在,假设candidate是您的按键缓冲区,您可以执行

auto pair = cheatmap.find(candidate);
if (pair != cheatmap.end()) {
    switch(pair->second) {
        case CHEAT_ONE:
        case CHEAT_TWO:
        case CHEAT_THREE:
    }
}

答案 3 :(得分:1)

我会这样做:当先按某个特定按钮时,例如输入,它会开始填充cheatBuffer,并且在缓冲区末尾填充一个字符后,它将使用该缓冲区来检查是否它的值存在于std :: map中。当该值存在时,它将执行一个函数,该指针存储在std :: map。

答案 4 :(得分:1)

这可能是一种过度杀伤和太多工作,但您可以创建一个有限状态机来处理您的键输入,存储您当前的状态而不是存储密钥历史记录。您的起始状态0表示没有按下适用的键。 'c'会让你进入状态1,其中'h'会将你带到状态2,'c'会让你保持在状态1,而其他任何东西都会让你回到0.所以在给定的按键上你打开当前状态,并在其中打开提供的字符,以查看您转换到的状态。如果它是最终状态,则执行作弊并转换回0。