【问题描述】请编程实现贪吃蛇游戏。首先自动生成一个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());
示例:
以下是我的代码,为什么运行时在运行窗口光标反复跳动,什么也不显示?
#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();下面
在运行代码时,如果在终端中只看到光标反复跳动而没有其他内容显示,可能是由于以下原因之一:
system("cls")
来清空终端输出,但有些终端在刷新屏幕时可能会导致光标闪烁。这可能是导致光标跳动的原因,而没有其他内容显示。解决方法:尝试在代码的适当位置注释掉system("cls")
语句,或者将其替换为其他方式来清空终端输出。
解决方法:尝试更换终端或调整终端的设置,例如更换终端程序、调整字体设置或增加终端的行高度。
解决方法:尝试将特定的字符替换为终端支持的字符,或者调整终端的编码设置以正确解析特定字符。
如果以上方法仍然无法解决问题,请提供更多关于运行环境和终端设置的详细信息,以便更准确地定位问题。
可以借鉴下
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来清屏,导致光标位置在窗口内反复跳动,看起来像是没有输出任何内容。
解决方法有以下两种:
cpp
for (int i = 0; i < N; ++i) {
cout << "\r"; // 将光标移到行首
for (int j = 0; j < N; ++j) {
// 输出游戏元素到同一行
}
}
cout << endl; // 换行
这种方法通过\r将光标移到行首实现清理当前行的效果,无须调用cls清屏,可以避免光标跳动的问题。
cpp
cls;
COORD pos = {0, 0};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
// 定位光标后输出第一个游戏元素
这种方法在调用cls清屏后,通过Windows API SetConsoleCursorPosition重新定位光标到(0, 0)的起点位置。之后正常输出游戏元素,就不会出现光标跳动的问题。
我看了您提供的代码,个人推荐使用第一种方法,不调用cls来清屏,通过\r清理当前行的方式更简单明了。不过两种方法对这个问题的解决思路都是一致的,希望能提供参考。