#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
// 引用 Windows Multimedia API
#pragma comment(lib,"Winmm.lib")
/***********宏定义区******************/
#define X 500 // 保存球点坐标的个数
#define Y 500
int len = 640;
int wide = 480;
MCI_PLAY_PARMS mciplay;//定义播放参数mciplay
/***********结构定义区****************/
struct food
{
int x; // 横坐标
int y; // 纵坐标
int flag; // 金币状态 1: 有金币; 0:没有金币
}food;
struct snake
{
int x[X]; // 球的横坐标
int y[Y];
int life; // 生命状态
int node; // 球的大小
char direction; // 球的方向
int score; // 分数
int grade; // 难度
int speed; // 速度
}snake;
/*************函数声明区**************/
void initsnake(); // 初始化一个球
void print_wall(); // 输出围墙
void out_food(); // 出现金币
void Gameover(); // 结束游戏
void Gamebegin(); // 开始游戏
void dead_case(); // 死亡情况(撞墙)
void eat_food(); // 吃金币
void init_data(); // 初始化数据
void get_direction(char ch); // 得到方向
void print_snake(); // 输出球
void print_score(); // 输出分数
void set_grade(); // 设置等级
void RealseMusic(LPCTSTR strResName,char *DeviceStr); // 播放资源文件中的音乐
void pass(); // 通关函数
/****************************************************/
// 提取指定模块中的资源文件
// 参数:
// strDstFile: 目标文件名。提取的资源将保存在这里;
// strResType: 资源类型;
// strResName: 资源名称;
// 返回值:
// true: 执行成功;
// false: 执行失败。
/****************************************************/
bool ExtractResource(LPCTSTR strDstFile, LPCTSTR strResType, LPCTSTR strResName); // 提取资源到临时文件
/************函数定义区***************/
void pass()
{
if (snake.speed == 20)
{
EndBatchDraw();
IMAGE img;
loadimage(&img,"IMAGE","PASS",len,wide,true); // s输出通关图片
putimage(0,0,&img);
_getch();
exit(0);
}
}
bool ExtractResource(LPCTSTR strDstFile, LPCTSTR strResType, LPCTSTR strResName)
{
// 创建文件
HANDLE hFile = ::CreateFile(strDstFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return false;
// 查找资源文件中、加载资源到内存、得到资源大小
HRSRC hRes = ::FindResource(NULL, strResName, strResType);
HGLOBAL hMem = ::LoadResource(NULL, hRes);
DWORD dwSize = ::SizeofResource(NULL, hRes);
// 写入文件
DWORD dwWrite = 0; // 返回写入字节
::WriteFile(hFile, hMem, dwSize, &dwWrite, NULL);
::CloseHandle(hFile);
return true;
}
void RealseMusic(LPCTSTR strResName,char *DeviceStr)
{
// 产生临时文件的文件名
TCHAR tmpmp3[_MAX_PATH];
::GetTempPath(_MAX_PATH, tmpmp3);
_tcscat_s(tmpmp3,strResName); // VC 请用 _tcscat函数
// 将 MP3 资源提取为临时文件
ExtractResource(tmpmp3, "MP3",strResName);
// 打开音乐
TCHAR mcicmd[300];
_stprintf_s(mcicmd,"open \"%s\" alias %s",tmpmp3,DeviceStr);
mciSendString(mcicmd, NULL, 0, NULL);
// 播放音乐
// mciSendString("play mymusic", NULL, 0, NULL);
}
void set_grade()
{
int grade = 0;
if (snake.speed > 30)
{
grade = snake.score / 100 + 1;
if (snake.grade != grade)
{
snake.grade = grade; // 最高只有7级
snake.speed -= 30;
}
}
}
void print_score()
{
char score[10] = "0";
char grade[3] = "0";
int x = 0, y1 = 0,y2 = 0;
x =( len /3 + len % 3) * 2;
y1 = wide / 5;
y2 = wide / 3;
set_grade();
_itoa_s(snake.score,score,10);
_itoa_s(snake.grade,grade,10);
setbkmode(TRANSPARENT); // 设置文字背景透明
setcolor(RGB(255,255,0)); // 设置文字颜色
outtextxy(x + len / 10,y1,"分数:");
outtextxy(x + len / 6,y1,score);
outtextxy(x + len / 10,y2,"操作说明");
outtextxy(x + len / 10,y2 + 20,"a:向左走");
outtextxy(x + len / 10,y2 + 40,"d:向右走");
outtextxy(x + len / 10,y2 + 60,"w:向上走");
outtextxy(x + len / 10,y2 + 80,"s:向下走");
outtextxy(x + len / 10,y1 * 4,"等级:");
outtextxy(x + len / 10 + 40,y1 * 4,grade);
outtextxy(x + len / 10 + 50,y1 * 4,"级");
}
void print_snake()
{
int i;
setfillcolor(BLACK); // 设置当前填充色为黑色
/* 输出球*/
for (i = 0; i < snake.node; i++)
fillrectangle(snake.x[i],snake.y[i],snake.x[i] + 10,snake.y[i] + 10);
for (i = snake.node; i > 0; i--) // 球体坐标
{
snake.x[i] = snake.x[i - 1];
snake.y[i] = snake.y[i - 1];
}
}
void get_direction(char ch)
{
/* 排除反方向 */
if (snake.direction != 'a' && ch == 'd')
snake.direction = 'd';
else if (snake.direction != 'd' && ch == 'a')
snake.direction = 'a';
else if (snake.direction != 'w' && ch == 's')
snake.direction = 's';
else if (snake.direction != 's' && ch == 'w')
snake.direction = 'w';
/* 球动过程中的方向 */
switch (snake.direction)
{
case 'a': snake.x[0] -= 10; break;
case 'd': snake.x[0] += 10;break;
case 'w': snake.y[0] -= 10;break;
case 's': snake.y[0] += 10;break;
}
}
void init_data()
{
/***初始化***/
snake.score = 0;
snake.x[0] = 20,snake.y[0] = 30;
snake.node = 1;
snake.life = 1; // 1表示活着
food.flag = 0;
snake.grade = 1;
snake.speed = 200;
}
void eat_food()
{
mciplay.dwFrom = 0;
/* 吃掉金币 */
if (snake.x[0] == food.x && snake.y[0] == food.y)
{
// 播放吃的音乐
mciSendString("seek AteMusic to 0",0,0,0);
mciSendString("play AteMusic",NULL,0,0);
setfillcolor(RGB(219,49,0));
fillrectangle(food.x,food.y,food.x + 10,food.y + 10); // 擦掉食金币
snake.node++; // 球大小加1
food.flag = 0; // 改变金币状态
snake.score += 10; // 改变分数
}
}
void dead_case()
{
int i = 0;
int x = 0;
x =( len /3 + len % 3) * 2;
/* 判断撞到撞墙 */
for (i = 2; i < snake.node; i++)
{
if (snake.x[i] == snake.x[0] && snake.y[i] == snake.y[0])
{
snake.life = 0;
break;
}
}
/* 判断是否撞墙 */
if (snake.x[0] > x || snake.x[0] < 10 || snake.y[0] < 10 || snake.y[0] > 470)
snake.life = 0;
}
void Gamebegin()
{
IMAGE image;
MOUSEMSG msg;
// 初始化
RealseMusic("BeginMusic.mp3","BeginMusic");
RealseMusic("AteMusic.mp3","AteMusic");
// 播放开始的音乐
mciSendString("play BeginMusic", NULL, 0, NULL);
loadimage(&image,"IMAGE","StartCover",len,wide,true); // s输出开始图片
putimage(0,0,&image);
// setbkmode(TRANSPARENT); // 设置文字背景透明
// setcolor(RGB(255,255,0)); // 设置文字颜色
// outtextxy(len / 3 + 50,wide * 4 / 5,"按任意键继续");
while (1) // 等待鼠标点击
{
msg = GetMouseMsg();
if (msg.uMsg ==WM_LBUTTONDOWN)
break;
}
mciSendString("close BeginMusic",NULL,0,NULL); // 关闭开始音乐
setbkcolor(RGB(219,49,0)); // 设置屏幕背景色为褐色
cleardevice();
print_wall(); // 输出围墙
}
void Gameover()
{
cleardevice(); // 清屏
IMAGE image; // 定义图片对像
char score[10] = "0"; // 临时存储成绩
loadimage(&image,"IMAGE","End",len,wide,true); // 获取图片
putimage(0,0,&image); // 输出图片
setcolor(RED);
_itoa_s(snake.score,score,10); // 转换分数为自符
outtextxy(270,160,"分数:"); // 输出分数
outtextxy(320,160,score);
outtextxy(270,180,"GAME OVER");
}
void out_food()
{
int x = 0;
x =( len /3 + len % 3) * 2;
srand((unsigned)time(NULL));
if (food.flag == 0) // 获取金币坐标
{
food.x = rand() % (x - 30) + 10; // 避免出现在围墙范围
food.y = rand() % 450 + 10;
food.flag = 1;
}
while (food.x % 10 != 0) // 保证金币在格子里面要不吃不到
food.x++;
while (food.y % 10 != 0)
food.y++;
setfillcolor(RED);
if (food.flag == 1) // 输出金币
fillrectangle(food.x,food.y,food.x + 10,food.y + 10);
}
/* 画出围墙 */
void print_wall()
{
int i =0;
int x = 0;
x =( len /3 + len % 3) * 2;
setfillcolor(RGB(220,115,10)); // 设置围墙填充色
for (i = 0; i < wide; i += 10)
{
fillrectangle(0,i,10,i + 10); // 左边围墙
fillrectangle(x,i,x + 10,i + 10); // 中间围墙
fillrectangle(len - 10,i,len,i + 10); // 右边围墙
}
for (i = 0; i < len; i += 10)
{
fillrectangle(i,0,i + 10,10); // 上边围墙
fillrectangle(i,wide - 10,i + 10,wide); // 下边围墙
}
}
void snake_game()
{
char ch = '0';
init_data();
print_score();
setfillcolor(BLACK); // 设置当前填充色为黑色
/* 开始时显示一个点球 */
solidrectangle(snake.x[0],snake.y[0],snake.x[0] + 10,snake.y[0] + 10);
snake.direction = _getch(); // 得到方向
BeginBatchDraw();
while (ch != 27) // 按下esc键就退出循环
{
print_wall();
out_food(); // 输出金币
if (_kbhit())
ch = _getch();
get_direction(ch);
print_snake();
dead_case(); // 球是否撞墙
/* 判断生命状态 */
if (snake.life == 0)
break;
eat_food();
print_score();
FlushBatchDraw();
Sleep(snake.speed);
cleardevice();
pass(); // 判断通关
}
EndBatchDraw();
}
void main()
{
initgraph(len,wide);
Gamebegin();
snake_game();
Gameover();
_getch();
closegraph();
}