C++的贪吃蛇游戏的建议
Advice for Snake Game in C++
我只想问你一件事。我不期望你提供任何代码。我想做一个贪吃蛇游戏。我的想法是创建一个数组并使用 GetAsyncKeyState() 函数控制蛇。我还没有决定如何移动蛇,但我正在考虑使用链表将蛇身体的坐标保存在数组中的想法。
我有两个问题:1. 你喜欢我使用链表的想法吗?2.我需要以某种方式清除控制台并再次输出表。但是如果我使用系统("CLS"),屏幕会闪烁。有没有更好的方法可以在不眨眼的情况下清除控制台?
任何其他想法将不胜感激。 :)
这是我现在的代码。
#include<iostream>
#include<windows.h>
using namespace std;
int matrix[20][40];
void FillMatrix()
{
for(int i = 0; i < 20; i++)
for(int j = 0; j < 40; j++)
matrix[i][j] = 0;
}
void Show()
{
COORD pos = {0, 0};
SetConsoleCursorPosition(cout, pos);
for(int i = 0; i < 20; i++)
{
for(int j = 0; j < 40; j++)
{
if(i == 0 || j == 0 || i == 19 || j == 39) cout << "#";
else if(matrix[i][j] == 0) cout << " ";
else cout << ".";
}
cout << endl;
}
}
void Change(int i, int j)
{
matrix[i][j] = 1;
}
int main()
{
FillMatrix();
int x, y;
x = 4;
y = 4;
while(!GetAsyncKeyState(VK_ESCAPE))
{
Sleep(100);
//system("cls");
if(GetAsyncKeyState(VK_LEFT))
{
y = y-1;
Change(x, y);
}
else
if(GetAsyncKeyState(VK_UP))
{
x = x-1;
Change(x, y);
}
else
if(GetAsyncKeyState(VK_RIGHT))
{
y = y+1;
Change(x, y);
}
else
if(GetAsyncKeyState(VK_DOWN))
{
x = x+1;
Change(x, y);
}
Show();
}
system("pause");
return 0;
}
使用链表几乎总是一个糟糕的主意。在这种情况下,似乎甚至没有理由考虑使用一个。支持使用链表的主要点是当您需要在列表中间插入或删除项目时(并且,为了获得很多好处,已经有一些东西指向列表中需要插入/删除的特定位置)。
由于您显然使用的是 Win32,因此我根本不会清除屏幕。相反,我会使用WriteConsoleOutput
将新输出写入屏幕,覆盖以前存在的任何内容。
虽然它本身不是一个贪吃蛇游戏,但这里有一个代码来实现约翰康威的生活游戏,使用WriteConsoleOutput
来产生屏幕输出。它还包括一个ClrScr
功能来清除屏幕,如果你决定你真的必须这样做(但你可能没有)。
/*
** A quick "life" (2-d cellular automaton) implementation done in Turbo C 2.0
** on the spur-of-the-moment by Jonathan Guthrie 9/20/1992 and donated to the
** public domain.
**
** In keeping with the guidelines of the C_ECHO, this program has been tested,
** and does seem to operate properly.
*/
/* Modified into a native Win32 program, July 2001 by Jerry Coffin.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifndef random
#define random(num) (int)(((long)rand()*(num))/RAND_MAX)
#endif
#ifndef randomize
#define randomize() srand(((unsigned int)time(NULL))|1)
#endif
#define ROWS 50
#define COLS 80
#define GENERATIONS 500
int civ1[ROWS+2][COLS+2], civ2[ROWS+2][COLS+2];
CHAR_INFO disp[ROWS][COLS];
HANDLE console;
COORD size = { COLS, ROWS };
COORD src = { 0, 0};
SMALL_RECT dest = { 0, 0, COLS, ROWS };
void fill_edges(int civ1[ROWS+2][COLS+2]);
void ClrScrn(int attrib) {
HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = { 0, 0};
DWORD written;
CONSOLE_SCREEN_BUFFER_INFO screen_attr;
unsigned size;
GetConsoleScreenBufferInfo(screen, &screen_attr);
size = screen_attr.dwSize.X * screen_attr.dwSize.Y;
FillConsoleOutputCharacter( screen,attrib, size, pos, &written);
SetConsoleCursorPosition(console, pos);
}
void update_generation(int old[ROWS][COLS], int new[ROWS][COLS])
{
int i, j, count;
for (i = 1; i <= ROWS; ++i)
{
for (j = 1; j <= COLS; ++j)
{
count = old[(i + ROWS - 1) % ROWS][(j + COLS - 1) % COLS] +
old[(i + ROWS - 1) % ROWS][j] +
old[(i + ROWS - 1) % ROWS][(j + 1) % COLS] +
old[i][(j + COLS - 1) % COLS] +
old[i][(j + 1) % COLS] +
old[(i + 1) % ROWS][(j + COLS - 1) % COLS] +
old[(i + 1) % ROWS][j] +
old[(i + 1) % ROWS][(j + 1) % COLS];
switch(count)
{
default:
new[i][j] = 0;
disp[i][j].Char.AsciiChar = ' ';
break;
case 2:
new[i][j] = old[i][j];
break;
case 3:
new[i][j] = 1;
disp[i][j].Char.AsciiChar = '*';
break;
}
}
}
WriteConsoleOutput(console,disp, size, src, &dest);
}
void initialize(void)
{
int i, j;
ClrScrn(0x71);
randomize();
for (i = 1; i <= ROWS; ++i)
{
for (j = 1; j <= COLS; ++j)
{
civ1[i][j] = random(2);
disp[i][j].Char.AsciiChar = civ1[i][j] ? '*' : ' ';
disp[i][j].Attributes = 0x71;
}
}
WriteConsoleOutput(console,disp, size, src, &dest);
fill_edges(civ1);
}
void fill_edges(int civ1[ROWS+2][COLS+2]) {
int i;
for (i=1; i<ROWS; ++i) {
civ1[i][0] = civ1[i][ROWS+1];
civ1[i][ROWS+2] = civ[i][1];
}
for (j=1; j<COLS; ++j) {
civ1[0][j] = civ1[COLS+1][j];
civ1[COLS+2][j] = civ1[1][j];
}
civ1[0][0] = civ1[COLS+1][ROWS+1];
civ1[COLS+2][ROWS+2] = civ1[1][1];
civ1[COLS+2][0] = civ1[
}
int main(void)
{
int i;
console = (HANDLE)_get_osfhandle(_fileno(stdout));
initialize();
for (i = 0; i < GENERATIONS; ++i)
{
update_generation(civ1, civ2);
update_generation(civ2, civ1);
}
// getch();
return EXIT_SUCCESS;
}
除非你能用一些合理化来证明这一点,否则听起来你已经选择了一个链表,因为你以前听说过这个名字。
至于屏幕闪烁,终端不会双重缓冲,所以这就是它的方式,直到您使用像ncurses
这样的库来移动光标覆盖位置,而不是反复清洁屏幕并从头开始。
相关文章:
- 在C++游戏中与库存系统作斗争
- 换位表导致测试失败(但在游戏中运行良好)
- Craps游戏问题,忽略if语句
- 矢量下标超出SFML游戏中的范围
- 我是 c++ 的新手.学习基本知识后,我想做井字游戏.对于印刷板,我在下面写代码,但它显示错误
- 我在贪吃蛇游戏中收到了错误代码 -1073741571
- 我应该在简单的策略游戏中为各个派系使用类吗 - C++
- 游戏体验和升级
- 我的代码运行良好,但在游戏循环中中断
- 如何使用 SFML 在贪吃蛇游戏中定义游戏结束?
- 我可以使用任何好的逻辑来阻止计算机将 O 放在井字游戏中的现有 X 上
- 将鼠标和键盘输入发送到 unity3d 游戏 (Rust)
- 在猜谜游戏 c++ 中不计算尝试次数
- 在C++不适用于猜数字游戏的情况下再次播放选项
- 在为我的基于文本的 RPG 游戏制作库存时遇到困难
- 在定义字符数组(井字游戏)的 for 循环中应用输入限制
- Frank Luna 在他的书"使用 DirectX12 进行 3D 游戏编程"的介绍中盒子示例的问题
- 如何在Linux上正确发布C++软件(游戏)
- 提高基于组件的游戏引擎的效率
- 文本冒险游戏 - 如何区分一种项目类型与另一种项目类型以及如何构建项目类/子类