C语言Window控制台实现弹弹方块(单个方块,多个方块)

简介: C语言Window控制台实现弹弹方块(单个方块,多个方块)

前面,我们用C语言实现了列表时的学生信息管理系统,那么,window控制台还能做什么好玩的东西呢?

http://blog.csdn.NET/morixinguan/article/details/77511003

这节我们来实现一下Window下的弹弹方块。

设计这个小游戏要考虑的问题

(1)方块:方块的大小,方块的颜色,方块在Window控制终端的起始位置(x,y的坐标),方块移动的速度,移动的方向。

(2)边框:弹弹方块需要在一定的空间内弹,而不能超出这个空间,那么这时需要设计一个边框,需要考虑边框的大小。

(3)方块和边框之间的关系:方块不能超出边框之外,也就是要判断一个方块以及方框的临界条件。

方块用" * " 组成的图形来代替,边框长用" - ",宽用方向 " | "代替。

现在可以来实现这个小游戏:


我们需要有以下的接口:

//窗口初始化  
void HANDLE_init(HANDLE hOut);  
//显示边框的函数  
void show_map(HANDLE hOut);  
//显示方块  
void show_block(HANDLE hOut,struct block_t *array , int size);  
//清除方块  
void clear_block(HANDLE hOut,struct block_t *array , int size);  
//移动方块  
void move_block(struct block_t *array , int size);  
//检测方块是否在边框内  
int  check_block(struct block_t *array , int size);

下面开始写代码:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <conio.h>
#include <tchar.h>
#define msleep(x)     (usleep(1000*x))
#define   ROW     18
#define   COL     60
#define TITLE "弹弹方块游戏 设计者:杨源鑫 日期:2017年8月24日 版本:1.0"
//在终端上打印信息
#define Print_Info_To_console(str,hOut,pos,x,y,color_type) \
  SetConsoleTextAttribute(hOut, color_type);  \
  pos.X = x;                  \
  pos.Y = y ;                 \
  SetConsoleCursorPosition(hOut,pos);       \
  printf("%s",str);
//窗口初始化
void HANDLE_init(HANDLE hOut);
void show_map(HANDLE hOut);
void show_block(HANDLE hOut,int row , int col , int w , int h);
void clear_block(HANDLE hOut,int row , int col , int w , int h);
void move_block(int *row , int *col , int *drow , int *dcol , int h , int w);
//定义设置光标结构体变量
CONSOLE_CURSOR_INFO cci; 
//定义默认的坐标位置   
COORD pos = {0,0};
int main(int argc , char **argv)
{
  int row = 5 ; 
  int col = 5 ; 
  int w = 4 ; 
  int h = 2 ;   
  int drow = 1 ; 
  int dcol = 1 ; 
  HANDLE hOut;
  hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  HANDLE_init(hOut);
  //刷方框
  show_map(hOut);
  while(1)
  {
    show_block(hOut, row , col , w , h);
    //sleep(1);
    Sleep(100);
    clear_block(hOut,row , col , w , h);
    move_block(&row , &col , &drow , &dcol , h , w);
  }
  return 0 ;
}
//窗口初始化
void HANDLE_init(HANDLE hOut)
{
    SetConsoleTitleA(TITLE);
    //获取当前的句柄---设置为标准输出句柄 
    //获取光标信息
    GetConsoleCursorInfo(hOut, &cci); 
  //设置光标大小   
    cci.dwSize = 1; 
  //设置光标不可见 FALSE   
    cci.bVisible =  0; 
    //设置(应用)光标信息
    SetConsoleCursorInfo(hOut, &cci); 
}
//画边框 
void show_map(HANDLE hOut)
{
  int i ; 
  system("cls");  //全局刷
  Print_Info_To_console(TITLE,hOut,pos,2,0,FOREGROUND_GREEN | 0x8);
  //Print_Info_To_console(str,hOut,pos,x,y,color_type) 
  for(i = 1 ; i <= COL ; i++)
  {
    Print_Info_To_console("-",hOut,pos,i,1,FOREGROUND_GREEN | 0x8);
    Print_Info_To_console("-",hOut,pos,i,ROW,FOREGROUND_GREEN | 0x8);
  }
  for(i = 1 ; i <= ROW ; i++ )
  {
    Print_Info_To_console("|",hOut,pos,1,i,FOREGROUND_GREEN | 0x8);
    Print_Info_To_console("|",hOut,pos,COL,i,FOREGROUND_GREEN | 0x8);
  }
  fflush(stdout);
}
//画方块 
void show_block(HANDLE hOut,int row , int col , int w , int h)
{
  int i , j ; 
  for(i = 0 ; i < h ; i++)
  {
    for(j = 0 ; j < w ; j++)
    {
      Print_Info_To_console("*",hOut,pos,col+j,row+i,FOREGROUND_RED | FOREGROUND_GREEN | 0x8);
    }
  }
  fflush(stdout); 
}
void move_block(int *row , int *col , int *drow , int *dcol , int h , int w)
{
  if((*row == ROW-h) || (*row == 2) )
    *drow = -*drow ; 
  if((*col == COL-w) || (*col == 2)) 
    *dcol = -*dcol;
  *row += *drow ;
  *col += *dcol ; 
}
void clear_block(HANDLE hOut,int row , int col , int w , int h)
{
  int i , j ; 
  for(i = 0 ; i < h ; i++)
  {
    for(j = 0 ; j < w ; j++)
    {
      Print_Info_To_console("*",hOut,pos,col+j,row+i,0);  
    }
  }
  fflush(stdout);
}

运行结果演示:

0.gif

那么既然可以实现一个,可以实现多个方块同时运行吗?当然是可以的!

多个方块,这时候要考虑什么问题?

前面我们知道,关于方块我们设计的时候需要考虑的问题:方块的起始位置,方块的大小,方块的移动方向,方块的颜色。现在我们要实现多个方块,那么就需要设计一个结构体,然后定义一个结构体数组来存储这些方块。


我们设计的结构体如下:

struct  block_t
{
  //方块的起始位置
  int row; 
  int col; 
  //方块的大小
  int w; 
  int h;  
  //方块的移动方向
  int drow ; 
  int dcol ; 
  //方块着色
  int color ;
};

当然,上面的接口内存需要改动一下,参数传参改为结构体数组的形式即可,这样就方便很多了。

接口修改如下:

//窗口初始化
void HANDLE_init(HANDLE hOut);
//显示边框的函数
void show_map(HANDLE hOut);
//显示方块
void show_block(HANDLE hOut,struct block_t *array , int size);
//清除方块
void clear_block(HANDLE hOut,struct block_t *array , int size);
//移动方块
void move_block(struct block_t *array , int size);
//检测方块是否在边框内
int  check_block(struct block_t *array , int size);

下面开始修改代码:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <conio.h>
#include <tchar.h>
#define msleep(x)     (usleep(1000*x))
#define NR(x)     (sizeof(x)/sizeof(x[0]))
//定义边框的行为18,列为60
#define   ROW     18
#define   COL     60
#define TITLE "弹弹方块游戏 设计者:杨源鑫 日期:2017年8月24日 版本:2.0"
//在终端上打印信息
#define Print_Info_To_console(str,hOut,pos,x,y,color_type) \
  SetConsoleTextAttribute(hOut, color_type);  \
  pos.X = x;                  \
  pos.Y = y ;                 \
  SetConsoleCursorPosition(hOut,pos);       \
  printf("%s",str);
struct  block_t
{
  //方块的起始位置
  int row; 
  int col; 
  //方块的大小
  int w; 
  int h;  
  //方块的移动方向
  int drow ; 
  int dcol ; 
  //方块着色
  int color ;
};
//窗口初始化
void HANDLE_init(HANDLE hOut);
//显示边框的函数
void show_map(HANDLE hOut);
//显示方块
void show_block(HANDLE hOut,struct block_t *array , int size);
//清除方块
void clear_block(HANDLE hOut,struct block_t *array , int size);
//移动方块
void move_block(struct block_t *array , int size);
//检测方块是否在边框内
int  check_block(struct block_t *array , int size);
//定义设置光标结构体变量
CONSOLE_CURSOR_INFO cci; 
//定义默认的坐标位置   
COORD pos = {0,0};
int main(void)
{
  //定义方块结构体数组
  struct block_t  array[] = {
  {3,4,3,2,1,1,FOREGROUND_RED | FOREGROUND_GREEN | 0x8},
  {6,7,3,2,1,1,FOREGROUND_RED | 0x8},
  {8,9,3,2,1,1,FOREGROUND_GREEN | FOREGROUND_BLUE | 0x8},
  };
  //刷方框
  if(check_block(array , NR(array)))
  {
    printf("方块定义不在界线内\n");
    return -1 ; 
  }
  HANDLE hOut;
  hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  HANDLE_init(hOut);
  fflush(stdout);
  //显示边框
  show_map(hOut);
  while(1)
  {
    //显示方块
    show_block(hOut ,array , NR(array));
    //延时
    msleep(100);
    //清除方块
    clear_block(hOut ,array , NR(array));
    //移动方块
    move_block(array , NR(array));
  }
  return 0 ;
}
//窗口初始化
void HANDLE_init(HANDLE hOut)
{
  SetConsoleTitleA(TITLE);
  //获取当前的句柄---设置为标准输出句柄 
    //获取光标信息
    GetConsoleCursorInfo(hOut, &cci); 
  //设置光标大小   
    cci.dwSize = 1; 
  //设置光标不可见 FALSE   
    cci.bVisible =  0; 
    //设置(应用)光标信息
    SetConsoleCursorInfo(hOut, &cci); 
}
//画边框 
void show_map(HANDLE hOut)
{
  int i ; 
  system("cls");  //全局刷
  Print_Info_To_console(TITLE,hOut,pos,2,0,FOREGROUND_GREEN | 0x8);
  for(i = 1 ; i <= COL ; i++)
  {
    Print_Info_To_console("-",hOut,pos,i,1,FOREGROUND_GREEN | 0x8);
    Print_Info_To_console("-",hOut,pos,i,ROW,FOREGROUND_GREEN | 0x8);
  }
  for(i = 1 ; i <= ROW ; i++ )
  {
    Print_Info_To_console("|",hOut,pos,1,i,FOREGROUND_GREEN | 0x8);
    Print_Info_To_console("|",hOut,pos,COL,i,FOREGROUND_GREEN | 0x8);
  }
  fflush(stdout);
}
//显示方块子函数
static void _show_block(HANDLE hOut,struct block_t block)
{
  int i , j ; 
  for(i = 0 ; i < block.h ; i++)
  {
    for(j = 0 ; j < block.w ; j++)
    {
      Print_Info_To_console("*",hOut,pos,block.col+j,block.row+i,block.color);
      //Print_Info_To_console("*",hOut,pos,block.col+j,block.row+i,FOREGROUND_RED | FOREGROUND_GREEN | 0x8);
      //printf("\033[%d;%dH\033[%dm \033[0m" , block.row+i , block.col+j , block.color);
    }
  }
  fflush(stdout);
}
void show_block(HANDLE hOut ,struct block_t *array , int size)
{
  int i ; 
  for(i = 0 ; i < size ; i++)
  {
    _show_block(hOut,array[i]);
  }
} 
//移动方块子函数
static void _move_block(struct block_t *block)
{
  if((block->row >= ROW-block->h) || (block->row <= 2) )
    block->drow = -block->drow ; 
  if((block->col >= COL-block->w) || (block->col <= 2)) 
    block->dcol = -block->dcol;
  block->row += block->drow ;
  block->col += block->dcol ; 
}
void move_block(struct block_t *array , int size)
{
  int i ; 
  for(i = 0 ; i < size ; i++)
  {
    _move_block(&(array[i]));
  }
} 
//清除方块子函数
static void _clear_block(HANDLE hOut,struct block_t block)
{
  int i , j ; 
  for(i = 0 ; i < block.h ; i++)
  {
    for(j = 0 ; j < block.w ; j++)
    {
      Print_Info_To_console("*",hOut,pos,(block.col)+j,(block.row)+i,0);  
      //printf("\033[%d;%dH " , (block.row)+i , (block.col)+j);
    }
  }
  fflush(stdout);
}
void clear_block(HANDLE hOut,struct block_t *array , int size)
{
  int i ; 
  for(i = 0 ; i < size ; i++)
  {
    _clear_block(hOut,array[i]);
  }
} 
//检测方块是否在允许的方块内
static int _check_block(struct block_t block)
{
  if((block.row == 2) || (block.col == 2) || 
    (block.row == ROW - block.h) || (block.col == COL-block.w))
  {
    return 1 ; 
  } 
  return 0 ; 
}
int  check_block(struct block_t *array , int size)
{
  int i ; 
  for(i = 0 ; i < size ; i++)
  {
    if(_check_block(array[i]))
      return 1 ; 
  }
  return 0 ; 
}

运行结果演示:

0.gif

       那么该游戏还能继续拓展,比如,方块的移动方式修改用手动用键盘的上下左右按键来进行控制,还有,方块如果碰撞到了,会弹开一段距离。甚至,我们还可以借助这个,设计一个控制台版本的坦克大战。

       更多脑洞,需要你仔细的斟酌与思考,一个游戏不是轻轻松松就做出来的。发挥你的脑洞,想你所想,编你所编!!

原文链接:http://blog.csdn.net/morixinguan/article/details/77541343

目录
相关文章
用c语言输出有颜色的字体 printf输出 控制台程序修改文本位置 设置控制台程序窗口标题
用c语言输出有颜色的字体 printf输出 控制台程序修改文本位置 设置控制台程序窗口标题
|
Linux API C语言
Linux下C语言实现弹弹方块小游戏
Linux下C语言实现弹弹方块小游戏
147 0
|
Linux C语言 C++
C语言实现一个Window控制台带彩色,且可以用方向键选择并确认的菜单式列表(一)
C语言实现一个Window控制台带彩色,且可以用方向键选择并确认的菜单式列表(一)
159 0
|
C语言
C语言——修改控制台背景色和字体颜色
C语言——修改控制台背景色和字体颜色
|
C语言
在C语言中,SetConsoleTextAttribute(参数1,参数2)是设置控制台窗口字体颜色和背景颜色的函数。GetStdHandle(参数)函数用于获得句柄
在C语言中,SetConsoleTextAttribute(参数1,参数2)是设置控制台窗口字体颜色和背景颜色的函数。 参数1:句柄 参数2:颜色
282 0
在C语言中,SetConsoleTextAttribute(参数1,参数2)是设置控制台窗口字体颜色和背景颜色的函数。GetStdHandle(参数)函数用于获得句柄
|
1月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
62 23
|
1月前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
66 15
|
1月前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
60 24
|
1月前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
63 16
|
1月前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
36 3

热门文章

最新文章