视觉 一个简单的坦克C++游戏



我现在对c ++有点陌生,我必须编写一个控制台坦克游戏。我自己做了很多部分,大部分部分都没有错。这是我的坦克类:

    class Tank  {
    protected:
         string name;
         static int number;
         static int row;
         static int col;
         static char direction;
public:
    Tank(int _number, string _name, int _row, int _col, char _direction){
        this->name = _name;
        this->number = _number;
        setRow(_row);
        setCol(_col);
        setDirection(_direction);
    }
    ///////////////////////////////
    ///----GETTERS FUNCTIONS----///
    ///////////////////////////////
    char getdirection(){ return direction; }
    int getnumber(){ return number; }
    int getCol(){ return col; }
    int getRow(){ return row; }
    void setDirection(char _direction)
    {
        direction = _direction;
    }
    void setCol(int _col)
    {
        col = _col;
    }
    void setRow(int _row)
    {
        row = _row;
    }
    ////////////////////////
    ///To String Function///
    ////////////////////////
    string _toString(){
        string r = "";
        r = ("Tank No. " + toString(number + 1) + " " + name + " At (" + toString(row) + "," + toString(col) + ") " + direction);
        return r;
    }
};
int Tank::col = 0;
int Tank::row = 0;
int Tank::number = 0;
char Tank::direction = '';

问题是当我创建对象数组时,例如:

Tank *players[4];

因为我需要一个四人游戏和一个坦克对象,所以它只使用最后一个对象。以下是我想在每个回合使用的代码,让每个玩家说出他们将要做什么:

static char action;
        static int turn = 1;
        static Game game(*players, map);
        for (int count = 0; players[count] != NULL; count++)
        {
            clr_screen();
            gotoxy(100, 15); cout << "Turn " << turn;
            gotoxy(100, 16); cout << "Player " << players[count]->getnumber() + 1 << " Action: ";
            cin >> action;
            game.move(action, count);
        }
        turn++;

正如您可能看到的那样,代码存在问题。

您可能想知道,这是游戏类:

class Game{
private:
    Tank *p_tank[5];
    Map map;
public:
    Game(Tank *tanks, Map _map)
    {
        *p_tank = tanks; map = _map;
    }
    //Tank getTank(){ return p_tank; }
    Map getMap(){ return map; }

如果您需要完整的代码,它是:

    #include <iostream>
#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <fstream>
#include <sstream>
using namespace std;
void SetWindow(int Width, int Height)
{
    _COORD coord;
    coord.X = Width;
    coord.Y = Height;
    _SMALL_RECT Rect;
    Rect.Top = 0;
    Rect.Left = 0;
    Rect.Bottom = Height - 1;
    Rect.Right = Width - 1;
    HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);      // Get Handle
    SetConsoleScreenBufferSize(Handle, coord);            // Set Buffer Size
    SetConsoleWindowInfo(Handle, TRUE, &Rect);            // Set Window Size
}
void gotoxy(int x, int y)
{
    static HANDLE h = NULL;
    if (!h)
        h = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD c = { x, y };
    SetConsoleCursorPosition(h, c);
}
string toString(int x) {
    stringstream ss;
    ss << x;
    return ss.str();
}
class Tank  {
protected:
    string name;
     static int number;
     static int row;
     static int col;
     static char direction;
public:
    Tank(int _number, string _name, int _row, int _col, char _direction){
        this->name = _name;
        this->number = _number;
        setRow(_row);
        setCol(_col);
        setDirection(_direction);
    }
    ///////////////////////////////
    ///----GETTERS FUNCTIONS----///
    ///////////////////////////////
    char getdirection(){ return direction; }
    int getnumber(){ return number; }
    int getCol(){ return col; }
    int getRow(){ return row; }
    void setDirection(char _direction)
    {
        direction = _direction;
    }
    void setCol(int _col)
    {
        col = _col;
    }
    void setRow(int _row)
    {
        row = _row;
    }
    ////////////////////////
    ///To String Function///
    ////////////////////////
    string _toString(){
        string r = "";
        r = ("Tank No. " + toString(number + 1) + " " + name + " At (" + toString(row) + "," + toString(col) + ") " + direction);
        return r;
    }
};
int Tank::col = 0;
int Tank::row = 0;
int Tank::number = 0;
char Tank::direction = '';
class Bullet : public Tank{
private:
    Tank tank;
public:
    Tank getTank(){ return tank; }
    void setRow(int _row){ row = _row; }
    void setCol(int _col){ col = _col; }
    char getDirection(){ return direction; }
    string __toString(){
        string r = "";
        r = ("Bullet At (" + toString(row) + "," + toString(col) + ") From Tank No " + toString(number));
        return r;
    }
};
class Block{//Characters: according to legends Lines: 316 - 322
protected:
    int row;
    int col;
    char character;
public:
    Block(char block)
    {
        this->character = block;
    }
    virtual string _toString(){
        string r = "";
        r = (character + (" at (" + toString(row) + toString(col) + "). "));
        return r;
    }
    int getRow(){ return row; }
    int getCol(){ return col; }
    void setRow(int _row){ row = _row; }
    void setCol(int _col) { row = _col; }
    virtual char getCharacter() { return character; }
};
/*class Ground : public Block{
public:
Ground(){
character = '.';
Block block;
block.getCharacter();
}
};
class Wall : public Block{
public:
Wall(){
character = 'W';
Block block;
block.getCharacter();
}
};
class Box : public Block{
public:
Box(){
character = 'B';
Block block;
block.getCharacter();
}
};
class Ice : public Block{
public:
Ice(){
character = 'I';
Block block;
block.getCharacter();
}
};
class Trap : public Block{
public:
Trap(){
character = 'T';
Block block;
block.getCharacter();
}
};
class Random : public Block{
public:
Random(){
character = '?';
Block block;
block.getCharacter();
}
};
class Tblock : public Block{
public:
Tblock(){
character = 'T';
Block block;
block.getCharacter();
}
};*/
class Map{
private:
    int rows;
    int cols;
    static const int MaxSize = 100;
    Block *map[MaxSize][MaxSize];
public:
    Map(int row = MaxSize, int col = MaxSize){
        this->rows = row;
        this->cols = col;
        for (int i = 0; i < row; i++){
            for (int j = 0; j < col; j++)
                map[i][j] = new Block(' ');
        }
    }
    void edit(int row, int col, char legend)
    {
        if (legend == '%')//bullet sign
            map[row][col] = new Block('O');
        else if (legend == '0')
            map[row][col] = new Block('1');
        else if (legend == '1')
            map[row][col] = new Block('2');
        else if (legend == '2')
            map[row][col] = new Block('3');
        else if (legend == '3')
            map[row][col] = new Block('4');
        else if (legend == 'G' || legend == 'g')
            map[row][col] = new Block(' ');
        else if (legend == 'w' || legend == 'W')
            map[row][col] = new Block('W');
        else if (legend == '?')
            map[row][col] = new Block('?');
        else if (legend == 'B' || legend == 'b')
            map[row][col] = new Block('B');
        else if (legend == 'X' || legend == 'x')
            map[row][col] = new Block('X');
        else if (legend == 'I' || legend == 'i')
            map[row][col] = new Block('I');
        else
            map[row][col] = new Block('B');
        _toGUI(row, col);
    }
    void _toGUI(int x, int y)
    {
        int X = 7 + 8 * x;
        int Y = 6 + 4 * y;
        gotoxy(X, Y);
        cout << map[x][y]->getCharacter();
    }
    bool moveOk(int r, int c, char mov)
    {
        switch (mov)
        {
        case 'l':
            if (r - 1 < 0) return false;
            else return true;
            break;
        case 'r':
            if (r > rows - 2) return false;
            else return true;
            break;
        case 'd':
            if (c < cols - 1) return true;
            else return false;
            break;
        case 'u':
            if (c > 0) return true;
            else return false;
            break;
        }
    }
    int getRows(){ return cols; }
    int getCols(){ return rows; }
};
class Game{
private:
    Tank *p_tank[5];
    Map map;
public:
    Game(Tank *tanks, Map _map)
    {
        *p_tank = tanks; map = _map;
    }
    //Tank getTank(){ return p_tank; }
    Map getMap(){ return map; }
    void move(char move, int whoToPlay)
    {
        string wtp;
        wtp = toString(whoToPlay);
        int m_row, m_col;
        switch (move)
        {
        case 'l':
            m_row = p_tank[whoToPlay]->getRow() - 1;
            m_col = p_tank[whoToPlay]->getCol() - 1;
            if (map.moveOk(m_row, m_col, 'l')){
                map.edit(m_row, m_col, 'G');
                map.edit(--m_row, m_col, wtp[0]);
                p_tank[whoToPlay]->setRow(m_row + 1);
                p_tank[whoToPlay]->setCol(m_col + 1);
            }
            break;
        case 'r':
            m_row = p_tank[whoToPlay]->getRow() - 1;
            m_col = p_tank[whoToPlay]->getCol() - 1;
            if (map.moveOk(m_row, m_col, 'r')){
                map.edit(m_row, m_col, 'G');
                map.edit(++m_row, m_col, wtp[0]);
                p_tank[whoToPlay]->setRow(m_row + 1);
                p_tank[whoToPlay]->setCol(m_col + 1);
            }
            break;
        case 'd':
            m_row = p_tank[whoToPlay]->getRow() - 1;
            m_col = p_tank[whoToPlay]->getCol() - 1;
            if (map.moveOk(m_row, m_col, 'd')){
                map.edit(m_row, m_col, 'G');
                map.edit(m_row, ++m_col, wtp[0]);
                p_tank[whoToPlay]->setRow(m_row + 1);
                p_tank[whoToPlay]->setCol(m_col + 1);
            }
            break;
        case 'u':
            m_row = p_tank[whoToPlay]->getRow() - 1;
            m_col = p_tank[whoToPlay]->getCol() - 1;
            if (map.moveOk(m_row, m_col, 'u')){
                map.edit(m_row, m_col, 'G');
                map.edit(m_row, --m_col, wtp[0]);
                p_tank[whoToPlay]->setRow(m_row + 1);
                p_tank[whoToPlay]->setCol(m_col + 1);
            }
            break;
        }
    }
};
void draw_field(Map map)
{
    ////////////////////////
    //-------Border-------//
    ////////////////////////
    for (int i = 3; i <= 2 * (4 * map.getRows() + 3); i++)
    {
        gotoxy(i, 3);
        printf("%c", 219);
        gotoxy(i, (4 * map.getCols() + 7));
        printf("%c", 219);
    }
    for (int i = 6; i < (4 * map.getCols() + 7); i++){
        gotoxy(3, i);
        printf("%c", 219);
        gotoxy(2 * (4 * map.getRows() + 3), i);
        printf("%c", 219);
    }
    gotoxy(3, 5);
    printf("%c", 219);
    gotoxy(3, 4);
    printf("%c", 219);
    gotoxy(3, 4 * map.getCols() + 7);
    printf("%c", 219);
    gotoxy(2 * (4 * map.getRows() + 3), 4);
    printf("%c", 219);
    gotoxy(2 * (4 * map.getRows() + 3), 5);
    printf("%c", 219);
    gotoxy(2 * (4 * map.getRows() + 3), map.getCols() + 7);
    printf("%c", 219);
    //end of BORDER
    //****************\
    //---COORD GUI----\
    //****************\
    //numbers:
    int j = 1;
    int z = 1;
    for (int i = 8; i < 2 * (4 * map.getRows() + 3); i += 8)
    {
        gotoxy(i, 2); cout << j;
        j++;
    }
    for (int i = 6; i < (4 * map.getCols() + 6); i += 4)
    {
        gotoxy(1, i);
        cout << z;
        z++;
    }
    //lines:
    for (int j = 8; j < (4 * map.getCols() + 6); j += 4)
    for (int i = 4; i < 2 * (4 * map.getRows() + 3); i++)
    {
        gotoxy(i, j);
        cout << "-";
    }
    for (int j = 12, c = 0; c < 4 * map.getRows() / 4 - 1; j += 8, c++)
    for (int i = 4, t = 0; t < 4 * map.getCols() + 1; i++, t++)
    {
        Sleep(10);
        gotoxy(j, i);
        cout << "|";
    }
}
void clr_screen()
{
    for (int i = 100; i <= 136; i++){
        for (int j = 15; j <= 55; j++){
            gotoxy(i, j); cout << " ";
        }
    }
}
void legend()
{
    gotoxy(100, 2); cout << "Legends:             ";
    gotoxy(100, 4); cout << "Tanks: #tBullet: *";
    gotoxy(100, 5); cout << "Walls: WtRandom: ?";
    gotoxy(100, 6); cout << "Box: BtIce: I";
    gotoxy(100, 7); cout << "Trap: Xt";
    gotoxy(100, 9); cout << "Actions:";
    gotoxy(100, 10); cout << "U D L RtFire: F";
    gotoxy(100, 11); cout << "----------------------";
}
void action_display(string str, Map &map)
{
    Tank *players[5];
    char reply = 'n';
    if (str == "%edit%" || str == "%Edit%"){
        while (reply != 'y'){
            char legend; int c; int r;
            clr_screen();
            gotoxy(100, 14);
            cout << "Actions:";
            gotoxy(100, 15);
            cout << "Edit Section:";
            gotoxy(100, 16); cout << "Enter the legend: ";
            gotoxy(100, 17); cin >> legend;
            if (legend == '1' || legend == '2' || legend == '3' || legend == '4')
                legend = '!';
            gotoxy(100, 18); cout << "Col: "; cin >> r;
            gotoxy(100, 19); cout << "Row: "; cin >> c;
            map.edit(r - 1, c - 1, legend);
            gotoxy(100, 20); cout << "Done?(Y|N)"; cin >> reply;
        }
    }
    if (str == "%NewGame%")
    {
        static int P;
        string name;
        int r, c;
        clr_screen();
        gotoxy(100, 15);
        cout << "How many players?";
        cin >> P;
        if (P >= 4) P = 4;
        for (int i = 0; i < P; i++)
        {
            clr_screen();
            gotoxy(100, 16); cout << "Enter player " << i + 1 << " start: ";
            gotoxy(100, 17); cout << "col: "; cin >> r;
            gotoxy(100, 18); cout << "row: "; cin >> c;
            gotoxy(100, 19); cout << "Name: "; cin >> name;
            players[i] = new Tank(i, name, r, c, 'u');
            string a;
            a = toString(i);
            map.edit(r - 1, c - 1, a[0]);
            clr_screen();
            gotoxy(100, 15); cout << players[i]->_toString();
            _getch();
        }
    }
    if (str == "%%MovementDuringGame%%")
    {
        static char action;
        static int turn = 1;
        static Game game(*players, map);
        for (int count = 0; players[count] != NULL; count++)
        {
            clr_screen();
            gotoxy(100, 15); cout << "Turn " << turn;
            gotoxy(100, 16); cout << "Player " << players[count]->getnumber() + 1 << " Action: ";
            cin >> action;
            game.move(action, count);
        }
        turn++;
        clr_screen();
    }
}
void menu()
{
    cout << "Welcome to Tank CPP Game.n";
    cout << "At first, Please Enter the field's Size.n!!Attention!! We Recommend 10x10. Max Row Size: 11 and Max Column Size: 11nnpress Any Key to continue...";
    _getch();
    int r; int c;
    system("cls");
    cout << "Row:"; cin >> r; cout << "Col:"; cin >> c;
    if (r >= 11) r = 11;
    if (c >= 11) c = 11;
    SetWindow(138, 60);
    system("cls");
    Map map(r, c);
    draw_field(map);
    _getch();
    clr_screen();
    legend();
    //**********************//
    //****** Editing *******//
    //**********************//
    action_display("%edit%", map);
    clr_screen();
    /****************************
    ******GAME START-Players*****
    ****************************/
    action_display("%NewGame%", map);
    _getch();
    /************************
    ******* MOVEMENTS *******
    *************************/
    while (1)
        action_display("%%MovementDuringGame%%", map);
    _getch();
}
void main()
{
    menu();
}
*p_tank = tanks;

失败的行,你应该告诉我们。

现在我可以告诉你如何解决这个问题,但你真的不应该使用原始指针和数组。当您使用std::vector<Tank>时,整个问题就消失了。

这是非常危险的:

for (int count = 0; players[count] != NULL; count++)

不能保证原始数组之外的players[4]或任何其他内存为 null,因为它可能被其他内容使用,或者只是保存旧的和未初始化的内存值,从而导致程序意外继续并导致您遇到的问题。

改进:

  • 将玩家数量硬编码存储在常量中。
  • 使用 sizeofcountof 函数或宏检索数组中的项数
  • 使用存储当前项目数量的std::vector或类似
我没有

阅读完整的代码示例,但我注意到您正在使用静态成员变量来保存类状态。当然,这是行不通的,因为如果您有多个对象,它们共享相同的数字、行、列和方向内存。这意味着,如果您有一个 Tank 对象数组,并且您只更改了这些数组对象中的任何一个成员,它们都将设置为完全相同的值。这意味着你所有的坦克总是彼此重叠,朝同一个方向看。可能有四个,但你只能看到其中一个。

我不是说这是肯定的问题,但这是你可以考虑的事情。

最新更新