简体   繁体   English

在 C++ 中使用 2D 数组进行游戏 map

[英]Using a 2D array for a game map in C++

Software: Visual Studio 2017 Community软件:Visual Studio 2017 社区

Hi, everybody,大家好你们好,

I am making a simple 2d console game in C++ (perhaps very simplified Dwarf Fortress if you know it).我正在 C++ 中制作一个简单的 2d 控制台游戏(如果你知道的话,也许是非常简化的矮人要塞)。

And I want a map to be displayed in console with ASCII.我希望 map 以 ASCII 显示在控制台中。

Something like this:像这样的东西:

在此处输入图像描述

I have a WorldMap class declared in the header file(simplified version).我在 header 文件(简化版)中声明了 WorldMap class。 And I declare a 2d array inside it.我在里面声明了一个二维数组。

#pragma once
#include <iostream>

class WorldMap
{
public:
    WorldMap();
    virtual ~WorldMap();

private:
    int worldWidth;
    int worldHeight;
    char worldMap;     // Declare a variable that will hold all the characters for the map
};

And then define it in the.cpp file:然后在.cpp文件中定义:

#include "WorldMap.h"
#include <algorithm>

WorldMap::WorldMap()
{
    worldWidth = 50;
    worldHeight = 50;
    worldMap[50][50];       // Define the map array
    // And then here I will also somehow need to be able to fill the whole map with '.' symbols, and so on
}

So that is the basic idea of what I am trying to achieve.这就是我想要实现的基本理念。 The reason why I can't define the array size immediately is because I want to be able to choose the size of the map when the map is created.我不能立即定义数组大小的原因是因为我希望能够在创建 map 时选择 map 的大小。

I have already tried:我已经尝试过:

  1. The code above.上面的代码。

Error:错误:

error C2109: subscript requires array or pointer type
  1. Declaring 2d array as char worldMap[][];将二维数组声明为char worldMap[][]; and then defining it as worldMap[50][50];然后将其定义为worldMap[50][50]; . .

Error:错误:

error C2087: 'worldMap': missing subscript
warning C4200: nonstandard extension used: zero-sized array in struct/union
message : This member will be ignored by a defaulted constructor or copy/move assignment operator
  1. Declaring 2d array as char worldMap[worldWidth][worldHeight];将二维数组声明为char worldMap[worldWidth][worldHeight]; , expecting that when the object is created, the width and height variables will be defined first, and then they will define the array. ,期望在创建object时,会先定义width和height变量,然后再定义数组。

Error:错误:

error C2327: 'WorldMap::worldWidth': is not a type name, static, or enumerator
error C2065: 'worldWidth': undeclared identifier
error C2327: 'WorldMap::worldHeight': is not a type name, static, or enumerator
error C2065: 'worldHeight': undeclared identifier
  1. Using char* worldMap;使用char* worldMap; and char** worldMap , but so far I can't even understand how double pointer works, yet char* worldMap actually works with a 1D array without errors, until I start accessing values of the elements in the array.char** worldMap ,但到目前为止我什至无法理解双指针是如何工作的,但char* worldMap实际上可以毫无错误地使用一维数组,直到我开始访问数组中元素的值。

I suppose a workaround would be to use a string or 1D char array and when displaying it just use mapWidth to end line each 50 characters for example, which will give the same result.我想一种解决方法是使用字符串或一维字符数组,并且在显示它时只需使用 mapWidth 来结束每 50 个字符的行,例如,这将给出相同的结果。 But I feel like that's not a good way to achieve this since I will need to access x and y coords of this map and so on.但我觉得这不是实现这一目标的好方法,因为我需要访问这个 map 等的 x 和 y 坐标。

I guess what I am asking is:我想我要问的是:

  1. What's the best way of declaring a 2d array for a class and then defining it in the object?为 class 声明二维数组然后在 object 中定义它的最佳方法是什么?
  2. What's the best way to store a map for such a console game?为这样的主机游戏存储 map 的最佳方式是什么? (Not necessarily using arrays) (不一定使用数组)

Thank you for reading.感谢您的阅读。 I will really appreciate any help, even just ideas and tips might push me in the right direction:)我将非常感谢任何帮助,即使只是想法和提示也可能将我推向正确的方向:)

  1. What's the best way of declaring a 2d array for a class and then defining it in the object?为 class 声明二维数组然后在 object 中定义它的最佳方法是什么?
  2. What's the best way to store a map for such a console game?为这样的主机游戏存储 map 的最佳方式是什么? (Not necessarily using arrays) (不一定使用数组)

This is not " the best way " but it's one way of doing it.这不是“最好的方式”,但它是一种方式。

  • Create a class wrapping a 1D std::vector<char> .创建一个包装一维std::vector<char>class
  • Add operator() s to access the individual elements.添加operator()以访问各个元素。
  • Add misc.添加杂项。 other support functions to the class , like save() and restore() . class的其他支持功能,例如save()restore()

I've used your class as a base and tried to document what it's doing in the code: If some of the functions I've used are unfamiliar, I recommend looking them up at https://en.cppreference.com/ which is an excellent wiki that often has examples of how to use the particular function you read about.我使用您的class作为基础,并尝试记录它在代码中的作用:如果我使用的某些功能不熟悉,我建议在https://en.cppreference.com/上查找它们一个出色的 wiki,其中经常包含有关如何使用您所读到的特定 function 的示例。

#include <algorithm>   // std::copy, std::copy_n
#include <filesystem>  // std::filesystem::path
#include <fstream>     // std::ifstream, std::ofstream
#include <iostream>    // std::cin, std::cout
#include <iterator>    // std::ostreambuf_iterator, std::istreambuf_iterator
#include <vector>      // std::vector

class WorldMap {
public:
    WorldMap(unsigned h = 5, unsigned w = 5) : // colon starts the initializer list
        worldHeight(h),      // initialize worldHeight with the value in h
        worldWidth(w),       // initialize worldWidth with the value in w
        worldMap(h * w, '.') // initialize the vector, size h*w and filled with dots.
    {}

    // Don't make the destructor virtual unless you use polymorphism
    // In fact, you should probably not create a user-defined destructor at all for this.
    //virtual ~WorldMap(); // removed

    unsigned getHeight() const { return worldHeight; }
    unsigned getWidth() const { return worldWidth; }

    // Define operators to give both const and non-const access to the
    // positions in the map.
    char operator()(unsigned y, unsigned x) const { return worldMap[y*worldWidth + x]; }
    char& operator()(unsigned y, unsigned x) { return worldMap[y*worldWidth + x]; }

    // A function to print the map on screen - or to some other ostream if that's needed
    void print(std::ostream& os = std::cout) const {
        for(unsigned y = 0; y < getHeight(); ++y) {
            for(unsigned x = 0; x < getWidth(); ++x)
                os << (*this)(y, x); // dereference "this" to call the const operator()
            os << '\n';
        }
        os << '\n';
    }

    // functions to save and restore the map
    std::ostream& save(std::ostream& os) const {
        os << worldHeight << '\n' << worldWidth << '\n'; // save the dimensions

        // copy the map out to the stream
        std::copy(worldMap.begin(), worldMap.end(), 
                  std::ostreambuf_iterator<char>(os));
        return os;
    }

    std::istream& restore(std::istream& is) {
        is >> worldHeight >> worldWidth;            // read the dimensions
        is.ignore(2, '\n');                         // ignore the newline
        worldMap.clear();                           // empty the map
        worldMap.reserve(worldHeight * worldWidth); // reserve space for the new map

        // copy the map from the stream
        std::copy_n(std::istreambuf_iterator<char>(is),
                    worldHeight * worldWidth, std::back_inserter(worldMap));
        return is;
    }

    // functions to save/restore using a filename
    bool save(const std::filesystem::path& filename) const {
        if(std::ofstream ofs(filename); ofs) {
            return static_cast<bool>(save(ofs)); // true if it suceeded
        }
        return false;
    }

    bool restore(const std::filesystem::path& filename) {
        if(std::ifstream ifs(filename); ifs) {
            return static_cast<bool>(restore(ifs)); // true if it succeeded
        }
        return false;
    }

private:
    unsigned worldHeight;
    unsigned worldWidth;

    // Declare a variable that will hold all the characters for the map
    std::vector<char> worldMap;
};

Demo演示

There is no best way to do anything*.没有最好的方法来做任何事情*。 It's what works best for you.这是最适合你的。

From what I understand you want to make a dynamic 2D arrays to hold your char of world map.据我了解,您想要制作一个动态的 2D arrays 来保存您的世界 map 的字符。 You have a lot of options to do this.你有很多选择来做到这一点。 You can have a worldMap class nothing wrong with that.你可以有一个世界地图 class 没有错。 If you want dynamic 2D arrays just make functions out of this kind of logic.如果您想要动态 2D arrays 只需使用这种逻辑制作函数即可。

#include <iostream>
#include <vector>

int main() {
    int H = 10, W = 20;
    char** map = NULL; //This would go in your class.H

    //Make a function to allocate 2D array 
    map = new char* [H];
    for (int i = 0; i < H; i++) {
        map[i] = new char[W];
    }
    //FILL WITH WHATEVER 
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            map[i][j] = 'A';
        }
    }
    //do what ever you want like normal 2d array 
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            std::cout << map[i][j] << " ";
        }
        std::cout << std::endl;
    }
    //Should always delete when or if you want to make a new one run time  
    for (int i = 0; i < H; i++)    
        delete[] map[i];
    delete[] map;              
    map = NULL;

    //Also you can use vectors
    std::cout << "\n\n With vector " << std::endl;
    std::vector<std::vector<char>> mapV; 

    //FILL WITH WHATEVER 
    for (int i = 0; i < H; i++) {
        std::vector<char> inner;
        for (int j = 0; j < W; j++) {
            inner.push_back('V');
        }
        mapV.push_back(inner);
    }
    //do what ever you want kind of like a normal array 
    //but you should look up how they really work 
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            std::cout << mapV[i][j] << " ";
        }
        std::cout << std::endl;
    }

    mapV.clear();

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM