贪吃蛇小游戏,请问为什么光标到处乱跳,运行窗口什么也不显示

【问题描述】请编程实现贪吃蛇游戏。首先自动生成一个NN(如2020)的空间,在内部随机生成1个$代表食物,随机生成一条长度为5的蛇,蛇的身体用心形(ASCII码为003)显示,蛇头用笑脸(ASCII码为002)显示。自行定义蛇的起始位置。用户随意按键后蛇即刻开始自行行走,可设置行走速率为0.5秒。监测用户按键,根据用户的选择方向键,改变蛇的行走方向。在遇到食物$时,长度增一,且随机生成另一个食物$。倘若蛇碰到墙壁,则游戏失败,并打印蛇最终的长度。

###要求:必须符合我的题目,如果成功,给与采纳

【提示】本题涉及知识点:数组、循环、函数。

监测用户是否按键需要用到kbhit()函数,需要包含头文件conio.h。

可让用户按下wsad四个字母键分别代表上下左右四个方向,用char direction=getch()函数接收。

监测系统当前时间的函数为clock(),判断两次时间间隔用以下代码:

start=clock();

while((timeover=(clock()-start<=500))&&!kbhit());

示例:

img

以下是我的代码,为什么运行时在运行窗口光标反复跳动,什么也不显示?

#include <iostream>
#include <conio.h>
#include <cstdlib>
#include <ctime>
#include<windows.h>
using namespace std;

const int N = 20;   // 游戏区域的大小
const char SNAKE_BODY = 3;  // 蛇身体的显示字符,ASCII码为003
const char SNAKE_HEAD = 2;  // 蛇头的显示字符,ASCII码为002

const char FOOD = '$';  // 食物的显示字符
const int DELAY = 500;  // 蛇的移动速度,单位为毫秒

// 定义蛇的方向
enum Direction {
    UP,
    DOWN,
    LEFT,
    RIGHT
};

struct Position {
    int x;
    int y;
};

class SnakeGame {
public:
    SnakeGame();
    void run();

private:
    void initBoard();
    void generateFood();
    void drawBoard();
    void updateSnake();
    void handleInput();
    bool isCollision();
    void gameOver();

    char board[N][N];
    Position snake[2 * N * N];
    int snakeLength;
    Direction direction;
    Position food;
    bool isEaten;
};

SnakeGame::SnakeGame() {
    // 初始化随机数生成器
    srand(static_cast<unsigned>(time(0)));

    // 初始化游戏区域
    initBoard();

    // 初始化蛇的位置和长度
    int startX = N / 2;
    int startY = N / 2;
    snake[0].x = startX;
    snake[0].y = startY;
    snake[1].x = startX - 1;
    snake[1].y = startY;
    snakeLength = 2;

    // 初始化蛇的方向
    direction = RIGHT;

    // 初始化食物的位置
    generateFood();

    // 初始化蛇未吃到食物
    isEaten = false;
}

void SnakeGame::initBoard() {
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            board[i][j] = ' ';
        }
    }
}

void SnakeGame::generateFood() {
    int x, y;
    do {
        x = rand() % N;
        y = rand() % N;
    } while (board[x][y] != ' ');

    food.x = x;
    food.y = y;
    board[x][y] = FOOD;
}

void SnakeGame::drawBoard() {
    system("cls");  // 清空终端输出

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (i == food.x && j == food.y) {
                cout << FOOD;
            } else {
                bool isSnakeBody = false;
                for (int k = 0; k < snakeLength; ++k) {
                    if (snake[k].x == i && snake[k].y == j) {
                        cout << (k == 0 ? SNAKE_HEAD : SNAKE_BODY);
                        isSnakeBody = true;
                        break;
                    }
                }
                if (!isSnakeBody) {
                    cout << board[i][j];
                }
            }
        }
        cout << endl;
    }
}

void SnakeGame::updateSnake() {
    // 记录蛇尾的位置
    Position tail = snake[snakeLength - 1];

    // 更新蛇身体的位置
    for (int i = snakeLength - 1; i > 0; --i) {
        snake[i] = snake[i - 1];
    }

    // 更新蛇头的位置
    switch (direction) {
        case UP:
            snake[0].x--;
            break;
        case DOWN:
            snake[0].x++;
            break;
        case LEFT:
            snake[0].y--;
            break;
        case RIGHT:
            snake[0].y++;
            break;
    }

    // 判断是否吃到食物
    if (snake[0].x == food.x && snake[0].y == food.y) {
        // 蛇长度增加
        snakeLength++;

        // 生成新的食物
        generateFood();

        // 标记食物已被吃掉
        isEaten = true;
    }

    // 更新蛇尾的位置为空白
    board[tail.x][tail.y] = ' ';

    // 更新蛇头和身体的位置
    board[snake[0].x][snake[0].y] = SNAKE_HEAD;
    for (int i = 1; i < snakeLength; ++i) {
        board[snake[i].x][snake[i].y] = SNAKE_BODY;
    }
}

void SnakeGame::handleInput() {
    if (_kbhit()) {
        char ch = _getch();

        switch (ch) {
            case 'w':
                if (direction != DOWN)
                    direction = UP;
                break;
            case 's':
                if (direction != UP)
                    direction = DOWN;
                break;
            case 'a':
                if (direction != RIGHT)
                    direction = LEFT;
                break;
            case 'd':
                if (direction != LEFT)
                    direction = RIGHT;
                break;
        }
    }
}

bool SnakeGame::isCollision() {
    // 判断是否碰到墙壁
    if (snake[0].x < 0 || snake[0].x >= N || snake[0].y < 0 || snake[0].y >= N) {
        return true;
    }

    // 判断是否碰到自己的身体
    for (int i = 1; i < snakeLength; ++i) {
        if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
            return true;
        }
    }

    return false;
}

void SnakeGame::gameOver() {
    system("cls");
    cout << "Game Over!" << endl;
    cout << "Your snake length: " << snakeLength << endl;
}

void SnakeGame::run() {
    clock_t start = clock();

    while (true) {
        drawBoard();

        handleInput();

        if (clock() - start >= DELAY) {
            updateSnake();
            start = clock();
        }

        if (isCollision()) {
            gameOver();
            break;
        }
        if (isEaten) {
            Sleep(200);  // 等待一段时间显示被吃食物的效果
            isEaten = false;
        }
    }
}
int main() {
    SnakeGame game;
    game.run();

    return 0;
}


要求:必须提供完整代码

把drawBoard();放一份循环外,再放一份updateSnake();下面

在运行代码时,如果在终端中只看到光标反复跳动而没有其他内容显示,可能是由于以下原因之一:

  1. 终端刷新问题:代码中使用了system("cls")来清空终端输出,但有些终端在刷新屏幕时可能会导致光标闪烁。这可能是导致光标跳动的原因,而没有其他内容显示。

解决方法:尝试在代码的适当位置注释掉system("cls")语句,或者将其替换为其他方式来清空终端输出。

  1. 终端设置问题:终端的设置可能会导致无法正确显示输出内容。例如,可能使用了不支持ASCII码的终端或字体。或者可能终端的行高度太小,导致输出被隐藏在屏幕外部。

解决方法:尝试更换终端或调整终端的设置,例如更换终端程序、调整字体设置或增加终端的行高度。

  1. 编码问题:代码中使用了ASCII码来表示特定的字符,但终端可能不支持或未正确解析这些字符。

解决方法:尝试将特定的字符替换为终端支持的字符,或者调整终端的编码设置以正确解析特定字符。

如果以上方法仍然无法解决问题,请提供更多关于运行环境和终端设置的详细信息,以便更准确地定位问题。

可以借鉴下

import random
import time
import os

# 定义常量
WIDTH = 20
HEIGHT = 20
FOOD = "$"
SNAKE = "♥"
HEAD = "☻"
BLANK = " "

# 初始化游戏界面
board = [[BLANK for y in range(HEIGHT)] for x in range(WIDTH)]

# 随机生成初始蛇
snake = [(random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1))]
for i in range(4):
    snake.append((snake[-1][0], snake[-1][1]+1))

# 随机生成食物
food = (random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1))

# 定义方向常量
UP = (-1, 0)
DOWN = (1, 0)
LEFT = (0, -1)
RIGHT = (0, 1)

# 定义游戏逻辑函数
def move(direction):
    global snake, food
    
    # 计算新的蛇头位置
    head = (snake[-1][0]+direction[0], snake[-1][1]+direction[1])
    
    # 判断是否撞墙
    if head[0] < 0 or head[0] >= WIDTH or head[1] < 0 or head[1] >= HEIGHT:
        return False
    
    # 判断是否吃到食物
    if head == food:
        snake.append(head)
        food = (random.randint(0, WIDTH-1), random.randint(0, HEIGHT-1))
    else:
        snake.pop(0)
        snake.append(head)
    
    # 判断是否撞到自己
    if len(set(snake)) != len(snake):
        return False
    
    return True

# 游戏循环
while True:
    # 清空界面
    os.system("cls" if os.name == "nt" else "clear")
    
    # 更新蛇位置
    if not move(RIGHT):
        break
    
    # 显示界面
    board = [[BLANK for y in range(HEIGHT)] for x in range(WIDTH)]
    for s in snake:
        board[s[0]][s[1]] = SNAKE
    board[snake[-1][0]][snake[-1][1]] = HEAD
    board[food[0]][food[1]] = FOOD
    
    for i in range(WIDTH):
        for j in range(HEIGHT):
            print(board[i][j], end=" ")
        print()
    
    # 等待一段时间
    time.sleep(0.5)
在运行代码时,用户可以使用方向键控制蛇的移动方向。当蛇撞墙或撞到自己时,游戏结束,并打印蛇的长度

以下答案由GPT-4.5Plus大模型(语音)与博主A努力中.......共同编写:

从您提供的代码和描述来看,很可能是由于调用了系统命令cls导致的。cls命令会清空输出窗口,但是也会使光标位置重新回到原点(0, 0)。
由于您的游戏逻辑里反复调用cls来清屏,导致光标位置在窗口内反复跳动,看起来像是没有输出任何内容。

解决方法有以下两种:

  1. 不调用cls来清屏,而是在每次输出前清理当前行。具体可以这样实现:
cpp
for (int i = 0; i < N; ++i) {
    cout << "\r";  // 将光标移到行首
    for (int j = 0; j < N; ++j) {
        // 输出游戏元素到同一行
    }
}
cout << endl;  // 换行

这种方法通过\r将光标移到行首实现清理当前行的效果,无须调用cls清屏,可以避免光标跳动的问题。

  1. 调用cls清屏后,在输出第一个元素前重新定位光标位置。可以这样实现:
cpp 
cls;
COORD pos = {0, 0};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
// 定位光标后输出第一个游戏元素

这种方法在调用cls清屏后,通过Windows API SetConsoleCursorPosition重新定位光标到(0, 0)的起点位置。之后正常输出游戏元素,就不会出现光标跳动的问题。

我看了您提供的代码,个人推荐使用第一种方法,不调用cls来清屏,通过\r清理当前行的方式更简单明了。不过两种方法对这个问题的解决思路都是一致的,希望能提供参考。