首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >游戏库存系统

游戏库存系统
EN

Stack Overflow用户
提问于 2020-04-06 02:54:44
回答 2查看 554关注 0票数 2

我正在尝试用C++为我正在开发的一款游戏建立一个库存系统。然而,当我调用Inventory::AddItem(Item i)时,库存系统中有一个bug,没有添加任何物品,并且该插槽仍然为空。目前,我通过std::vector<Item>处理库存,其中Item是一个结构,其中包含类型(如果它是可堆叠的)、堆栈中的最大块数、堆栈中的当前块数以及几个用于动画的对象。此外,我自动使用40个空块填充库存,这些空块的ID为INVENTORY_EMTPY_SLOT_ID.

代码如下:

代码语言:javascript
复制
    typedef struct item {
        int type;    // this is whether the block is a foreground of background tile
        int id;      // use this for the id of objects
        bool stackable;   // true indicates that the block can be stacked
        int max_num;      // maximum number of blocks in a stack
        int num;          // the current number of blocks in the stack
        Animation* use_animation;    // the animation of the block or item when it is being used
        Animation* other_animation;  // secondary animation of item in case it is necessary
    } Item;

如何初始化空槽:

代码语言:javascript
复制
    for (size_t x = 0; x < INVENTORY_MAX_SLOTS; x++) {
        Item i = {0, INVENTORY_EMPTY_SLOT_ID, true, 1, 1, NULL, NULL};
        this->items.push_back(i);
    }

添加项目

代码语言:javascript
复制
/*********BUG HERE:******************/
void Inventory::AddItem(Item item) {
    // find all indexes with the same item.id
    std::vector<size_t> indexes_w_same_item;
    for (size_t i = 0; i < this->items.size(); i++) {
        if (this->items[i].id == item.id) {
            indexes_w_same_item.push_back(i);
        }
    }

    // find the next empty slot
    int next_empty_slot = -1;
    for (size_t i = 0; i < this->items.size(); i++) {
        if (this->items[i].id == INVENTORY_EMPTY_SLOT_ID) {
            next_empty_slot = i;
        }
    }

    // go through all the indexes with the same item.id
    // and see if at least one of them is empty.
    // if one is empty and has sufficient capacity,
    // add the item and return. if it isn't, keep moving forward
    for (size_t x = 0; x < indexes_w_same_item.size(); x++) {
        if (item.id == this->items[indexes_w_same_item[x]].id) {
            if (this->items[indexes_w_same_item[x]].num + item.num <= this->items[indexes_w_same_item[x]].max_num) {
                this->items[indexes_w_same_item[x]].num += item.num;
                return;
            }
        }
    }

    // if there is an empty slot, make a new stack
    if (next_empty_slot >= 0) {
        this->items[next_empty_slot].id = item.id;
        this->items[next_empty_slot].max_num = item.max_num;
        // clamp item.num so it doesn't exceed item.max_num
        if (item.max_num > item.num) {
            this->items[next_empty_slot].num = item.num;
        } else {
            this->items[next_empty_slot].num = item.max_num;
        }
    }
}
EN

回答 2

Stack Overflow用户

发布于 2020-04-06 04:43:09

我知道你已经发现了这个错误,但是你的代码中有许多问题导致了这个错误,我想帮助你理解如何写出更好的代码,所以下次你会更容易找到它(甚至可以避免它!)。

  1. 你应该把逻辑分成尽可能小的部分--模块化是让代码更加清晰和整洁的关键,它可以帮助你理解清晰流程的错误,你可以断断续续地创建两个截然不同的流程。当您耗尽一个可能的流,然后才启动另一个流时,代码会清晰得多(看看函数add_item_to_existing_stack_if_possibleadd_item_to_new_stack_if_possible.
  2. Your变量/函数/类的名称必须代表它们所代表的内容,但原始代码并非如此!)(就我个人而言,我根本没有使用注释)
  3. C++不是带有类的C语言-像typedef这样的东西不应该出现在你的代码中,你应该使用operator<<代替std::cout,依此类推。
  4. 确保你尽可能地添加常量说明符,它可以帮助发现编译时的许多错误(并使你的程序运行faster).
  5. Performance相关的-你应该尽可能多地传递对象作为引用,传递一个uint64 (内存位置)比复制整个Item对象快得多。<代码>H220<代码>G221

代码语言:javascript
复制
#include <vector>
#include <array>
#include <iostream>

struct Animation;

struct Item {
    int type;
    int id;
    bool is_stackable;
    int max_num_blocks_in_stack;
    int curr_num_of_blocks_in_stack;
    Animation* used_animation; // if it is non nullable, you should consider to use it without a pointer (possibly a reference)
    Animation* secondary_animation; // nullable - can be a pointer or std::optional
};

class Inventory
{
public:
    bool add_item(Item&& item);

private:
    bool is_slot_empty(size_t idx) const { return items[idx].id == INVENTORY_EMPTY_SLOT_ID; }
    std::vector<size_t> find_indexes_of(const Item& item) const;
    size_t find_next_empty_slot() const;

    bool add_item_to_existing_stack_if_possible(const Item& item);
    bool add_item_to_new_stack_if_possible(Item&& item);

    void print() const;

    static constexpr size_t MAX_INV_SIZE = 40; // can transform into a class template!

    std::array<Item, MAX_INV_SIZE> items;

    static constexpr int INVENTORY_EMPTY_SLOT_ID = -1;
};

std::vector<size_t> Inventory::find_indexes_of(const Item& item) const
{
    std::vector<size_t> indexes{};

    for (size_t idx = 0; idx < MAX_INV_SIZE; ++idx) 
    {
        if (items[idx].id == item.id) 
        {
            indexes.push_back(idx);
        }
    }

    return indexes;
}

size_t Inventory::find_next_empty_slot() const
{
    for (size_t idx = 0; idx < MAX_INV_SIZE; ++idx) 
    {
        if (is_slot_empty(idx)) 
        {
            return idx;
        }
    }

    return MAX_INV_SIZE; // invalid value!
}

void Inventory::print() const
{
    for (size_t i = 0; i < MAX_INV_SIZE; ++i) 
    {
        if (this->items[i].id != INVENTORY_EMPTY_SLOT_ID)
        {
            std::cout << "Inventory slot: " << i << "\n"
                      << "Item ID: " << items[i].id << "\n"
                      << "Item Num: " << items[i].curr_num_of_blocks_in_stack << "\n"
                      << "Item Max Num: " << items[i].max_num_blocks_in_stack << std::endl;
                      //<< "Item Texture: " << textures[items[i].id] << std::endl;
        }
    }
}

bool Inventory::add_item_to_existing_stack_if_possible(const Item& item)
{
    auto indexes_with_same_item = find_indexes_of(item);

    for (auto idx : indexes_with_same_item) 
    {
        if (item.id == items[idx].id) 
        {
            if (items[idx].curr_num_of_blocks_in_stack + item.curr_num_of_blocks_in_stack <= 
                items[idx].max_num_blocks_in_stack) 
            {
                items[idx].curr_num_of_blocks_in_stack += item.curr_num_of_blocks_in_stack;
                return true;
            }
        }
    }

    return false;
}

bool Inventory::add_item_to_new_stack_if_possible(Item&& item)
{
    size_t next_empty_slot = find_next_empty_slot();

    if (next_empty_slot >= 0) 
    {
        this->items[next_empty_slot] = std::move(item);

        return true;
    }

    return false;
}

bool Inventory::add_item(Item&& item) 
{
    bool was_possible_to_add_to_existing_stack = add_item_to_existing_stack_if_possible(item);

    if (!was_possible_to_add_to_existing_stack)
    {
        return add_item_to_new_stack_if_possible(std::move(item));
    }

    return false;
}
票数 1
EN

Stack Overflow用户

发布于 2020-04-06 03:36:35

好吧,我想通了。在第二个for循环的末尾必须有一个中断,它在其中查找下一个空插槽,否则,它将检测到下一个空插槽作为库存中的最后一个插槽,假设您正在库存中添加第一个项目。因此,该项目没有显示在跳栏中。

以下是正确的解决方案:

代码语言:javascript
复制
void Inventory::AddItem(Item item) {
// find all indexes with the same item.id
std::vector<size_t> indexes_w_same_item;
for (size_t i = 0; i < this->items.size(); i++) {
    if (this->items[i].id == item.id) {
        indexes_w_same_item.push_back(i);
    }
}

// find the next empty slot
int next_empty_slot = -1;
for (size_t i = 0; i < this->items.size(); i++) {
    if (this->items[i].id == INVENTORY_EMPTY_SLOT_ID) {
        next_empty_slot = i;
        break;
    }
}

// go through all the indexes with the same item.id
// and see if at least one of them is empty.
// if one is empty and has sufficient capacity,
// add the item and return. if it isn't, keep moving forward
for (size_t x = 0; x < indexes_w_same_item.size(); x++) {
    if (item.id == this->items[indexes_w_same_item[x]].id) {
        if (this->items[indexes_w_same_item[x]].num + item.num <= this->items[indexes_w_same_item[x]].max_num) {
            this->items[indexes_w_same_item[x]].num += item.num;
            return;
        }
    }
}

// if there is an empty slot, make a new stack
if (next_empty_slot >= 0) {
    this->items[next_empty_slot] = item;
}

for (size_t i = 0; i < INVENTORY_MAX_SLOTS; i++) {
    if (this->items[i].id != '.') {
        printf("\nInventory slot: %d\n", i);
        printf("Item ID: %c\n", this->items[i].id);
        printf("Item Num: %d\n", this->items[i].num);
        printf("Item Max Num: %d\n", this->items[i].max_num);
        printf("Item Texture: %x\n", this->textures[this->items[i].id]);
    }
}


return;

}

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61047811

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档