C语言书写推箱子(坤坤版easyx库)

简介: C语言书写推箱子(坤坤版easyx库)

游戏效果的展示

游戏玩法:玩家(坤坤)把箱子(篮球)推到目的地(篮框),然后篮筐变成鸡,鸡你太美, 便是胜利

运用的知识点(必看)

1.学会easyx库的使用

2.利用数组绘制地图,再利用枚举,表示游戏元素。

还有对三维数组的了解与掌握

3.函数的构造和调用

4.循环和判断语句

5**.bool类型(C++中会有介绍)**

不会easyx库的,可以去看一下我之前写的文章,推箱子这个项目不算是很复杂,非常的适合初学者上手

代码的讲解

游戏地图的实现

地图的初始化

enum Mine
{
  space,
  wall,
  destination,
  box,
  player,
};
int level = 0;
int map[3][10][10] =
{
  {
    {0, 0, 0, 1, 1, 1 ,1 ,1, 0, 0},
    {0, 0, 0, 1, 0, 0 ,2 ,1, 0, 0},
    {0, 0, 0, 1, 0, 3 ,0 ,1, 0, 0},
    {0, 1, 1, 1, 0, 0 ,0 ,1, 1, 1},
    {0, 1, 0, 2, 3 ,4 ,3, 0, 2, 1},
    {0, 1, 1, 1, 0, 3 ,0 ,1, 1, 1},
    {0, 0, 0, 1, 0, 2 ,0 ,1, 0, 0},
    {0, 0, 0, 1, 0, 0 ,0 ,1, 0, 0},
    {0, 0, 0, 1, 1, 1 ,1 ,1, 0, 0},
    {0, 0, 0, 0, 0, 0 ,0 ,0, 0, 0},
  },
  {
    {1, 1, 1, 1, 1, 1 ,1 ,1, 1, 1},
    {1, 2, 0, 0, 0, 0 ,0 ,0, 0, 1},
    {1, 0, 0, 0, 0, 0 ,3 ,0, 1, 0},
    {1, 0, 0, 3, 0, 0 ,0 ,0, 0, 1},
    {1, 0, 0, 3, 0 ,4 ,0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0 ,1 ,0, 0, 1},
    {1, 2, 1, 1, 0, 0 ,1 ,0, 2, 1},
    {1, 1, 1, 0, 1, 0 ,1 ,0, 1, 0},
    {0, 0, 0, 0, 1, 0 ,1 ,0, 1, 0},
    {0, 0, 0, 0, 1, 1 ,1 ,1, 0, 0},
  },
  {
    {0, 0, 0, 1, 1, 1 ,1 ,0, 0, 0},
    {0, 0, 1, 0, 0, 0 ,0 ,1, 0, 0},
    {0, 1, 0, 3, 0, 3 ,0 ,0, 1, 0},
    {1, 2, 0, 0, 0, 0 ,1 ,0, 0, 1},
    {1, 1, 1, 1, 2 ,0 ,1, 0, 0, 1},
    {1, 0, 0, 1, 1, 1 ,1 ,0, 0, 1},
    {1, 2, 0, 0, 0, 4 ,0 ,0, 0, 1},
    {0, 1, 0, 0, 3, 0 ,3 ,0, 1, 0},
    {0, 0, 1, 0, 0, 0 ,2 ,1, 0, 0},
    {0, 0, 0, 1, 1, 1 ,1 ,0, 0, 0},
  }
};

推箱子这个游戏共有5个元素

这里采用枚举列举出来

0 代表空地, 1代表墙, 2代表目的地(篮筐), 3代表箱子(篮球), 4代表玩家(坤坤当然还有一种情况,当篮球在篮筐时候,就变成鸡了

这里采用了三维数组,

游戏地图是有二维数组构成,一关的话是二维数组,如果想要增加游戏关卡的话,就需要用到三维数组,这里我只写了3关,如果你有兴趣,可以自行添加下一个关卡.

同时这里定义了一个level, 它代表着关卡数

地图图片的加载

void IoadImge()
{
  for (int i = 0; i < 6; i++)
  {
    char str[20] = "";
    sprintf_s(str, "./images/%d.bmp", i);
    loadimage(image_all + i, str, 64, 64);
  }
}

这里主要是运用easyx库, 当然要先定义图片, 定义图片的代码我把它跟头文件放在一起的,这函数里便没有。

1、先定义一个字符串数组

2、sprintf()函数,主要起到拼接字符串的作用。

3.加载图片,loadiomage()函数里的64,是指的图片的大小,也就是图片素材的大小

地图图片的放置

oid drawmap()
{
  for (int i = 0; i < 10; ++i)
  {
    for (int j = 0; j < 10; ++j)
    {
      int x = j * 64;
      int y = i * 64;
      switch (map[level][i][j])
      {
      case space:
        //printf("  ");
        putimage(x, y, image_all);
        break;
      case wall:
        //printf("▓ ");
        putimage(x, y, image_all + 1);
        break;
      case destination:
        //printf("☆");
        putimage(x, y, image_all + 2);
        break;
      case box:
        //printf("□");
        putimage(x, y, image_all + 3);
        break;
      case player:
        //printf("♀");
        putimage(x, y, image_all + 4);
        break;
      case box + destination:
        //printf("★");
        putimage(x, y, image_all + 5);
        break;
      case player + destination:
        //printf("♂");
        putimage(x, y, image_all + 4);
        break;
      }
    }
    printf("\n");
  }
}

1.这里 x, y 算的是坐标,图片的大小为60,行与列分别*64,便是坐标的大小

2.主要是用switch语句加上for嵌套循环,对各个元素,分别putimage()

这里多了一种情况,当篮球被推到篮筐时, 这里贴了一张照片,它2就变成了一只鸡

也就是鸡你太美。

人物和箱子的移动(重点)

void playgame()
{
  int i = 0, j = 0;
  for (i = 0; i < 10; i++)
  {
    for (j = 0; j < 10; j++)
    {
      if (map[level][i][j] == player || map[level][i][j] == player + destination)
      {
        goto end;       //break跳出一层循环,用  goto end; end:; 跳出所有的循环
      }
    }
  }
end:;
  int  key = _getch();
  switch (key)
  {
  case 'w':      // 上
  case 'W':
  case  72:
    if (map[level][i - 1][j] == space || map[level][i - 1][j] == destination)
    {
      map[level][i - 1][j] += player;
      map[level][i][j] -= player;
    }
    else
    {
      if (map[level][i - 1][j] == box || map[level][i - 1][j] == box + destination)
      {
        if (map[level][i - 2][j] == space || map[level][i - 2][j] == destination)
        {
          map[level][i - 2][j] += box;
          map[level][i - 1][j] = map[level][i - 1][j] - box + player;
          map[level][i - 1][j] -= player;
        }
      }
    }
    break;
  case 's':     //  下
  case 'S':
  case 80:
    if (map[level][i + 1][j] == space || map[level][i + 1][j] == destination)
    {
      map[level][i + 1][j] = map[level][i + 1][j] + player;
      map[level][i][j] = map[level][i][j] - player;
    }
    else
    {
      if (map[level][i + 1][j] == box || map[level][i + 1][j] == box + destination)
      {
        if (map[level][i + 2][j] == space || map[level][i + 2][j] == destination)
        {
          map[level][i + 2][j] = map[level][i + 2][j] + box;
          map[level][i + 1][j] = map[level][i + 1][j] - box + player;
          map[level][i + 1][j] = map[level][i + 1][j] - player;
        }
      }
    }
    break;
  case 'a':     //  左
  case 'A':
  case 75:
    if (map[level][i][j - 1] == space || map[level][i][j - 1] == destination)
    {
      map[level][i][j - 1] += player;
      map[level][i][j] -= player;
    }
    else
    {
      if (map[level][i][j - 1] == box || map[level][i][j - 1] == box + destination)
      {
        if (map[level][i][j - 2] == space || map[level][i][j - 2] == destination)
        {
          map[level][i][j - 2] += box;
          map[level][i][j - 1] = map[level][i][j - 1] - box + player;
          map[level][i][j - 1] -= player;
        }
      }
    }
    break;
  case 'd':      // 右
  case 'D':
  case 77:
    if (map[level][i][j + 1] == space || map[level][i][j + 1] == destination)
    {
      map[level][i][j + 1] += player;
      map[level][i][j] -= player;
    }
    else
    {
      if (map[level][i][j + 1] == box || map[level][i][j + 1] == box + destination)
      {
        if (map[level][i][j + 2] == space || map[level][i][j + 2] == destination)
        {
          map[level][i][j + 2] += box;
          map[level][i][j + 1] = map[level][i][j + 1] - box + player;
          map[level][i][j + 1] -= player;
        }
      }
    }
    break;
  }
}
bool deduce_suc-cess()
{
  for (int a = 0; a < 10; a++)
  {
    for (int b = 0; b < 10; b++)
    {
      if (map[level][a][b] == box)
      {
        return false;
      }
    }
  }
  return true;
}

人物的移动主要是通过数组的移动来实现的

第一步:在数组中找到 player 和 player + destination 这两种情况多层循环跳出这里用了 goto语句(break只跳出一层)

通过按键盘,控制坤坤移动

这里讲解下坤坤上移,其他方向移动,原理是一样的,只是方向不一样。

这里采用Switch语句

键盘中上移的键有3种, W, w, 以及键盘右边向上移动的键(72)****(键盘右边表示方向的键都可以用特定数字来表示, 向上72, 向下80, 向左75, 向右77)

移动前,要思考一个问题

坤坤前面是空地可以移动, 坤坤前面是前面是篮筐可以移动,坤坤前面是墙不能够移动,

坤坤前面是篮球而篮球前面是空地可以移动, 坤坤前面是篮球而篮球前面是篮筐可以移动

坤坤前面是篮球而篮球前面是空地则不能够移动

注意:坤坤推篮球的时候, 先是篮球先动, 坤坤不动,篮球动了,坤坤前面有空地,然后坤坤再动。

if (map[level][i - 1][j] == space || map[level][i - 1][j] == destination)

//坤坤前面是空地可以移动, 坤坤前面是前面是篮筐可以移动.

那么

map[level][i - 1][j] += player; //向上移动, 前面的位置+个player

map[level][i][j] -= player;// 向上移动 前面的位置- 一个player

if (map[level][i - 1][j] == box || map[level][i - 1][j] == box + destination)// 坤坤前面是篮球或者坤坤前面是篮球加篮筐(鸡)
{

if (map[level][i - 2][j] == space || map[level][i - 2][j] == destination)//坤坤前面(篮球或者鸡)的前面是空地或者坤坤前面(篮球或者鸡)的前面是篮筐也是可以移动的

}

这里主要实现坤坤推着篮球移动你也可以理解为坤坤开始将要进行三步上篮的操作了)

map[level][i - 2][j] += box; //篮球前面移动一个单位, 前面那个位置出现了篮球,自然前面那个位置+个篮球

map[level][i - 1][j] = map[level][i - 1][j] - box + player;篮球原来的位置 - 个篮球,坤坤前面移动一个单位,则坤坤前面的位置加一个坤坤

map[level][i - 1][j] -= player; ://坤坤推篮球的时候, 先是篮球先动, 坤坤不动,篮球动了,坤坤前面有空地,然后坤坤再动。

所以为实现坤坤推篮球的时候不移动这个位置,前面这个位置加了一个坤坤,这个位置再减去一个坤坤。

当然如果你想实现坤坤跟篮球一起移动, 你可以在坤坤原来这个位置减去一个坤坤

游戏结束的判断

bool deduce_success()
{
  for (int a = 0; a < 10; a++)
  {
    for (int b = 0; b < 10; b++)
    {
      if (map[level][a][b] == box)
      {
        return false;
      }
    }
  }
  return true;
}

游戏的判断这里采用boole类型,两种返回结果,

(游戏成功返回return true, 游戏失败返回return false)

游戏结束的标志是:地图上都没有篮球,因为篮球都被坤坤推到篮筐里了, 变成了鸡

如果地图上篮球,那么就return false

else if 那么就return true

音乐的播放

vmciSendString("open 1.mp3", 0, 0, 0);
mciSendString("play 1.mp3", 0, 0, 0);

俗话说没有音乐的游戏,是没有灵魂的
所以我特意去找了一些鸡哥的音乐

播放音乐的步骤很简单

如果代码不懂

看我之前写的博客easyx库的介绍

头文件以及全局变量

#include<stdio.h>                                       // 推箱子的几个元素;
#include<stdlib.h>                                     //  0 空地   1 墙  2 目的地   3 箱子 4 玩 5 箱子在目的地  6 玩家在目的地 
#include<conio.h>  //_getch()函数的头文件             //用_getch函数,如果用getchar(),次移动要回车键  // 上 72  下 80  左75   右77    
#include<graphics.h> // 使用第三方库easyx
#include<mmsystem.h>
#pragma comment(lib, "winmm.lib")
IMAGE image_all[6];      // 用数组存储图片

main函数

int main()
{
  mciSendString("open 1.mp3", 0, 0, 0);
  mciSendString("play 1.mp3", 0, 0, 0);
  //cols 长  lines宽
  //system("mode con cols=25 lines=15");
  initgraph(640, 640);
  IoadImge();
  while (1)
  {
    //system("cls");
    drawmap();
    /*playmusic();*/
    if (deduce_success())
    {
      level++;
      if (level > 2)
      {
        setbkmode(TRANSPARENT);
        settextcolor(RED);
        settextstyle(50, 0, "行楷");
        outtextxy(100, 400, "你赢了,恭喜通关\n");
        outtextxy(60, 300, "快看我鸡你太美,唱跳rap\n");
        //printf("你赢了");
        //printf("不愧是地表最强的人!!!!!!");
        //printf("恭喜通关!!!!!!");
        break;
      }
    }
    playgame();
  }
  getchar();
  return 0;
}

这里需要注意的主函数中

游戏结束判断的那部分代码

这个关过了就 level就++
这里通关了,我也采用了easyx库的操作,
自己打印了一些字, 当然你也可以自己修改

游戏源码和图片素材领取(百度网盘)

**家人们游戏源码和图片素材都在这里,可以自行领取

链接:https://pan.baidu.com/s/1qGGIeKPUAr5GY8xEhej47Q?pwd=2222

提取码:2222

–来自百度网盘超级会员V1的分享

你们的三连真的对我很重要,后续我会创作出更多的优质博客



相关文章
|
18天前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。
ly~
|
1月前
|
数据可视化 BI API
除了 OpenGL,还有哪些常用的图形库可以在 C 语言中使用?
除了OpenGL,C语言中还有多个常用的图形库:SDL,适合初学者,用于2D游戏和多媒体应用;Allegro,高性能,支持2D/3D图形,广泛应用于游戏开发;Cairo,矢量图形库,支持高质量图形输出,适用于数据可视化;SFML,提供简单接口,用于2D/3D游戏及多媒体应用;GTK+,开源窗口工具包,用于创建图形用户界面。这些库各有特色,适用于不同的开发需求。
ly~
130 4
|
1月前
|
存储 安全 编译器
深入C语言库:字符与字符串函数模拟实现
深入C语言库:字符与字符串函数模拟实现
|
3月前
|
C语言
C语言中的math库概述
C语言中的math库概述
|
3月前
|
存储 Serverless C语言
C语言中的标准库函数
C语言中的标准库函数
52 0
|
3月前
|
API 开发工具 C语言
C语言与图形界面:利用GTK+、Qt等库创建GUI应用。
C语言与图形界面:利用GTK+、Qt等库创建GUI应用。
174 0
|
5月前
|
存储 移动开发 C语言
技术心得记录:嵌入式开发中常用到的C语言库函数
技术心得记录:嵌入式开发中常用到的C语言库函数
55 1
|
5月前
|
存储 C语言
C语言标准库介绍:<time.h>
C语言标准库介绍:<time.h>
|
5月前
|
C语言
C 语言 math.h 库介绍
C 语言 math.h 库介绍
|
5月前
|
C语言
C 语言 locale.h 库介绍
C 语言 locale.h 库介绍