【c语言】五子棋(EasyX图形库+背景音乐)

简介: 【c语言】五子棋(EasyX图形库+背景音乐)

大家好,有没有觉得写了好多c语言代码,面对的都是黑框框控制台,当我们学习了基础的c语言知识,和EasyX图形库后,终于可以和黑框框saygoodbye,今天要分享给大家的是小游戏五子棋,跟着小张一起学习吧


EasyX图形库安装

图形库链接

1.点击下载

2.安装你对应集成开发环境对应的安装包,我用的是vs2019

3.ok,我们使用库函数,加上头文件即可

棋盘的绘制

注意创建必须是.cpp,要不然图形库用不了

棋盘大小我们搞成15*15的格子,每个格子长宽为30,每个棋子半径搞成13,棋盘格长450,宽450,为了防止边界下的棋子显示不完全,每个边在向外延申15,界面总大小为480×480

1.棋盘木板

initgraph(480, 480);//初始化一个窗口(窗口大小480*480);

此时窗口闪一下就消失了,尝试加一个while循环

#include<graphics.h>//包含图形库头文件
int main()
{
  initgraph(480, 480);
  while (1)
  {
  }
}

编译运行:

这个并非控制台的黑框框

五子棋背景一般是棕色,我们需要自己画一个棕色背景图片贴上去,大小和界面大小480*480一样大

IMAGE p;//定义一个图片变量
loadimage(&p, "./background.png", 480, 480);//加载图片函数,(参数1图片地址,参数2图片的位置,图片大小)

./为当前目录下,和.c文件放在一个目录下面

putimage(0, 0, &p);//贴图片到界面上去(参数1,2为图片从界面的哪个位置开始贴)

#include<graphics.h>//包含图形库头文件
IMAGE p;
int main()
{
  initgraph(480, 480);
  loadimage(&p, "./background.png", 480, 480);
  putimage(0, 0, &p);
  while (1)
  {
  }
}

如果出现该问题,调试>属性>高级>字符集改为多字符集就行了

编译运行:


2.开始画线

setlinecolor(BLACK);//设置线颜色的函数(黑线)
for (int x = 15; x < 480; x += 30)//循环画竖线
  {
    line(x, 15, x, 465);//画线函数,前两个参数为起始点x,y,后两个参数为终点x,y
  }
  for (int y= 15; y < 480; y+= 30)//循环画横线
  {
    line(15, y, 465,y);
  }
#include<graphics.h>//包含图形库头文件
IMAGE p;
int main()
{
  initgraph(480, 480);
  loadimage(&p, "./background.png", 480, 480);
  putimage(0, 0, &p);
  setlinecolor(BLACK);
  for (int x = 15; x < 480; x += 30)
  {
    line(x, 15, x, 465);
  }
  for (int y = 15; y < 480; y += 30)
  {
    line(15, y, 465, y);
  }
  while (1)
  {
  }
}

编译运行

3.专业棋盘好像有5个黑点点(圆)

对应五个点的坐标

setfillcolor(BLACK);//设置圆的颜色
  fillcircle(15 + 3 * 30, 15 + 3 * 30, 3);前两个参数为圆的圆心坐标,第三个参数为圆的半径
  fillcircle(15 + 3 * 30, 15 + 11 * 30, 3);
  fillcircle(15 + 11 * 30, 15 + 3 * 30, 3);
  fillcircle(15 + 7 * 30, 15 + 7 * 30, 3);
  fillcircle(15 + 11 * 30, 15 + 11 * 30, 3);

编译运行

#include<graphics.h>//包含图形库头文件
IMAGE p;
int main()
{
  initgraph(480, 480);
  loadimage(&p, "./background.png", 480, 480);
  putimage(0, 0, &p);
  setlinecolor(BLACK);
  for (int x = 15; x < 480; x += 30)
  {
    line(x, 15, x, 465);
  }
  for (int y = 15; y < 480; y += 30)
  {
    line(15, y, 465, y);
  }
  setfillcolor(BLACK);
  fillcircle(15 + 3 * 30, 15 + 3 * 30, 3);
  fillcircle(15 + 3 * 30, 15 + 11 * 30, 3);
  fillcircle(15 + 11 * 30, 15 + 3 * 30, 3);
  fillcircle(15 + 7 * 30, 15 + 7 * 30, 3);
  fillcircle(15 + 11 * 30, 15 + 11 * 30, 3);
  while (1)
  {
  }
}

获取鼠标点击

ExMessage msg;//消息结构体变量
if (peekmessage(&msg, EX_MOUSE)) //偷瞄消息,第一个消息结构体地址,第二个参数,鼠标消息
    {
      switch (msg.message)   //鼠标消息
      {
      case WM_LBUTTONDOWN:                      //左键
        draw(msg.x, msg.y);//鼠标光标位置坐标
        break;
      }
    }

当鼠标左键按下时,将此时的鼠标在对应界面的坐标传递给draw函数,需要随时获取鼠标的消息,将上述代码放在循环里面

while (1)
  {
    if (peekmessage(&msg, EX_MOUSE))              //偷瞄消息,第一个消息结构体地址,鼠标消息
    {
      switch (msg.message)                      //鼠标消息
      {
      case WM_LBUTTONDOWN:                      //左键
        draw(msg.x, msg.y);
        break;
      }
    }
  }

画棋子

将鼠标点击的坐标传到draw函数中来,定义一个全局变量num,判断是黑子,还是白子,num=1,黑子下,num=-1,白子下。

int num = 1;
void draw(int m, int n)
{
  if (num == -1)
  {
    setfillcolor(WHITE);//设置圆的填充色(白色)白棋
    }
  else if (num == 1)
  {
    setfillcolor(BLACK);//设置圆的填充色(黑色)黑棋
    }
    fillcircle(m - m % 30 + 15, n - n % 30 + 15, 13);//画圆,圆的x,y,半径,棋子的绘制
    num *= -1;//黑白棋轮着下,每次调用draw,改变num值,实现黑白黑白黑白
}

为什么棋子坐标是(m - m % 30 + 15, n - n % 30 + 15),因为鼠标不可能一点就是要下的坐标,只能鼠标点在某一个范围,就把该棋子落在离鼠标点的位置最近的位置,如果鼠标的坐标为48,48传给draw时,

我们知道应该下在这个位置,经过处理后是45,45,刚好是要下的位置,避免棋子落在不该落的位置。

编译运行

解决棋子可以下在棋子上面的问题

>在点一次黑色棋子被覆盖

我们可以定义一个二维数组,15*15,刚开始初始化为0,如果数组下标对应棋盘的地方有黑棋,把对应二维数组中的值放1,如果数组下标对应棋盘的地方有白棋,把对应二维数组中的值放-1;如果鼠标点击的位置有棋子的话,直接return掉,不进行绘制棋子

二维数组的初始化:

int arr[15][15];//全局变量好操作
void initboard()
{
  for (int i = 0; i < 15; i++)
  {
    for (int j = 0; j < 15; j++)
    {
      arr[i][j] = 0;//循环初始化二维数组
       }
       }
}
int full(int x, int y)
{
  if (arr[x][y] != 0)//如果不等于0,表示下过棋了return 0;
    return 0;
  else//如果等于0,表示没下过棋了,将该数组对应位置放num,return 1;
    arr[x][y] = num;
       return 1;
}
void draw(int m,int n)
{
  if (num == -1)
  {       setfillcolor(WHITE);
  }
  else if (num == 1)
  {       setfillcolor(BLACK);
  }
  int x;
  int y;y
  x = m / 30;//二维数组横坐标,m鼠标横坐标,如果m=48,x就是1,
  y = n / 30;//二维数组纵坐标n鼠标纵坐标,如果n=48,y就是1,
  if (full(x,y) == 0)//等于0表示下过棋了,直接return;跳出draw,如果=1,跳过这个条件判断语句,开始下棋
    return;
  fillcircle(m - m % 30 + 15, n - n % 30 + 15, 13);//下棋
  num *= -1;
}

此时不能下下过的位置

判断输赢

int check_over()
{
  for (int i = 0; i < 15; i++)
  {
    for (int j = 0; j < 15; j++)
    {
      if (arr[i][j] == 0)
        continue;
      if (check_five(i, j) == 1)
      {
        q = arr[i][j];
        return 1;
      }
    }
  }
}

因为二维数组记录了下棋的状况,对应位置为1则是黑棋,-1为白棋,0是未下,循环遍历每个数组元素,先是找到下过棋的位置,没下过棋的位置直接跳过,因为我们是通过这个函数将下过棋的坐标传给

check_five(int x, int y),然后根据下x,y坐标相邻的五个是否一样,如果没下的话直接跳过,防止五个相邻位置没下棋都是0,进入check_five(int x, int y),五个0也是一样,然后游戏就结束了

int check_five(int x, int y)
{//检查一个下过棋的坐标相邻五个是否一样
  if (arr[x][y] == arr[x - 1][y] && arr[x][y] == arr[x - 2][y] && arr[x][y] == arr[x + 1][y] && arr[x][y] == arr[x + 2][y])//横行判断
    return 1;
  if (arr[x][y] == arr[x][y-1] && arr[x][y] == arr[x][y-2] && arr[x][y] == arr[x][y+1] && arr[x][y] == arr[x][y+2])//纵行判断
    return 1;
  if (arr[x][y] == arr[x - 1][y-1] && arr[x][y] == arr[x - 2][y-2] && arr[x][y] == arr[x + 1][y+1] && arr[x][y] == arr[x + 2][y+2])以该坐标为中心,主对角线判断
    return 1;
  if (arr[x][y] == arr[x - 1][y+1] && arr[x][y] == arr[x+2][y-2] && arr[x][y] == arr[x + 1][y-1] && arr[x][y] == arr[x-2][y+2])以该坐标为中心,副对角线判断
    return 1;
//相同则返回1
//不同返回0
  return 0;
}

在check_over()中如果check_five(i, j) 返回一,则有五个连成,将该坐标对应二维数组中的值保存在q全局变量中,然后check_over()返回1

if (check_over() == 1)
    {
      outtextxy(180, 180, "游戏结束");//输出文字,参数一参数二为文字左上角坐标,参数三为文字内容
      //change();//消息盒子函数,提示谁赢了
      system("pause");//退出程序,头文件windows.h
    }

在调用之前必须

settextstyle(40, 20, "隶书");//设置字体高度,宽度,字体的格式
  setbkmode(TRANSPARENT);//字体后面设置透明,背景模式

编译运行

提示输赢

void change()//消息盒子函数,提示谁赢了
{
  HWND hnd = GetHWnd();  //获取窗口句柄(相当于窗口的指针)
  SetWindowText(hnd, "五子棋"); //设置窗口标题
  int isok;
        if(q==1)//q获取的是赢家对应二维数组的消息,黑子为1                     //
         isok = MessageBox(NULL, "黑子胜", "提示", MB_OKCANCEL); //弹出消息盒子,提示用户操作
      else if(q==-1)
        isok = MessageBox(NULL, "白子胜", "提示", MB_OKCANCEL);
  if (IDOK== isok)                                             //返回点了哪里
  {                                                            //点了ok
  }
  else if (IDCANCEL == isok)                               //点了取消
  {
  }
}

编译运行

背景音乐函数

这里可以去看动态通讯录那一篇,加音乐有具体步骤

#include<graphics.h>//包含图形库头文件
#include<mmsystem.h>//包含多媒体设备接口头文件
#pragma comment(lib,"winmm.lib")//加载静态库
void bgm()
{    //打开音乐
  mciSendString("open ./music.MP3", 0, 0, 0);//后面参数不用管
  //播放音乐
  mciSendString("play ./music.MP3", 0, 0, 0);//后面参数不用管
}

整体代码展示

#include <windows.h>
#include<graphics.h>//包含图形库头文件
#include<mmsystem.h>//包含多媒体设备接口头文件
#pragma comment(lib,"winmm.lib")//加载静态库
IMAGE p;
int num = 1;
int q;
int arr[15][15];
void change()
{
  HWND hnd = GetHWnd();                                             //获取窗口句柄(相当于窗口的指针)
  SetWindowText(hnd, "五子棋"); 
  int isok;//设置窗口标题
        if(q==1)                      //
         isok = MessageBox(NULL, "黑子胜", "提示", MB_OKCANCEL); //弹出消息盒子,提示用户操作
      else if(q==-1)
        isok = MessageBox(NULL, "白子胜", "提示", MB_OKCANCEL);
  if (IDOK== isok)                                             //返回点了哪里
  {                                                            //点了ok
  }
  else if (IDCANCEL == isok)                               //点了取消
  {
  }
}
void bgm()
{    //打开音乐
  mciSendString("open ./music.MP3", 0, 0, 0);//后面参数不用管
  //播放音乐
  mciSendString("play ./music.MP3", 0, 0, 0);//后面参数不用管
}
void initboard()
{
  for (int i = 0; i < 15; i++)
  {
    for (int j = 0; j < 15; j++)
    {
      arr[i][j] = 0;
    }
  }
}
int full(int x, int y)
{
  if (arr[x][y] != 0)
    return 0;
  else
    arr[x][y] = num;
       return 1;
}
void draw(int m,int n)
{
  if (num == -1)
  {       setfillcolor(WHITE);
  }
  else if (num == 1)
  {       setfillcolor(BLACK);
  }
  int x;
  int y;
  x = m / 30;
  y = n / 30;
  if (full(x,y) == 0)
    return;
  fillcircle(m - m % 30 + 15, n - n % 30 + 15, 13);
  num *= -1;
}
int check_five(int x, int y)
{
  //if (x < 2 || y < 2 || x>12 || y>12)
    //return 0;
  if (arr[x][y] == arr[x - 1][y] && arr[x][y] == arr[x - 2][y] && arr[x][y] == arr[x + 1][y] && arr[x][y] == arr[x + 2][y])
    return 1;
  if (arr[x][y] == arr[x][y-1] && arr[x][y] == arr[x][y-2] && arr[x][y] == arr[x][y+1] && arr[x][y] == arr[x][y+2])
    return 1;
  if (arr[x][y] == arr[x - 1][y-1] && arr[x][y] == arr[x - 2][y-2] && arr[x][y] == arr[x + 1][y+1] && arr[x][y] == arr[x + 2][y+2])
    return 1;
  if (arr[x][y] == arr[x - 1][y+1] && arr[x][y] == arr[x+2][y-2] && arr[x][y] == arr[x + 1][y-1] && arr[x][y] == arr[x-2][y+2])
    return 1;
  return 0;
}
int check_over()
{
  for (int i = 0; i < 15; i++)
  {
    for (int j = 0; j < 15; j++)
    {
      if (arr[i][j] == 0)
        continue;
      if (check_five(i, j) == 1)
      {
        q = arr[i][j];
        return 1;
      }
    }
  }
}
int main()
{
  bgm();
  ExMessage msg;
  initgraph(480, 480);
  loadimage(&p,"./background.png",480,480);
  putimage(0, 0, &p);
  setlinecolor(BLACK);
  for (int x = 15; x < 480; x += 30)
  {
    line(x, 15, x, 465);
  }
  for (int y= 15; y < 480; y+= 30)
  {
    line(15, y, 465,y);
  }
  setfillcolor(BLACK);
  fillcircle(15 + 3 * 30, 15 + 3 * 30, 3);
  fillcircle(15 + 3 * 30, 15 + 11 * 30, 3);
  fillcircle(15 + 11 * 30, 15 + 3 * 30, 3);
  fillcircle(15 + 7 * 30, 15 + 7 * 30, 3);
  fillcircle(15 + 11 * 30, 15 + 11 * 30, 3);
  settextstyle(40, 20, "隶书");
  setbkmode(TRANSPARENT);
  while (1)
  {
    if (peekmessage(&msg, EX_MOUSE))              //偷瞄消息,第一个消息结构体地址,鼠标消息
    {
      switch (msg.message)                      //鼠标消息
      {
      case WM_LBUTTONDOWN:                      //左键
        draw(msg.x, msg.y);
        break;
      }
    }
    if (check_over() == 1)
    {
      outtextxy(180, 180, "游戏结束");
      change();
      system("pause");
    }
  }
}

效果展示

20230821_194813

目录
相关文章
|
4天前
|
存储 移动开发 C语言
技术心得记录:嵌入式开发中常用到的C语言库函数
技术心得记录:嵌入式开发中常用到的C语言库函数
|
4天前
|
存储 C语言
C语言标准库介绍:<time.h>
C语言标准库介绍:<time.h>
6 0
|
4天前
|
C语言
C 语言 math.h 库介绍
C 语言 math.h 库介绍
7 0
|
4天前
|
C语言
C 语言 locale.h 库介绍
C 语言 locale.h 库介绍
6 0
|
5天前
|
C语言
C语言的标准库:string.h, math.h, stdlib.h
C语言的标准库:string.h, math.h, stdlib.h
8 1
|
7天前
|
C语言
【海贼王编程冒险 - C语言海上篇】库函数怎样模拟实现?
【海贼王编程冒险 - C语言海上篇】库函数怎样模拟实现?
7 1
|
8天前
|
C语言
【C语言】:图形打印
【C语言】:图形打印
6 0
|
26天前
|
C语言
C语言小插曲——对图形库的初步探索(消除小球小游戏)
C语言小插曲——对图形库的初步探索(消除小球小游戏)
11 0
|
1天前
|
Java C语言 C++
定义C语言的int main()函数
定义C语言的int main()函数
|
3天前
|
Java C语言 C++
定义C语言的int main()函数
定义C语言的int main()函数