首先在main函数里写下天天酷跑的整个框架,比如初始化,更新偏移量和背景图,检查分数和死亡之类的,然后将这些函数放入死循环,一次次的迭代
int main(void) {
int timer = 0;//计时
init();
loadimage(0,"res/over.png");//初始化游戏界面
system("pause");
while (true) {
KeyEvent();
timer += getDelay();//得到上一次调用这个函数到现在的毫秒数
if (timer > 15) {
timer = 0;
update = true;
}
if (update) {
update = false;
BeginBatchDraw();//批量加载,避免卡顿
UpdateBg();//更新背景图
updateHero();
updateBlood();
updateScore();
checkWin();
ShowEnemy();
EndBatchDraw();
UpdateXY();//更新XY的偏移量
checkOver();
CheckHit();
checkScore();
}
}
system("pause");
return 0;
}
我们应该做出整个程序的初始化,为接下来的函数做准备
void init() {
char name[64];
initgraph(WIN_WIDTH, WIN_HEIGHT);
for (int i = 0; i != 3; ++i) {
sprintf_s(name, "res/bg%03d.png", i + 1);
loadimage(&bg_image[i], name);
bg_x[i] = 0;
}
//加载人物动作
for (int i = 0; i != 12; ++i) {
sprintf_s(name, "res/hero%d.png", i + 1);
loadimage(&hero_image[i], name);
}
IMAGE imgTurtle;
loadimage(&imgTurtle, "res/t1.png");
vector<IMAGE> imgturtleArray;
imgturtleArray.push_back(imgTurtle);
obstacle_image.push_back(imgturtleArray);
IMAGE imgLion;
vector<IMAGE> imgLionArray;
for (int i = 0; i != 6; ++i) {
sprintf_s(name, "res/p%d.png", i + 1);
loadimage(&imgLion, name);
imgLionArray.push_back(imgLion);
}
obstacle_image.push_back(imgLionArray);
//一开始每个障碍物都不能出现
for (int i = 0; i != OBSTACLE_COUNT; ++i) {
obstacles[i].exist = false;
}
//加载下蹲动作
loadimage(&down_image[0], _T("res/d1.png"));
loadimage(&down_image[1], _T("res/d2.png"));
IMAGE hook_image;
for (int i = 0; i != 4; ++i) {
vector<IMAGE> hook_image_array;
sprintf_s(name, "res/h%d.png", i + 1);
loadimage(&hook_image, name, 64, 256, true);
hook_image_array.push_back(hook_image);
obstacle_image.push_back(hook_image_array);
}
for (int i = 0; i != 10; ++i) {
sprintf_s(name, sizeof(name), "res/sz/%d.png", i);
loadimage(&sz_image[i], name);
}
playSound("res/hit.mp3");//预加载
mciSendString("play res/bg.mp3 repeat", 0, 0, 0);//背景音乐
}
接下来就到了具体实现,我们应该搞清楚,我们做这个函数是为了什么,换而言之,这个函数的功能是什么,尽可能的把功能细化,不要写的太复杂,甚至可以只在函数里设置一些条件,然后在其他的函数中依据这些条件做出具体的实现,例如这样
void KeyEvent() {
if (_kbhit()) {
char c = _getch();//从缓冲区读入数据
if (c == ' ') {
jump();
}
else if (c == 'd' || c == 'D') {
down();
}
}
}
void jump() {
hero.jump = true;
update = true;
}
void down() {
update = true;
hero.down = true;
hero.index = 0;
}
我们只需要捕获键盘事件,然后进行判断,再调用相应的函数就行了,里面不需要太复杂的内容,只需要设置两三个条件接着就可以在接下来的函数中实现具体的内容
if (hero.jump) {
if (hero.y < JUMP_MAX) {//如果已经到了顶点
jumpHeight = 4;
}
hero.y += jumpHeight;//实现偏移
if (hero.y > JUMP_MIN) {//已经到了底部,结束跳跃
jumpHeight = -4;
hero.jump = false;
}
}
else if (hero.down) {//如果处于下蹲状态
static int count = 0;
int delays[2] = { 10,30 };
++count;
if (count > delays[hero.index]) {
count = 0;
++hero.index;
}
if (hero.index >= 2) {
hero.index = 0;
hero.down = false;
}
}
上面的函数依据这些条件设置了具体的偏移量,但依然没有做出具体的实现,我们把这个任务交给了以下函数
void updateHero() {
if (!hero.down) {//如果不处于下蹲状态
putimagePNG2(hero.x, hero.y, &hero_image[hero.index]);
}
else {
//减去当前的图片高度
putimagePNG2(hero.x, 355 - down_image[hero.index].getheight(), &down_image[0]);
putimagePNG2(hero.x, 355 - down_image[hero.index].getheight(), &down_image[1]);
}
}
上面的这个函数就对跳跃和下蹲做出了具体实现,这应该就是所谓的模块化吧,把一个复杂的函数化成一个个细小的函数,每个函数只要设置一点点变量,然后就可以实现较为复杂的功能
整个程序中最为关键的就是下面的这个更新偏移量的函数,它完成了人物,背景和障碍物的坐标偏移,上面的这个函数实现也是基于这个函数的坐标来实现的,这个函数可以说是这个程序的灵魂
void UpdateXY() {
for (int i = 0; i != 3; ++i) {//更新背景的偏移量
bg_x[i] -= bg_speed[i];
if (bg_x[i] < -WIN_WIDTH) {
bg_x[i] = 0;
}
}
if (hero.jump) {
if (hero.y < JUMP_MAX) {//如果已经到了顶点
jumpHeight = 4;
}
hero.y += jumpHeight;//实现偏移
if (hero.y > JUMP_MIN) {//已经到了底部,结束跳跃
jumpHeight = -4;
hero.jump = false;
}
}
else if (hero.down) {//如果处于下蹲状态
static int count = 0;
int delays[2] = { 10,30 };
++count;
if (count > delays[hero.index]) {
count = 0;
++hero.index;
}
if (hero.index >= 2) {
hero.index = 0;
hero.down = false;
}
}
else {//不跳跃的时候才要改变姿势
hero.index = (hero.index + 1) % 12;//更改人物姿势
}
//创建障碍物
static int FrameCount = 0;//乌龟在0-300的区间随机出现
static int enemyFre = 100;
++FrameCount;
if (FrameCount > enemyFre) {
FrameCount = 0;
enemyFre = 100 + rand() % 200;
createobstacle();
}
//更新所有障碍物的坐标
for (int i = 0; i != OBSTACLE_COUNT; ++i) {
if (obstacles[i].exist) {
obstacles[i].x -= (obstacles[i].speed + bg_speed[2]);
//障碍物越界
if (obstacles[i].x < -obstacle_image[obstacles[i].type][0].getwidth() * 2) {
obstacles[i].exist = false;
}
int len = obstacle_image[obstacles[i].type].size();//障碍物的造型个数
obstacles[i].imgindex = (obstacles[i].imgindex + 1) % len;
}
}
}
然后就是一些不太重要的函数实现了,比如显示障碍物,检查碰撞之类的
void ShowEnemy() {
for (int i = 0; i != OBSTACLE_COUNT; ++i) {
if (obstacles[i].exist) {
//渲染所有障碍物
putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH,
&obstacle_image[obstacles[i].type][obstacles[i].imgindex]);
}
}
}