You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++控制台游戏碰撞检测失效问题求助

控制台汽车躲避游戏碰撞检测失效问题修复

我用C++结合Windows库开发了一款简易控制台汽车躲避障碍游戏,采用二维数组存储地图数据。原本碰撞检测逻辑是判断障碍物下方单元格是否被汽车占据,运行正常,但现在障碍物会直接穿过汽车,碰撞检测完全失效,修改代码后仍无法解决。

问题代码

#include <iostream> // for the text
#include <cmath>
#include <windows.h> // for the key press
#include <stdlib.h> // for clearing console
#define ROWS 16
#define COLUMNS 36
short SCORE = 0;
short map[ROWS][COLUMNS];
bool GameOver = false;
using namespace std; 

// Game classes
class Car {
    public:
    short mapX = 6;
    short mapY = 10;

    void UpdateCar() {
        MoveCar();
    }

    private:
    short direction = 0; // -1 is left, 1 is right
    short leftKey;
    short rightKey;

    void SetCar() {
        // car
        map[mapY][mapX]         = 3; // origin
        map[mapY - 1][mapX]     = 3; // top
        map[mapY + 1][mapX]     = 3; // bottom
        map[mapY - 2][mapX]     = 3; // top2
        map[mapY + 2][mapX]     = 3; // bottom2
        map[mapY - 1][mapX - 1] = 3; // left
        map[mapY + 1][mapX - 1] = 3; // left2
        map[mapY + 1][mapX + 1] = 3; // right
        map[mapY - 1][mapX + 1] = 3; // right2
    }

    void EraseCar() {
        // car
        map[mapY][mapX]         = 0; // origin
        map[mapY - 1][mapX]     = 0; // top
        map[mapY + 1][mapX]     = 0; // bottom
        map[mapY - 2][mapX]     = 0; // top2
        map[mapY + 2][mapX]     = 0; // bottom2
        map[mapY - 1][mapX - 1] = 0; // left
        map[mapY + 1][mapX - 1] = 0; // left2
        map[mapY + 1][mapX + 1] = 0; // right
        map[mapY - 1][mapX + 1] = 0; // right2
    }

    void MoveCar() {
        EraseCar();

        // Key Checking
        leftKey = GetAsyncKeyState(VK_LEFT);
        rightKey = GetAsyncKeyState(VK_RIGHT);

        // Key setting the direction
        if (leftKey == 1) {direction = -1;}
        else if (rightKey == 1) {direction = 1;}

        // moving the car
        mapX += direction;

        // reset movement
        leftKey = 0;
        rightKey = 0;
        direction = 0;

        // setting car
        SetCar();
    }

};

class Obstacle {
    public:
    short mapX = 5;
    short mapY = 1;
    void UpdateObstacle() {
        if (CollideWithCar() == false) {
            EraseObstacle();
            ChangeX();
            mapY++; // move the obstacle down 1 grid cell
            DrawObstacle();
        } else {
            GameOver = true;
        }
    }

    private:
    bool OnEdge() {

        if (mapY == ROWS - 1) { // is obstacle on the bottom
            return true; // return true
        }

        return false;
    }

    void ChangeX() { // set the obstacle X to a random number from 1 - COLUMNS - 1
        if (OnEdge()) {
            mapX = (int)(rand() % (COLUMNS - 2)) + 2;
            mapY = 1;
            SCORE++; // increase the score
        }
    }

    void DrawObstacle() {
        map[mapY][mapX] = 4;
        map[mapY][mapX + 1] = 4;
    }

    void EraseObstacle() {
        map[mapY][mapX] = 0;
        map[mapY][mapX + 1] = 0;
    }

    bool CollideWithCar() {
        if (map[mapY+1][mapX] == 3 || map[mapY+1][mapX+1] == 3) {
            return true;
        }

        return false;
    }
};

class Game {
    public:
    Car c;
    Obstacle o;

    // Map functions
    void DrawMap() {
        for (int y = 0; y < ROWS; y++) {

            for (int x = 0; x < COLUMNS; x++) {
                switch(map[y][x]) {
                    case 0: 
                    cout << "  "; // empty
                    break;
                    case 1:
                    cout << "[]"; // wall
                    break;
                    case 2:
                    cout << "||"; // road
                    break;
                    case 3:
                    cout << "()"; // car
                    break;
                    case 4:
                    cout << "{}"; // obstacle
                    break;
                }
            }

            // Make a new lines after the end of each column
            cout << "" << endl;
        }
    }
    
    // Defining the Game
    void DefineMap() {
    for (int y = 0; y < ROWS; y++) {

            for (int x = 0; x < COLUMNS; x++) {

                // Define the border
                if (x == 0 || x == COLUMNS - 1 || y == 0 || y == ROWS - 1) {
                    map[y][x] = 1;
                } else {map[y][x] = 0;}
            }
        } 
    }
    void DefineRoad() {
        for (int y = 0; y < ROWS; y++) {
            for (int x = (COLUMNS / 2) - 1; x < (COLUMNS / 2); x++) {
                map[y][x] = 2; // 2 is road
            }
        }
    }
    void DefineGame() {
        DefineRoad();
        DefineMap();
    }

    Game() { // constructor
        DefineGame();
    }

    // restarting the game
    void RestartGame() {
        o.mapY = 1;
        c.mapX = 6;
        c.mapY = 10;
    }

    // Updating the game
    void UpdateGame() {
        DefineMap(); // define the map
        DefineRoad(); // define the road
        o.UpdateObstacle(); // update the obstacle
        c.UpdateCar(); // update the car
        DrawMap(); // draw the map
    }
};

void GameOverText() {
// too long to add not useful
}

int main() {
    // escape key
    short escape = GetAsyncKeyState(VK_UP);

    // restart
    short restart = GetAsyncKeyState(VK_SPACE);

    // Game object
    Game g;

    // game loop
    while (escape == 0) {
        escape = GetAsyncKeyState(VK_UP); // check for the escape key

        // Game logic
        if (GameOver == false) {
            Sleep(500); // sleep for half a second then update the screen
            system("cls"); // clear the screen

            // DEBUGGING
            for (int i = 0; i < ROWS; i++) {
                for (int j = 0; j < COLUMNS; j++) {
                    cout << map[i][j];
                }
                cout << "" << endl;
            }

            g.UpdateGame(); // update the game
            cout << "SCORE: " << SCORE << "  " << "LEFT AND RIGHT ARROWS TO MOVE" << endl; // draw the score
            cout << "SPACE IS FOR RESTART" << endl; // draw the score
            cout << "ESCAPE IS FOR LEAVING" << endl; // draw the score
        } else {
            Sleep(1000); // sleep for a second then update the screen
            system("cls"); // clear the screen
            GameOverText(); // do the game over
            restart = GetAsyncKeyState(VK_SPACE); // get restart key
            if (restart == 1) {GameOver = false; g.RestartGame();} // if key is pressed
        }
    }

    // ending
    system("cls");
    cout << "THANKS FOR PLAYING";
}

问题分析

  1. 更新顺序错误:UpdateGame()先处理障碍物再绘制汽车,而DefineMap()已将地图重置为初始状态,碰撞检测时地图上还没有汽车的标记3,导致检测失效。
  2. 碰撞时机错误:UpdateObstacle()先检测碰撞再移动障碍物,且检测的是障碍物下方位置,此时障碍物未移动,加上地图已重置,逻辑完全无效。
  3. 按键检测逻辑错误:用GetAsyncKeyState() == 1判断按键,只会在按键刚按下瞬间生效,导致汽车移动不灵敏。

修复方案

1. 调整游戏更新顺序

修改Game类的UpdateGame()方法,先绘制汽车再处理障碍物:

void UpdateGame() {
    DefineMap(); // 重置地图
    DefineRoad(); // 绘制道路
    c.UpdateCar(); // 先将汽车绘制到地图
    o.UpdateObstacle(); // 再处理障碍物,确保碰撞检测能识别汽车
    DrawMap(); // 绘制最终地图
}

2. 重构障碍物更新与碰撞检测

修改Obstacle类的UpdateObstacle()方法,提前检查障碍物下一个位置是否与汽车重叠:

void UpdateObstacle() {
    EraseObstacle(); // 擦除当前位置障碍物
    
    ChangeX(); // 到达边界则重置位置
    
    short nextY = mapY + 1;
    // 检查下一个位置是否与汽车碰撞
    if (map[nextY][mapX] == 3 || map[nextY][mapX+1] == 3) {
        GameOver = true;
        DrawObstacle();
        return;
    }
    
    mapY = nextY;
    DrawObstacle(); // 绘制新位置的障碍物
}

3. 修复按键检测逻辑

修改Car类的MoveCar()方法,正确判断按键持续按下状态,并增加边界限制:

void MoveCar() {
    EraseCar();

    bool leftPressed = (GetAsyncKeyState(VK_LEFT) & 0x8000) != 0;
    bool rightPressed = (GetAsyncKeyState(VK_RIGHT) & 0x8000) != 0;

    if (leftPressed) {direction = -1;}
    else if (rightPressed) {direction = 1;}

    // 限制汽车移动范围,防止移出道路
    if (mapX + direction >= 2 && mapX + direction <= COLUMNS - 3) {
        mapX += direction;
    }

    direction = 0;
    SetCar();
}

4. 调整障碍物边界判断

修改Obstacle类的OnEdge()方法,避免障碍物移动到底部边框:

bool OnEdge() {
    if (mapY >= ROWS - 2) { // 到达倒数第二行即视为边界
        return true;
    }
    return false;
}

内容的提问来源于stack exchange,提问作者ripe_onions

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 20:07:02