在 C++ 中将二维数组用于游戏地图
Using a 2D array for a game map in C++
软件:Visual Studio 2017 社区
大家好,
我正在用 C++ 制作一个简单的 2d 控制台游戏(如果你知道的话,可能是非常简化的矮人要塞)。
而且我希望地图以 ASCII 码显示在控制台中。
像这样:
我在头文件(简化版)中声明了一个 WorldMap class。
我在其中声明了一个二维数组。
#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
};
然后在.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
}
这就是我想要实现的基本理念。之所以不能立即定义数组大小是因为我希望在创建地图时能够选择地图的大小。
我已经试过了:
- 上面的代码。
错误:
error C2109: subscript requires array or pointer type
- 将二维数组声明为
char worldMap[][];
,然后将其定义为 worldMap[50][50];
。
错误:
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
- 将二维数组声明为
char worldMap[worldWidth][worldHeight];
,期望在创建对象时,首先定义宽度和高度变量,然后再定义数组。
错误:
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
- 使用
char* worldMap;
和 char** worldMap
,但到目前为止我什至无法理解双指针的工作原理,但 char* worldMap
实际上可以毫无错误地使用一维数组,直到我开始访问数组中元素的值。
我想一个解决方法是使用字符串或一维字符数组,并且在显示它时只需使用 mapWidth 以每 50 个字符结束一行,这将给出相同的结果。但我觉得这不是实现此目标的好方法,因为我需要访问这张地图的 x 和 y 坐标等等。
我想我问的是:
- 为 class 声明二维数组然后在对象中定义它的最佳方法是什么?
- 为此类主机游戏存储地图的最佳方式是什么? (不一定使用数组)
感谢您的阅读。我将非常感谢任何帮助,即使只是想法和提示也可能将我推向正确的方向:)
做任何事情都没有最好的方法*。这是最适合你的。
据我了解,您想制作一个动态二维数组来保存您的世界地图字符。你有很多选择来做到这一点。你可以有一个 worldMap class 没有错。如果你想要动态 2D 数组,只需从这种逻辑中创建函数。
#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;
}
- What's the best way of declaring a 2d array for a class and then defining it in the object?
- What's the best way to store a map for such a console game? (Not necessarily using arrays)
这不是“最佳方式”,但它是一种方式。
- 创建一个
class
包裹一维 std::vector<char>
。
- 添加
operator()
以访问各个元素。
- 添加杂项。
class
的其他支持功能,如 save()
和 restore()
.
我以你的 class
为基础,并试图记录它在代码中的作用:如果我使用的某些功能不熟悉,我建议在 https://en.cppreference.com/ 这是一个优秀的 wiki,经常有关于如何使用您阅读的特定功能的示例。
#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;
};
软件:Visual Studio 2017 社区
大家好,
我正在用 C++ 制作一个简单的 2d 控制台游戏(如果你知道的话,可能是非常简化的矮人要塞)。
而且我希望地图以 ASCII 码显示在控制台中。
像这样:
我在头文件(简化版)中声明了一个 WorldMap class。 我在其中声明了一个二维数组。
#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
};
然后在.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
}
这就是我想要实现的基本理念。之所以不能立即定义数组大小是因为我希望在创建地图时能够选择地图的大小。
我已经试过了:
- 上面的代码。
错误:
error C2109: subscript requires array or pointer type
- 将二维数组声明为
char worldMap[][];
,然后将其定义为worldMap[50][50];
。
错误:
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
- 将二维数组声明为
char worldMap[worldWidth][worldHeight];
,期望在创建对象时,首先定义宽度和高度变量,然后再定义数组。
错误:
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
- 使用
char* worldMap;
和char** worldMap
,但到目前为止我什至无法理解双指针的工作原理,但char* worldMap
实际上可以毫无错误地使用一维数组,直到我开始访问数组中元素的值。
我想一个解决方法是使用字符串或一维字符数组,并且在显示它时只需使用 mapWidth 以每 50 个字符结束一行,这将给出相同的结果。但我觉得这不是实现此目标的好方法,因为我需要访问这张地图的 x 和 y 坐标等等。
我想我问的是:
- 为 class 声明二维数组然后在对象中定义它的最佳方法是什么?
- 为此类主机游戏存储地图的最佳方式是什么? (不一定使用数组)
感谢您的阅读。我将非常感谢任何帮助,即使只是想法和提示也可能将我推向正确的方向:)
做任何事情都没有最好的方法*。这是最适合你的。
据我了解,您想制作一个动态二维数组来保存您的世界地图字符。你有很多选择来做到这一点。你可以有一个 worldMap class 没有错。如果你想要动态 2D 数组,只需从这种逻辑中创建函数。
#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;
}
- What's the best way of declaring a 2d array for a class and then defining it in the object?
- What's the best way to store a map for such a console game? (Not necessarily using arrays)
这不是“最佳方式”,但它是一种方式。
- 创建一个
class
包裹一维std::vector<char>
。 - 添加
operator()
以访问各个元素。 - 添加杂项。
class
的其他支持功能,如save()
和restore()
.
我以你的 class
为基础,并试图记录它在代码中的作用:如果我使用的某些功能不熟悉,我建议在 https://en.cppreference.com/ 这是一个优秀的 wiki,经常有关于如何使用您阅读的特定功能的示例。
#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;
};