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

发布于 2024-10-11 07:32:40 字数 914 浏览 3 评论 0 原文

我一直通过深入研究一个项目(一个简单的 2d 游戏)来学习 C++。我试图实现一组作弊,但我在字符串操作方面真的是新手。我确信会有一种比下面的代码更优雅的方式来实现我想要的目标。

根据要求,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”。我不禁想到这可能会好得多。任何见解将不胜感激。

I have been learning C++ by diving into a project, a simple 2d game. I have attempted to implement a set of cheats but I'm seriously novice at string manipulation. I'm sure there would be a more elegant way to achieve what I would like than my code below.

As requested, stringBuffer is just a string that contains the last 12 pressed characters. I prepend it because it's trimmed at the end later with resize, and hence my cheats have to be backwards. I'm very much a noob at string manipulation, and I know something is wrong here, which I why I asked for it to be looked at and possibly improved.

//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;
        }
    }
}

The codes are "cheat1", "cheat2" and "cheat3" respectively. I can't help thinking that this could be a lot better. Any insight would be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

坦然微笑 2024-10-18 07:32:40

您可能需要考虑使用:

std::map> (如果您可以使用 C++0x)

std ::map> (如果可以使用 TR1)

std::map> (如果可以使用 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!

现场演示

You might want to consider using:

std::map<std::string, std::function<void ()>> (If you can use C++0x)

std::map<std::string, std::tr1::function<void ()>> (If you can use TR1)

std::map<std::string, boost::function<void ()>> (If you can use Boost)

(Of course, the signature of the function can differ)

Example using 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]();
        }
    }
}

Input:

notourcheat
cheat1
cheat2
cheat1

Output:

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

Live demo

塔塔猫 2024-10-18 07:32:40

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

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

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

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

当您查找一个字符串时,您只需检查该字符串是否包含在带有作弊代码的特里树中。如果是,您将获得附加数据(例如,指向执行您想要执行的操作的函数的函数指针;或更面向对象:指向类实例的指针,当您调用其成员函数之一时,该指针会执行“作弊”操作东西”)。

I would store the strings in a trie:

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

(in the Wikipedia article there are also links to C++ implementations).

In the leafs of the trie you can add additional data concerning the cheat.

When you lookup a string you simple check whether the string is contained in the trie with the cheat codes. If yes, you get the additional data (for example a function pointer to a function that does what you want to do; or more Object-Oriented: a pointer to a class instance that when you call one of its member functions does the "cheating stuff").

百合的盛世恋 2024-10-18 07:32:40

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

将不可变字符串设为常量静态

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:
    }
}

This code can be improved in several ways.

Make your immutable strings const static

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

So they don't have to be allocated every time in your "KeyPressed" handler.

Associate each cheat with a value that you can use in a case statement

I don't think all the additional logic to facilitate the switch is a good idea. What about something like this:

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),
};

This way you get an integer which you can use as a case label for each of your cheat codes.

Search for the cheat to activate

You want to be able to search for a cheat code that has been activated easily. Let's break up the std::pair instances and use a std::map instead.

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]));

Now, assuming that candidate is your keypress buffer, you can just do

auto pair = cheatmap.find(candidate);
if (pair != cheatmap.end()) {
    switch(pair->second) {
        case CHEAT_ONE:
        case CHEAT_TWO:
        case CHEAT_THREE:
    }
}
北城半夏 2024-10-18 07:32:40

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

I would do it this way: when pressing some specific button first, for example enter, it would start to fill the cheatBuffer, and after one char was filled in the end of the buffer, it would use that buffer to check if a value of it exists in an std::map. And when that value exists, it would execute a function, which pointer was stored in std::map.

赤濁 2024-10-18 07:32:40

这可能有点矫枉过正,工作量太大,但您可以制作一个有限状态机来处理您的关键输入,存储当前状态而不是存储关键历史记录。您的起始状态 0 表示没有按下任何适用的键。 'c' 将使您进入状态 1,其中 'h' 将使您进入状态 2,'c' 将使您保持在状态 1,而其他任何内容都会使您返回到 0。因此,在给定的按键上,您打开当前状态,并在其中打开提供的角色以查看您转换到哪个状态。如果是最终状态,则执行作弊并转换回 0。

This might be overkill and too much work, but you could make a finite state machine to handle your key inputs, storing your current state instead of storing a key history. Your starting state 0 represents no applicable keys pressed. A 'c' will put you into state 1, where an 'h' will bring you to state 2, a 'c' will keep you at state 1, and anything else will send you back to 0. So on a given keypress you switch on the current state, and inside of that, switch on the character supplied to see which state you transition into. If it was a final state then execute the cheat and transition back to 0.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文