首页 > 解决方案 > 文字冒险游戏 - 如何区分一个项目类型和另一个项目类型以及如何构建项目类/子类?

问题描述

我是一名初级程序员(他有很多与设计相关的视频游戏脚本编写经验,但编程经验很少——所以只是基本的东西,比如循环、流控制等——尽管我确实有 C++ 基础和 C++ 数据结构和算法的课程在我的带领下)。我正在从事一个文本冒险的个人项目(实际上,在我了解类如何工作之前,我早在很久以前就已经用 Python 编写了它——一切都是字典——所以这很可耻)。我正在用 C++ 用类“改造”它,以摆脱只做家庭作业的习惯。

我已经编写了我的播放器和房间类(这很简单,因为我只需要一个类)。我正在研究物品类别(物品是房间里的任何东西,例如手电筒、火、标志、容器等)。我不确定如何处理项目基类和派生类。这是我遇到的问题。

  1. 我如何以一种不废话的方式判断一个项目是否属于某种类型(很有可能我想多了)?

    • 例如,我设置了我的打印室信息功能,以便除了它可能执行的任何其他操作之外,它还打印其库存中的每个对象的名称(即其中的),并且我希望它为容器对象打印一些特殊的东西(例如其库存的内容)。
    • 第一部分很简单,因为每个项目都有一个名称,因为 name 属性是基本项目类的一部分。容器有一个清单,这是容器子类独有的属性。
    • 我的理解是,基于对象的类类型执行条件逻辑是一种不好的形式(因为一个类应该是多态的)并且我假设(可能不正确)将 getHasInventory 访问器虚函数放入其中是很奇怪和错误的item 基类(我的假设是基于认为在基类中为每个派生类放置虚函数会很疯狂——我有大约十几个派生类——其中几个是派生类的派生类)。
    • 如果这一切都正确,那么可以接受的方法是什么?一件显而易见的事情是将 itemType 属性添加到基础,然后执行条件逻辑,但这让我觉得是错误的,因为它似乎只是对检查类类型解决方案的重新设计。我不确定上述假设是否正确以及一个好的解决方案可能是什么。
  2. 我应该如何构建我的基类/类和派生类?

    • 我最初编写它们时,项目类是基类,而大多数其他类都使用单继承(除了一对具有多级的类)。
    • 这似乎呈现出一些尴尬和重复我自己。例如,我想要一个标志和一封信。标志是可读物品 > 不可取物品 > 物品。一封信是一个可读项目 > 可携带项目 > 项目。因为它们都使用单一继承,所以我需要两个不同的可读项,一个是可接收的,一个不是(我知道在这种情况下我可以将可接收和不可接收的属性设置为基础的属性,我做到了,但这只是一个例子,因为我仍然与其他类有类似的问题)。
    • 这对我来说似乎很恶心,所以我又试了一下,并使用多重继承和虚拟继承来实现它们。就我而言,这似乎更灵活,因为我可以组合多个类并为我的类创建一种组件系统。
    • 这些方法中的一种是否比另一种更好?有没有更好的第三种方法?

标签: c++game-developmentadventure

解决方案


解决问题的一种可能方法是polymorphism。通过使用多态性,您可以(例如)拥有一个describe函数,当调用该函数时,该函数会引导项目向玩家描述自身。您可以对use, 和其他常见动词执行相同的操作。


另一种方法是实现更高级的输入解析器,它可以识别对象并将动词传递给项目的某些(多态)函数以供自己处理。例如,每个项目可以有一个返回可用动词列表的函数,以及一个返回项目“名称”列表的函数:

struct item
{
    // Return a list of verbs this item reacts to
    virtual std::vector<std::string> get_verbs() = 0;

    // Return a list of name aliases for this item
    virtual std::vector<std::string> get_names() = 0;

    // Describe this items to the player
    virtual void describe(player*) = 0;

    // Perform a specific verb, input is the full input line
    virtual void perform_verb(std::string verb, std::string input) = 0;
};

class base_torch : public item
{
public:
    std::vector<std::string> get_verbs() override
    {
        return { "light", "extinguish" };
    }

    // Return true if the torch is lit, false otherwise
    bool is_lit();

    void perform_verb(std::string verb, std::string) override
    {
        if (verb == "light")
        {
            // TODO: Make the torch "lit"
        }
        else
        {
            // TODO: Make the torch "extinguished"
        }
    }
};

class long_brown_torch : public base_torch
{
    std::vector<std::string> get_names() override
    {
        return { "long brown torch", "long torch", "brown torch", "torch" };
    }

    void describe(player* p) override
    {
        p->write("This is a long brown torch.");
        if (is_lit())
            p->write("The torch is burning.");
    }
};

然后,如果玩家输入light brown torch,例如解析器查看所有可用物品(玩家库存中的物品,然后是房间中的物品),则获取每个物品名称列表(调用 itemsget_names()函数)并将其与brown torch. 如果找到匹配项,则解析器调用 itemsperform_verb函数并传递适当的参数 ( item->perform_verb("light", "light brown torch"))。

the您甚至可以修改解析器(和项目)以单独处理形容词,甚至像it.

构建不同的房间和物品是乏味的,但一旦做出了好的设计(你真的应该花一些时间创建需求、分析需求和创建设计)。真正困难的部分是编写一个像样的解析器。


请注意,这只是在此类游戏中处理项目和动词的两种可能方法。还有很多其他的方法,很多人都列出来了。


推荐阅读