所用知識:
- 一維數組的使用
- 結構體的使用
- 播放音樂函數的使用
- 電腦按鍵的檢測
- 窗口光標座標函數的使用
相關函數講解
1.光標移動到某一指定座標的函數
#include <windows.h>//座標的API
void gotoxy(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord; //定義結構體coord (座標系coord)
coord.X = x; //橫座標x
coord.Y = y; //縱座標y
SetConsoleCursorPosition(handle, coord); //移動光標
}
2.kbhit按鍵檢測函數
#include <conio.h>//按鍵
引用一下其他網友的解答:
#include <conio.h>
#include
using namespace std;
int main()
{
while(!kbhit()) //當沒有鍵按下
{
cout<<“無鍵按下”<<endl;
}
cout<<“有鍵按下”<<endl; //有鍵按下時輸出這
system(“pause”);
}
kbhit() 在執行時,檢測是否有按鍵按下,有按下返回非0值,一般是1
沒有按下返回0;是非阻塞函數
getch() 在執行時,檢測按下什麼鍵,如果不按鍵該函數不返回;是阻塞函數
類似地
在Tc2.0中有一個處理鍵盤輸入的函數bioskey();
int bioskey(int cmd);
當cmd爲1時,bioskey()檢測是否有鍵按下。沒有鍵按下時返回0;有鍵按下時返回按鍵碼(
任何按鍵碼都不爲0),但此時並不將檢測到的按鍵碼從鍵盤緩衝隊列中清除。 是非阻塞參數。
當cmd爲0時,bioskey()返回鍵盤緩衝隊列中的按鍵碼,並將此按鍵碼從鍵盤緩衝隊列中清
除。如果鍵盤緩衝隊列爲空,則一直等到有鍵按下,纔將得到的按鍵碼返回。是阻塞調用。
//個人理解kbhit()有點像bioskey(1)
具體搜索bioskey詞條吧 :)
3.playsound函數
引用一下這個函數的詳細說明
所需頭文件,順序要這樣子
#include <windows.h>//座標的API
#include <MMSystem.h>
#pragma comment(lib,"winmm.lib")
在main函數裏面使用,m1.wav爲文件名,我放在跟cpp文件同目錄下來了
PlaySound(L"m1.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//播放聲音
基本要素
- 畫地圖(包含剛開始的畫蛇和食物)
- 按鍵檢測
- 產生食物
- 判斷蛇的狀態
代碼
game.cpp
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>//座標的API
#include <conio.h>//按鍵
#include <time.h>//產生隨機數要用到
#include"game.h"
SNAKE snake;//定義SNAKE 類型的snake,不可在.h文件中定義
FOOD food;//同上
int score = 0;//得分
char key = 'W';//鍵盤獲得的方向
char tempkey = 'W';//當前蛇行進方向
bool changeflag = false;//用於有無喫到食物的標誌
//到某一指定座標的函數
void gotoxy(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord; //定義結構體coord (座標系coord)
coord.X = x; //橫座標x
coord.Y = y; //縱座標y
SetConsoleCursorPosition(handle, coord); //移動光標
}
//畫地圖
void drawmap()
{
gotoxy(50, 8);
printf("——遊戲開始——");
gotoxy(43, 10);
printf("——切換鍵盤爲大寫字母模式——");
gotoxy(51, 12);
system("pause");
system("CLS");
for (int i = 0; i <= MAP_HIGHT; i++)
{
gotoxy(0, i);
printf("■");
gotoxy(MAP_WIDTH, MAP_HIGHT-i);//不同方向打印
printf("■");
Sleep(20);//有一個一個打印的延時效果
}
for (int i = 0; i < MAP_WIDTH; i += 2)
{
gotoxy(i, 0);
printf("■");//佔兩個橫座標,一個縱座標
gotoxy(MAP_WIDTH - i, MAP_HIGHT);
printf("■");
Sleep(20);
}
//打印說明
gotoxy(100, 7);
printf("按鍵說明:");
gotoxy(100, 10);
printf("W:向上");
gotoxy(100, 13);
printf("A:向左");
gotoxy(100, 16);
printf("S:向下");
gotoxy(100, 19);
printf("D:向右");
gotoxy(100, 22);
printf("當前分數:%d", score);
//初始畫蛇頭
snake.x[0] = MAP_WIDTH / 2 +1;//蛇頭的座標必須是偶數,因爲■橫座標是佔了兩節,不明白的話把1去掉試試效果
snake.y[0] = MAP_HIGHT / 2;
gotoxy(snake.x[0], snake.y[0]);
printf("●");
//打印蛇身,方向要與初始的方向一致
for (int i = 1; i < snake.len; i++) {
snake.x[i] = snake.x[0];
snake.y[i] = snake.y[0] + i;
gotoxy(snake.x[i], snake.y[i]);
printf("●");
}
//初始畫食物
food.x = MAP_WIDTH / 4;
food.y = MAP_HIGHT / 2;
gotoxy(food.x, food.y);
printf("◆");
}
void KeyDown()
{ //無按鍵操作
if (_kbhit())
{
fflush(stdin);
key = _getch();
//當行進方向與按鍵方向相反時防止自殺現象
if (key != 'w' && key != 'W' && key != 's' && key != 'S' && key != 'A' && key != 'a' && key != 'd' && key != 'D')
key = tempkey;
else {
if (tempkey == 'w' || tempkey == 'W')
if (key == 's' || key == 'S')
key = tempkey;
if (tempkey == 's' || tempkey == 'S')
if (key == 'w' || key == 'W')
key = tempkey;
if (tempkey == 'a' || tempkey == 'A')
if (key == 'D' || key == 'd')
key = tempkey;
if (tempkey == 'D' || tempkey == 'd')
if (key == 'a' || key == 'A')
key = tempkey;
tempkey = key;//非wasd鍵
}
}
if (!changeflag)
{
gotoxy(snake.x[snake.len-1 ], snake.y[snake.len-1 ]);//總共有len個蛇的身體單元●,因爲數組,最後一個是len-1
printf(" ");//沒有喫到食物的時候要去最後把蛇尾擦除
}
else
{
snake.x[snake.len] = snake.x[snake.len - 1];//喫到食物後len+1
snake.y[snake.len] = snake.y[snake.len - 1];
snake.len++;
}
for (int i = snake.len - 1; i > 0; i--)
{
snake.x[i] = snake.x[i - 1];
snake.y[i] = snake.y[i - 1];
}
switch (key)
{
case 'W':
case 'w': snake.y[0]--; break;//注意gotoxy的座標原點是左上角
case 'S':
case 's': snake.y[0]++; break;
case 'A':
case 'a': snake.x[0] -= 2; break;//佔兩個字符
case 'D':
case 'd': snake.x[0] += 2; break;
default: break;
}
gotoxy(snake.x[0], snake.y[0]);
printf("●");
changeflag = false;
}
void CreatFood()
{
//隨機種子,產生隨機數
srand((unsigned)time(NULL));
if (snake.x[0] == food.x&&snake.y[0] == food.y)//判斷喫到食物
{
score++;
gotoxy(100, 22);
printf("當前分數:%d", score);//打印分數
if (score % 10 == 0)
{
snake.speed -= 10;
}
while (1)
{
bool flag = 1;
food.x = rand() % (MAP_WIDTH - 4) + 2;//減掉左右兩列4個座標,然後加上最左一列2個座標就是寬了
food.y = rand() % (MAP_HIGHT - 2) + 1;
for (int i = 0; i < snake.len; i++)
{
if (food.x == snake.x[i] && food.y == snake.y[i])//食物不能出現在自己身上
{
flag = 0;
break;
}
}
if (flag&&food.x % 2 == 0)//食物x座標要爲偶數
{
break;
}
}
gotoxy(food.x, food.y);
printf("◆");
changeflag = true;
}
}
int SnakeState(void)
{
//判斷是否撞牆
if (snake.x[0] == 0 || snake.x[0] == MAP_WIDTH || snake.y[0] == 0 || snake.y[0] == MAP_HIGHT)
return false;
for (int i = 1; i < snake.len; i++)
{
if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
return false;
}
return true;
}
game.h
#pragma once
#ifndef GAME_H
#define GAME_H
#define MAP_HIGHT 29
#define MAP_WIDTH 90
#define snake_max_len 200
#define snake_begin_len 3
#define snake_begin_speed 200
struct SNAKE
{
int len = snake_begin_len;
int x[snake_max_len];
int y[snake_max_len];
int speed = snake_begin_speed;
};
struct FOOD
{
int x;
int y;
};
extern SNAKE snake;
extern FOOD food;
extern int score;
void gotoxy(int x, int y);
void drawmap(void);
void KeyDown(void);
void CreatFood(void);
int SnakeState(void);
#endif // !GAME_H
main.cpp
#include <stdio.h>
#include <windows.h>//座標的API
#include <MMSystem.h>
#pragma comment(lib,"winmm.lib")
#include "game.h"
int main()
{
PlaySound(L"m1.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);//播放聲音
//隱藏光標
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut, &cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(hOut, &cci);
system("CLS");
drawmap();
while (1)
{
KeyDown();
Sleep(snake.speed);
CreatFood();
if (SnakeState()==false)
{
break;
}
}
system("CLS");
gotoxy(50, 8);
printf("——遊戲結束——");
gotoxy(52, 10);
printf("你的分數爲:%d\n", score);
gotoxy(51, 12);
system("pause");
return 0;
}
效果圖
一個.cpp文件的版本(差別不大)
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>//座標的API
#include <MMSystem.h>
#pragma comment(lib,"winmm.lib")
#include <conio.h>//按鍵
#include <time.h>
#define MAP_HIGHT 29
#define MAP_WIDTH 90
#define snake_max_len 200
#define snake_begin_len 3
#define snake_begin_speed 200
int score=0;//得分
char key = 'W';
char tempkey = 'W';
bool changeflag = false;
struct SNAKE
{
int len= snake_begin_len;
int x[snake_max_len];
int y[snake_max_len];
int speed = snake_begin_speed;
}snake;
struct FOOD
{
int x;
int y;
}food;
void gotoxy(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord; //定義結構體coord (座標系coord)
coord.X = x; //橫座標x
coord.Y = y; //縱座標y
SetConsoleCursorPosition(handle, coord); //移動光標
}
void drawmap()
{
for (int i = 0; i <= MAP_HIGHT; i++)
{
gotoxy(0, i);
printf("■");
gotoxy(MAP_WIDTH, i);
printf("■");
Sleep(20);
}
for (int i = 0; i < MAP_WIDTH; i+=2)
{
gotoxy(i, 0);
printf("■");
gotoxy(MAP_WIDTH -i, MAP_HIGHT);
printf("■");
Sleep(20);
}
gotoxy(100, 7);
printf("按鍵說明:");
gotoxy(100, 10);
printf("W:向上");
gotoxy(100, 13);
printf("A:向左");
gotoxy(100, 16);
printf("S:向下");
gotoxy(100, 19);
printf("D:向右");
gotoxy(100, 22);
printf("當前分數:%d", score);
//畫蛇
snake.x[0] = MAP_WIDTH/2+1;//偶數
snake.y[0] = MAP_HIGHT/2;
gotoxy(snake.x[0], snake.y[0]);
printf("●");
for (int i = 1; i < snake.len; i++) {
snake.x[i] = snake.x[0];
snake.y[i] = snake.y[0] + i;
gotoxy(snake.x[i], snake.y[i]);
printf("●");
}
//畫食物
food.x = MAP_WIDTH / 4;
food.y = MAP_HIGHT / 2;
gotoxy(food.x, food.y);
printf("◆");
}
void KeyDown()
{ //無按鍵操作
if (_kbhit())
{
fflush(stdin);
key = _getch();
if (key != 'w' && key != 'W' && key != 's' && key != 'S' && key != 'A' && key != 'a' && key != 'd' && key != 'D')
key = tempkey;
else {
if (tempkey == 'w' || tempkey == 'W')
if (key == 's' || key == 'S')
key = tempkey;
if (tempkey == 's' || tempkey == 'S')
if (key == 'w' || key == 'W')
key = tempkey;
if (tempkey == 'a' || tempkey == 'A')
if (key == 'D' || key == 'd')
key = tempkey;
if (tempkey == 'D' || tempkey == 'd')
if (key == 'a' || key == 'A')
key = tempkey;
tempkey = key;//非wasd鍵
}
}
if (!changeflag)
{
gotoxy(snake.x[snake.len-1], snake.y[snake.len - 1]);
printf(" ");
}
else
{
snake.x[snake.len] = snake.x[snake.len-1];
snake.y[snake.len] = snake.y[snake.len-1];
snake.len++;
}
for (int i = snake.len-1; i >0; i--)
{
snake.x[i] = snake.x[i - 1];
snake.y[i] = snake.y[i - 1];
}
switch (key)
{
case 'W':
case 'w': snake.y[0]--; break;
case 'S':
case 's': snake.y[0]++; break;
case 'A':
case 'a': snake.x[0]-=2; break;//佔兩個字符
case 'D':
case 'd': snake.x[0]+=2; break;
default: break;
}
gotoxy(snake.x[0], snake.y[0]);
printf("●");
changeflag = false;
}
void CreatFood()
{
srand((unsigned)time(NULL));
if (snake.x[0]==food.x&&snake.y[0] == food.y)
{
//PlaySound(L"m2.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
score++;
gotoxy(100, 22);
printf("當前分數:%d", score);//打印分數
if (score%15==0)
{
snake.speed -= 20;
}
while (1)
{
bool flag = 1;
food.x = rand() % (MAP_WIDTH - 4) + 2;
food.y = rand() % (MAP_HIGHT - 2) + 1;
for (int i = 0; i < snake.len; i++)
{
if (food.x ==snake.x[i] && food.y == snake.y[i])
{
flag = 0;
break;
}
}
if (flag&&food.x % 2 == 0)
{
break;
}
}
gotoxy(food.x, food.y);
printf("◆");
changeflag = true;
}
}
int SnakeState(void)
{
if (snake.x[0] == 0 || snake.x[0] == MAP_WIDTH || snake.y[0] == 0 || snake.y[0] == MAP_HIGHT)
return false;
for (int i = 1; i < snake.len; i++)
{
if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
return false;
}
return true;
}
int main()
{
PlaySound(L"m1.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
//隱藏光標
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut, &cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(hOut, &cci);
system("CLS");
drawmap();
while (1)
{
KeyDown();
Sleep(snake.speed);
CreatFood();
if (SnakeState()==false)
{
break;
}
}
system("CLS");
gotoxy(50, 8);
printf("——遊戲結束——");
gotoxy(52, 10);
printf("你的分數爲%d\n", score);
system("pause");
return 0;
}
單文件沒有詳細的講解,講解看看多文件版本。