近期应该没时间玩这个了。暂且记录下当时的一些细节。
对于代码中各模块的代码实现,见自己的印象笔记“游戏开发日记”部分。
如实在忘得太多,可以重学。
附学习链接:https://study.163.com/course/courseMain.htm?courseId=1004489035
关于EasyX,dev-c这类轻量级编译器不能使用,我用的VS。
EasyX的具体函数使用,可见其官方手册。
链接:https://docs.easyx.cn/en-us/intro
右上角语言切换成中文,即可下载中文手册。
若想做的完整性,将文件夹打包成.exe安装文件,可使用NSIS.
《丧尸围城》代码
#include<graphics.h>
#include<conio.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
#include<stdio.h>
#pragma comment(lib,"Winmm.lib") //引用Windows Multimedia API
//定义全局变量
#define High 700 //画布高度
#define Width 738 //画布宽度
IMAGE img_bk; //画布背景
double K_x, K_y; //主角K的位置
IMAGE img_K; //K的图像
int wall_x, wall_y; //围墙位置
IMAGE img_wall; //围墙图像
char Input; //交互输入
int K_step; //K的步长
double bullet_x, bullet_y; //子弹弹尾坐标
int bulletLength; //子弹长度
int K_Width; //K的宽度
int K_High; //K的高度
IMAGE img_enemy; //敌人图像
double enemy_x, enemy_y; //敌人的位置
int enemy_Width; //敌人的宽度
int enemy_High; //敌人的高度
int isKilled; //击杀标志
float enemy_velocity; //敌方移动速度
int gun_direction; //枪的方向指代参数,从上面开始,顺时针旋转,依次为1,2,3,4
int score; //得分
int count1; //延时
void startup() //数据初始化
{
srand(time(NULL)); //确定随机数种子
K_x = 500, K_y = 500; //K的位置
loadimage(&img_K,_T("E:\\丧尸围城\\my_game_img\\K1.jpg")); //装载K图像
loadimage(&img_enemy, _T("E:\\丧尸围城\\my_game_img\\enemy.jpg")); //装载敌人图像
loadimage(&img_wall, _T("E:\\丧尸围城\\my_game_img\\wall1.jfif")); //装载围墙图像 尺寸:36*37
loadimage(&img_bk, _T("E:\\丧尸围城\\my_game_img\\background.jpg")); //装载画布背景
K_step = 15; //初始化K的步长
bulletLength = 8; //初始化子弹长度
K_High = 28; //K的高度
K_Width = 28; //K的宽度
enemy_x = 100; //初始化敌人位置
enemy_y = 100;
enemy_Width = 28; //指定敌人的高度和宽度
enemy_High = 27;
enemy_velocity = 0; //初始化敌方移动速度
score = 0; //初始化分数
count1 = 0;
isKilled = 0;
mciSendString("open E:\\丧尸围城\\my_game_music\\yell.mp3 alias bkmusic", NULL, 0, NULL); //背景音乐
mciSendString("play bkmusic ", NULL, 0, NULL); //播放一次
BeginBatchDraw();
}
void chose_show()
{
setbkcolor(WHITE); //设置白色背景
cleardevice(); //清屏
setbkmode(TRANSPARENT); //字体边框透明
settextcolor(BLACK); //字体黑色
settextstyle(35, 18, "黑体"); //字体样式
/************游戏说明**************/
outtextxy(50, 100, "Mr.K:");
outtextxy(70, 135, "我想和你玩个游戏");
outtextxy(70, 170, "你要杀死20只已经腐化的丧尸");
outtextxy(70, 205, "然后我们再谈别的");
outtextxy(70, 240, "嘿嘿嘿");
outtextxy(70, 310, "当然,我总要给你写提示");
outtextxy(70, 345, "以防你死的那么惨");
outtextxy(70, 380, "按下 w,s,a,d 进行移动,空格射击");
outtextxy(70, 415, "你每杀死5个敌人,怨念的力量都会增强");
outtextxy(70, 450, "准备好就按下空格吧");
outtextxy(70, 485, "最后,祝你好运");
}
void chose() //选择
{
while (1)
{
char Input;
Input = _getch();
if (Input == ' ')
break;
}
}
void show() //显示界面
{
putimage(0, 0, &img_bk); //显示画布背景
for (wall_y = 0; wall_y <= 700; wall_y++) //显示围墙
{
for (wall_x = 0; wall_x <= 800; wall_x++)
{
if (wall_y == 0 || wall_x == 0 || wall_y == High-37 || wall_x == Width-36) // 画上四周的围墙
{
putimage(wall_x, wall_y, &img_wall);
}
}
}
putimage(K_x, K_y, &img_K); //显示K先生
if (isKilled == 0) //敌人未被击杀
{
putimage((int)enemy_x, (int)enemy_y, &img_enemy); //显示敌人
}
setbkmode(TRANSPARENT);
settextstyle(20, 10, "黑体"); //字体样式
outtextxy(40, 640, "得分:"); //显示分数
char s[5];
sprintf_s(s, "%d", score);
outtextxy(94, 641, s);
FlushBatchDraw();
}
void play_foot() //走动音效
{
mciSendString("close music_foot", NULL, 0, NULL); //先把前面一次的音乐关闭 (因为只是一个音效)
mciSendString("open E:\\丧尸围城\\my_game_music\\foot.mp3 alias music_foot", NULL, 0, NULL); // 打开走动音乐
mciSendString("play music_foot", NULL, 0, NULL); // 仅播放一次
}
void shoot() //射击函数
{
static int speed = 0; //限制子弹速度的循环量
if (gun_direction == 1)
{
for (bullet_x = K_x + 10, bullet_y = K_y - 1; bullet_y - bulletLength >= 37; bullet_y -= 3)
{
setlinecolor(BLACK);
line(bullet_x, bullet_y, bullet_x, bullet_y - bulletLength);
FlushBatchDraw();
if ((bullet_x >= enemy_x && bullet_x <= enemy_x + enemy_Width) && (bullet_y - bulletLength <= enemy_y + enemy_High)) //弹头碰到敌人
{
isKilled = 1; //已击杀
score++;
break; //停止输出子弹
}
while (speed < 200)
{
speed++;
}
if (speed == 200)
{
setlinecolor(RGB(214, 215, 210)); //遮挡之前的子弹,形成动画效果
line(bullet_x, bullet_y, bullet_x, bullet_y - bulletLength);
speed = 0;
}
}
}
else if (gun_direction == 2)
{
for (bullet_x = K_x + K_Width + 5, bullet_y = K_y + 5; bullet_x + bulletLength <= Width - 36; bullet_x += 3)
{
setlinecolor(BLACK);
line(bullet_x, bullet_y, bullet_x + bulletLength, bullet_y);
FlushBatchDraw();
if (bullet_x + bulletLength >= enemy_x && (bullet_y <= enemy_y + enemy_High && bullet_y >= enemy_y)) //弹头碰到敌人
{
isKilled = 1; //已击杀
score++;
break; //停止输出子弹
}
while (speed < 200)
{
speed++;
}
if (speed == 200)
{
setlinecolor(RGB(214, 215, 210)); //遮挡之前的子弹,形成动画效果
line(bullet_x, bullet_y, bullet_x + bulletLength, bullet_y);
speed = 0;
}
}
}
else if (gun_direction == 3)
{
for (bullet_x = K_x + 5, bullet_y = K_y + K_High + 5; bullet_y + bulletLength <= High - 37; bullet_y += 3)
{
setlinecolor(BLACK);
line(bullet_x, bullet_y, bullet_x, bullet_y + bulletLength);
FlushBatchDraw();
if ((bullet_x >= enemy_x && bullet_x <= enemy_x + enemy_Width) && bullet_y + bulletLength >= enemy_y) //弹头碰到敌人
{
isKilled = 1; //已击杀
score++;
break; //停止输出子弹
}
while (speed < 200)
{
speed++;
}
if (speed == 200)
{
setlinecolor(RGB(214, 215, 210)); //遮挡之前的子弹,形成动画效果
line(bullet_x, bullet_y, bullet_x, bullet_y + bulletLength);
speed = 0;
}
}
}
else
{
for (bullet_x = K_x - 5, bullet_y = K_y + +5; bullet_x - bulletLength >= 36; bullet_x -= 3)
{
setlinecolor(BLACK);
line(bullet_x, bullet_y, bullet_x - bulletLength, bullet_y);
FlushBatchDraw();
if (bullet_x - bulletLength <= enemy_x + enemy_Width && (bullet_y >= enemy_y && bullet_y <= enemy_y + enemy_High)) //弹头碰到敌人
{
isKilled = 1; //已击杀
score++;
break; //停止输出子弹
}
while (speed < 200)
{
speed++;
}
if (speed == 200)
{
setlinecolor(RGB(214, 215, 210)); //遮挡之前的子弹,形成动画效果
line(bullet_x, bullet_y, bullet_x - bulletLength, bullet_y);
speed = 0;
}
}
}
}
void updateWithoutInput() //无交互更新 (可以写一些自动变的代码,比如敌人自己向下走)
{
static int count = 0; //在击杀后移动两回合再产生新敌人
if (isKilled == 1)
{
count++;
if (count == 5)
{
enemy_x = rand() % 400 + 50; //随机产生敌人
enemy_y = rand() % 400 + 50; //为什么延时产生不起作用?
count = 0;
isKilled = 0;
}
}
else
{
count1++;
if (count1 == 100)
{
if (fabs((double)enemy_x - (double)K_x) >= fabs((double)enemy_y - (double)K_y)) //敌方向着K移动
{
if (enemy_x > K_x)
{
enemy_x -= enemy_velocity;
}
else if (enemy_x < K_x)
{
enemy_x += enemy_velocity;
} //等于就不变
}
else
{
if (enemy_y > K_y)
{
enemy_y -= enemy_velocity;
}
else if (enemy_y < K_y)
{
enemy_y += enemy_velocity;
}
}
count1 = 0;
}
if ((enemy_x + enemy_Width / 2 >= K_x && enemy_x + enemy_Width / 2 <= enemy_x + K_Width) && (enemy_y + enemy_High / 2 >= K_y && enemy_y + enemy_High / 2 <= K_y + K_High))
{
/*mciSendString("close bkmusic", NULL, 0, NULL); //先把前面一次的音乐关闭 (因为只是一个音效)
mciSendString("open E:\\丧尸围城\\my_game_music\\death.mp3 alias music_death", NULL, 0, NULL); // 打开死亡音乐
mciSendString("play music_death", NULL, 0, NULL); // 仅播放一次
Sleep(100);
*/
//exit(0); //人物死亡,game over !
}
}
if (score!= 0 && score % 5 == 0)
{
enemy_velocity += 0.2;
}
}
void updateWithInput() //交互更新
{
if (_kbhit())
{
Input = _getch();
switch (Input)
{
case 'w':
{
K_y -= K_step; //移动
gun_direction = 1; //确定枪的朝向
//play_foot(); //播放走动音效
FlushBatchDraw();
break;
}
case 's':
{
K_y += K_step;
gun_direction = 3;
//play_foot();
FlushBatchDraw();
break;
}
case 'a':
{
K_x -= K_step;
gun_direction = 4;
//play_foot();
FlushBatchDraw();
break;
}
case 'd':
{
K_x += K_step;
gun_direction = 2;
//play_foot();
FlushBatchDraw();
break;
}
case ' ':
{
setlinestyle(PS_SOLID, 2); //设置子弹为实线,宽度2
//播放射击音效
mciSendString("close music_shoot", NULL, 0, NULL); //先把前面一次的音乐关闭 (因为只是一个音效)
mciSendString("open E:\\丧尸围城\\my_game_music\\shoot.mp3 alias music_shoot", NULL, 0, NULL); // 打开走动音乐
mciSendString("play music_shoot", NULL, 0, NULL); // 仅播放一次
//
shoot();
FlushBatchDraw();
break;
}
}
}
FlushBatchDraw();
}
void gameover() //游戏结束
{
EndBatchDraw();
_getch(); //任意键结束
closegraph();
}
int main()
{
initgraph(Width, High); //创建画布
chose_show(); //选择界面
chose(); //选择模式
startup(); //数据初始化
while (1)
{
show(); //显示界面
updateWithoutInput(); //无交互更新
updateWithInput(); //交互更新
//updateWithoutInput(); //无交互更新
}
gameover(); //游戏结束
return 0;
}