叙述
文字游戏告一段落,想着可不可以绘制图像来实现游戏框架,在一段时间的百度中了解了点背景颜色的实现方式之后,于是乎就有了现在的图像游戏 < 贪吃蛇 >。但目前还不完善,身体增长后的绘制问题没有解决,so…只有一个蛇头在狂吃,但这给我的感觉是发现了一个新世界,绘制图像!这意味着我可以将想法可视化,或者模仿别人小游戏来实现趣味性,万事开头难,但迈下这一步之后就会从中寻找到自己的乐趣并深入其中,庆幸我没有放弃或者变心,接下来我会用同样的方法来制作一下小游戏,可能偶尔会试着学习OpenGL,虽然看不懂,但时间长着呢不是吗?
- 游戏截图
- 源码
感觉代码还是有点乱,想到怎么优化后再优化吧!
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <conio.h>
#include <ctime>
using namespace std;
#define random( x ) rand ( ) % ( x )
HANDLE handle = GetStdHandle ( STD_OUTPUT_HANDLE );
COORD coord;
void SetPosition ( int x, int y ) { coord.X = x; coord.Y = y; SetConsoleCursorPosition ( handle, coord ); }
class Data {
public:
struct strRect { int x; int y; int width; int height; int color; };
struct strButton { int x; int y; int width; int color; string text [ 2 ]; };
struct strText { int x; int y; int color; string text; };
struct strNumber { int x; int y; int color; int number; };
struct strXY { int x; int y; };
strButton button_start, button_set, button_exit, button_size, button_size_min,
button_level, button_level_n, button_level_h, button_level_vh, button_gameover;
strRect area_main, area_play, area_score, area_option, area_attribute, area_size;
strText text_pass, text_level, text_score, text_time, text_multiple, text_gametime;
strNumber number_score, number_speed, number_pass;
strXY xy_snake, xy_food [ 2 ];
int id_window, id_button, id_snake, id_food;
int isfood_score [ 2 ], isfood_random [ 2 ];
Data ( ) {
button_start = { 40, 10, 20, 0x8f, {"开始游戏","开 始 游 戏"} };
button_set = { 40, 14, 20, 0x8f, { "设置", "设 置" } };
button_exit = { 40, 18, 20, 0x8f, { "退出游戏", "退 出 游 戏" } };
button_size = { 10, 5, 20, 0x8f, { "分辨率", "分 辨 率" } };
button_size_min = { 30, 5, 60, 0x70, { "100 X 31", "100 X 31" } };
button_level = { 10, 8, 20, 0x8f, { "游戏难度", "游 戏 难 度" } };
button_level_n = { 30, 5, 60, 0x70, { "简单", "简 单" } };
button_level_h = { 30, 8, 60, 0x70, { "困难", "困 难" } };
button_level_vh = { 30, 11, 60, 0x70, { "地狱", "地 狱" } };
button_gameover = { 10, 14, 56, 0xcf, { "GAME\tOVER", "\0" } };
area_main = { 10, 0, 80, 31, 0xf0 };
area_play = { 10, 0, 56, 31, 0x7f };
area_score = { 66, 0, 24, 31, 0x8f };
area_option = { 10, 0, 20, 31, 0x8f };
area_attribute = { 30, 0, 60, 31, 0x7f };
area_size = { 30, 8, 60, 6, 0x7f };
text_pass = { 75, 2, 0x8f, "第 1 关" };
text_level = { 68, 5, 0x8f, "游戏难度:简单" };
text_score = { 68, 7, 0x8f, "得分:" };
text_time = { 68, 15, 0x8f, "计时:" };
text_multiple = { 68, 23, 0x8f, "倍率:" };
text_gametime = { 68, 25, 0x8f, "游戏时间:" };
number_score = { 75, 7, 0x8f, 0 };
number_speed = { 75, 23, 0x8f, 1 };
number_pass = { 78, 2, 0x8f, 1 };
xy_snake = { 34, 15 };
xy_food [ 0 ] = { 0 };
xy_food [ 1 ] = { 0 };
id_window = 1;
id_button = 1;
id_snake = 1;
id_food = 1;
isfood_random [ 0 ] = 0;
isfood_random [ 1 ] = 0;
isfood_score [ 0 ] = 0;
isfood_score [ 1 ] = 0;
}
};
class Draw : public Data {
public:
void Rectangle ( strRect& );
void PrintText ( strText& );
void PrintNumber ( strNumber& );
void PrintButton ( strButton& );
void Load ( );
void WindowMain ( );
void WindowPlay ( );
void WindowSet ( );
void SignalButton ( strButton& );
void SnakePlay ( );
void Food ( );
};
class Signal : public Draw {
public:
void SignalOn ( );
void SignalW ( );
void SignalS ( );
void SignalA ( );
void SignalD ( );
void SignalEnd ( );
void SignalEsc ( );
};
void Draw::Load ( ) {
CONSOLE_CURSOR_INFO info = { 1, 0 };
SetConsoleCursorInfo ( handle, &info );
system ( "mode con cols=100 lines=31" );
system ( "color f0" );
SetConsoleTitle ( TEXT ( "贪吃蛇" ) );
HWND hWnd = GetConsoleWindow ( );
RECT rc;
GetWindowRect ( hWnd, &rc );
SetWindowLongPtr ( hWnd, GWL_STYLE, GetWindowLong ( hWnd, GWL_STYLE ) &
~WS_THICKFRAME & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX );
SetWindowPos ( hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL );
srand ( ( int ) time ( NULL ) );
WindowMain ( );
}
void Draw::WindowMain ( ) {
SignalButton ( button_start );
PrintButton ( button_set );
PrintButton ( button_exit );
}
void Draw::WindowPlay ( ) {
Rectangle ( area_play );
Rectangle ( area_score );
PrintText ( text_pass );
PrintText ( text_level );
PrintText ( text_score );
PrintText ( text_time );
PrintText ( text_multiple );
PrintText ( text_gametime );
PrintNumber ( number_pass );
PrintNumber ( number_score );
PrintNumber ( number_speed );
SnakePlay ( );
}
void Draw::WindowSet ( ) {
Rectangle ( area_option );
Rectangle ( area_attribute );
SignalButton ( button_size );
PrintButton ( button_level );
PrintButton ( button_size_min );
}
void Draw::Rectangle ( strRect& rect ) {
SetConsoleTextAttribute ( handle, rect.color );
for (int i = 0; i < rect.height; i++ ) {
SetPosition ( rect.x, ( rect.y + i ) );
cout << setw ( rect.width ) << '\0';
}
}
void Draw::PrintButton ( strButton& button ) {
SetConsoleTextAttribute ( handle, button.color );
for ( int i = 0; i < 3; i++ ){
SetPosition ( button.x, ( button.y + i ) );
cout << setw ( button.width ) << '\0';
}
SetPosition ( ( button.x + ( ( button.width - button.text [ 0 ].length ( ) ) / 2 ) ), ( button.y + 1 ) );
cout << button.text [ 0 ];
}
void Draw::SignalButton ( strButton& button ) {
SetConsoleTextAttribute ( handle, 0xcf );
for (int i = 0; i < 3; i++ ) {
SetPosition ( button.x, ( button.y + i ) );
cout << setw ( button.width ) << '\0';
}
SetPosition ( ( button.x + ( ( button.width - button.text [ 1 ].length ( ) ) / 2 ) ), ( button.y + 1 ) );
cout << button.text [ 1 ];
}
void Draw::PrintText ( strText& text ) {
SetConsoleTextAttribute ( handle, text.color );
SetPosition ( text.x, text.y );
cout << text.text;
}
void Draw::PrintNumber ( strNumber& number ) {
SetConsoleTextAttribute ( handle, number.color );
SetPosition ( number.x, number.y );
cout << number.number;
}
void Signal::SignalOn ( ) {
switch ( getch ( ) ) {
case 'w':SignalW ( );break;
case 's':SignalS ( );break;
case 'a':SignalA ( );break;
case 'd':SignalD ( );break;
case 13:SignalEnd ( );break;
case 27:SignalEsc ( );break;
}
}
void Signal::SignalW ( ) {
switch ( id_button ) {
case 2:SignalButton ( button_start );PrintButton ( button_set );id_button--;break;
case 3:SignalButton ( button_set );PrintButton ( button_exit );id_button--;break;
case 5:SignalButton ( button_size );PrintButton ( button_size_min );PrintButton ( button_level );
Rectangle ( area_size );id_button--;break;
case 8:SignalButton ( button_level_n );PrintButton ( button_level_h );id_button--;break;
case 9:SignalButton ( button_level_h );PrintButton ( button_level_vh );id_button--;break;
}
}
void Signal::SignalS ( ) {
switch ( id_button ) {
case 1:SignalButton ( button_set );PrintButton ( button_start );id_button++;break;
case 2:SignalButton ( button_exit );PrintButton ( button_set );id_button++;break;
case 4:SignalButton ( button_level );PrintButton ( button_size );PrintButton ( button_level_n );
PrintButton ( button_level_h );PrintButton ( button_level_vh );id_button++;break;
case 7:SignalButton ( button_level_h );PrintButton ( button_level_n );id_button++;break;
case 8:SignalButton ( button_level_vh );PrintButton ( button_level_h );id_button++;break;
}
}
void Signal::SignalA ( ) {
switch ( id_button ) {
case 6:SignalButton ( button_size );PrintButton ( button_size_min );id_button = 4;break;
case 7:SignalButton ( button_level );PrintButton ( button_level_n );id_button = 5;break;
case 8:SignalButton ( button_level );PrintButton ( button_level_h );id_button = 5;break;
case 9:SignalButton ( button_level );PrintButton ( button_level_vh );id_button = 5;break;
}
}
void Signal::SignalD ( ) {
switch ( id_button ) {
case 4:SignalButton ( button_size_min );PrintButton ( button_size );id_button = 6;break;
case 5:SignalButton ( button_level_n );PrintButton ( button_level );id_button = 7;break;
}
}
void Signal::SignalEnd ( ) {
switch ( id_button ) {
case 1:WindowPlay ( );id_button = 10;id_window = 2;break;
case 2:WindowSet ( );id_button = 4;id_window = 3;break;
}
}
void Signal::SignalEsc ( ) {
switch ( id_window ) {
case 2:Rectangle ( area_main );WindowMain ( );id_button = 1;id_window = 1;
id_food = 1;number_score.number = 0;number_pass.number = 1;number_speed.number = 1;break;
case 3:Rectangle ( area_main );WindowMain ( );id_button = 1;id_window = 1;break;
}
}
void Draw::SnakePlay ( ) {
while ( 1 ) {
SetConsoleTextAttribute ( handle, 0xc0 );
SetPosition ( xy_snake.x, xy_snake.y );
cout << setw ( 2 ) << '\0';
Sleep ( 100 / number_speed.number );
while ( kbhit ( ) == 1 ) {
switch ( getch ( ) ) {
case 'w':id_snake = 4;break;
case 's':id_snake = 3;break;
case 'a':id_snake = 2;break;
case 'd':id_snake = 1;break;
}
}
SetConsoleTextAttribute ( handle, 0x70 );
SetPosition ( xy_snake.x, xy_snake.y );
cout << setw ( 2 ) << '\0';
switch ( id_snake ) {
case 1:xy_snake.x += 2;break;
case 2:xy_snake.x -= 2;break;
case 3:xy_snake.y++;break;
case 4:xy_snake.y--;break;
}
if ( xy_snake.x > ( ( area_play.x + area_play.width ) - 2 ) || xy_snake.x < area_play.x || xy_snake.y < area_play.y ||
xy_snake.y > ( area_play.height - 1 ) ) {
PrintButton ( button_gameover );
xy_snake = { 34, 15 };
break;
}
Food ( );
}
}
void Draw::Food ( ) {
while ( 1 ) {
isfood_random [ 0 ] = random ( 64 );
isfood_random [ 1 ] = random ( 64 );
if ( ( isfood_random [ 0 ] % 2 ) != 0 ) {
isfood_random [ 0 ]++;
}
if ( ( isfood_random [ 1 ] % 2 ) != 0 ) {
isfood_random [ 1 ]++;
}
if ( isfood_random [ 0 ] > 10 && isfood_random [ 1 ] > 10 ) {
break;
}
}
if ( id_food != 0 ) {
SetConsoleTextAttribute ( handle, 0xcf );
for ( int i = 0; i < 2; i++ ) {
xy_food [ i ] = { isfood_random [ i ], random ( 31 ) };
SetPosition ( xy_food [ i ].x, xy_food [ i ].y );
isfood_score [ i ] = random ( 100 );
cout << setw ( 2 ) << isfood_score [ i ];
}
id_food = 0;
}
else if ( xy_food [ 0 ].x == xy_snake.x && xy_food [ 0 ].y == xy_snake.y ) {
id_food = 1;
number_score.number += isfood_score [ 0 ];
SetConsoleTextAttribute ( handle, 0x70 );
SetPosition ( xy_food [ 1 ].x, xy_food [ 1 ].y );
cout << setw ( 2 ) << '\0';
PrintNumber ( number_score );
}
else if ( xy_food [ 1 ].x == xy_snake.x && xy_food [ 1 ].y == xy_snake.y ) {
id_food = 1;
number_score.number += isfood_score [ 1 ];
SetConsoleTextAttribute ( handle, 0x70 );
SetPosition ( xy_food [ 0 ].x, xy_food [ 0 ].y );
cout << setw ( 2 ) << '\0';
PrintNumber ( number_score );
}
if ( ( number_score.number > 1000 && number_pass.number == 1 ) ||
( number_score.number > 2000 && number_pass.number == 2 ) ||
( number_score.number > 3000 && number_pass.number == 3 ) ) {
number_pass.number++;
number_speed.number ++;
PrintNumber ( number_pass );
PrintNumber ( number_speed );
}
}
int main ( ) {
Draw draw;
Signal signal;
draw.Load ( );
while ( 1 ) {
signal.SignalOn ( );
}
return 0;
}