简体   繁体   English

一个简单的Tank C ++游戏

[英]A simple Tank C++ game

I'm a little new to c++ right now and I have to write a console Tank game. 我现在对C ++有点陌生,我必须编写一个控制台Tank游戏。 I did lots of the part by myself and there's nothing wrong with most of the parts. 我自己做了很多工作,大部分工作都没错。 Here is my Tank class: 这是我的Tank课程:

    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 = '\0';

the problem is when I create array of objects like: 问题是当我创建对象数组时,例如:

Tank *players[4];

Because I need a four player game and one Tank object for every one of them it Only uses the last object. 因为我需要一个四人游戏和一个坦克对象,所以只使用最后一个对象。 Here is the code I want to use for each turn, for each player to say what they're going to do: 这是我想在每个回合中使用的代码,供每个玩家说出他们打算做什么:

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++;

And as you may see there is a problem with the code. 如您所见,代码存在问题。

And as you may want to know, here is the Game class: 您可能想知道,这是Game类:

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; }

If you need the full code here it is: 如果您需要完整的代码,则为:

    #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 = '\0';

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: W\tRandom: ?";
    gotoxy(100, 6); cout << "Box: B\tIce: I";
    gotoxy(100, 7); cout << "Trap: X\t";
    gotoxy(100, 9); cout << "Actions:";
    gotoxy(100, 10); cout << "U D L R\tFire: 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: 11\n\npress 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();
}

This is very dangerous: 这是非常危险的:

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

There is no guarantee that players[4] or any other memory outside the original array is null as it might be used by something different or just holds old and uninitialized memory values, causing your program to continue unexpectedly and causing the problems you experience. 无法保证players[4]或原始数组之外的任何其他内存为空,因为它可能被不同的东西使用,或者仅保存旧的未初始化的内存值,从而导致程序意外继续运行并引起您遇到的问题。

Improvements: 改进:

  • Store the amount of players hard coded in a constant. 将硬编码的播放器数量存储在一个常量中。
  • Retrieve the number of items in the array using sizeof or a countof function or macro 使用sizeofcountof 函数或宏检索数组中的项目数
  • Use a std::vector or similar which stores the current number of items it holds 使用std::vector或类似的东西来存储它持有的当前项目数

*p_tank = tanks; is the line which fails, and you should have told us that. 是失败的线,您应该已经告诉我们了。

Now I could tell you how to fix just that, but you really should not be using raw pointers and arrays. 现在,我可以告诉您如何解决此问题,但实际上您不应该使用原始指针和数组。 The whole problem goes away when you use std::vector<Tank> . 使用std::vector<Tank>时,整个问题消失了。

I didn't read the full code sample but I've noticed you're using static member variables to save the classes state. 我没有阅读完整的代码示例,但是我注意到您正在使用静态成员变量来保存类状态。 Of course this can't work because if you have multiple objects they share the same memory for number, row, col and direction. 当然,这是行不通的,因为如果您有多个对象,它们将在数字,行,列和方向上共享相同的内存。 This means if you have an array of Tank objects and you change only one member of any of these array objects they will all be set to the very same value. 这意味着,如果您有一个Tank对象数组,并且仅更改了这些数组对象中的任何一个,则它们将全部设置为相同的值。 This means you have all your tanks always on top of each other, looking in the same direction. 这意味着您的所有水箱都始终朝着同一方向排列。 There may be four of them but you can only see one of them. 可能有四个,但您只能看到其中一个。

I don't say that this is the problem for sure, but this is something you might consider. 我并不是说这肯定是问题,但这是您可能要考虑的问题。

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

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