C图形化第一步
之前的贪吃蛇都是在cmd下实现,每次都要调用cls刷新屏幕,简直是闪瞎了我的狗眼。
度娘得知有一种方法可以避免闪烁,即:双缓冲。原理是先在内存中作图,然后将做好的图复制到前台,同时禁止背景刷新。
主要使用函数:
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain(HINSTANCE, HINSTANCE,PSTR, int);
涉及主要方法:
WNDCLASS wndclass;
wndclass.style=CS_HREDRAW|CS_VREDRAW;//位置改变时重绘
wndclass.lpfnWndProc=(WNDPROC)WndProc;//消息处理函数
wndclass.hInstance=;//当前实例句柄
wndclass.hbrBackground=(HBRUSH)COLOR_WINDOWFRAME;//背景色
wndclass.lpszClassName=szWindowClass;//参窗口类名
wndclass.hIcon=;//图标
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);//光标
wndclass.lpszMenuName=;//菜单名称
wndclass.hIconSm=;//最小化图标
RegisterClassEx(&wndclass);//注册窗口类
CreateWindow:
HWND CreateWindow(
LPCTSTR lpClassName, // 如果lpClassName是一个字符串,它指定了窗口的类名
LPCTSTR lpWindowName, // 指向一个指定窗口名的空结束的字符串指针,可使用lpWindowName来指定控制文本
DWORD dwStyle, // 指定创建窗口的风格, WS_CAPTION:创建一个有标题框的窗口
// WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格
int x, // 指定窗口的初始水平位置
// 如果该参数被设为CW_USEDEFAULT则系统为窗口选择缺省的左上角坐标并忽略Y参数。
// CW_USEDEFAULT只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则X和y参数被设为零
int y, //
int nWidth, // 以设备单元指明窗口的宽度
// 若nWidth是CW_USEDEFAULT,则系统为窗口选择一个缺省的高度和宽度:
// 缺省宽度为从初始X坐标开始到屏幕的右边界,缺省高度为从初始Y坐标开始到目标区域的顶部。
// CW_USEDEFAULT只对层叠窗口有效;如果为弹出式窗口和子窗口设定CW_USEDEFAULT标志则nWidth和nHeight被设为零。
int nHeight, //
HWND hWndParent, // 指向被创建窗口的父窗口或所有者窗口的句柄
HMENU hMenu, // 菜单句柄,或依据窗口风格指明一个子窗口标识
HANDLE hlnstance, // 与窗口相关联的模块实例的句柄
LPVOID lpParam // 指向一个值的指针,该值传递给窗口WM_CREATE消息
)
// 返回值:如果函数成功,返回值为新窗口的句柄:如果函数失败,返回值为NULL。
将字符贪吃蛇迁移过来,gcc 编译时需加 -mwindows 参数,如:
gcc snake.c -mwindows
代码如下:
#include <windows.h>
#define ID_TIMER 1
#define WIDTH 12 // 宽
#define HEIGHT 8 // 高
#define DEBUG 0
const char FENCE ='*'; // 栅栏
const char HEAD ='@'; // 蛇头
const char BODY ='#'; // 蛇身
const char FOOD ='O'; // 食物
const char BLANK =' '; // 空白
char arr[HEIGHT][WIDTH];
struct Snake{
int y,x;
}snake[WIDTH*HEIGHT]; // 结构体,保存坐标点
int len=,food=,key=,score=,alive=,direct=,speed=,full=(WIDTH-)*(HEIGHT-); // 长度、食物、按键、总分、存活、方向、速度
int uldr[][]={{},{-,},{,-},{,},{,}}; // 上、左、下、右 void init(){ // 初始化游戏地图
int y=,x=,start_pos=HEIGHT/;
for(y=;y<HEIGHT;y++)
for(x=;x<WIDTH;x++)
if( y == || y == HEIGHT- || x == || x == WIDTH- ){
arr[y][x] = FENCE;
}
else{
arr[y][x] = BLANK;
}
snake[].y=start_pos;
snake[].x=;
len++;
snake[].y=start_pos;
snake[].x=;
len++;
arr[ snake[].y ][ snake[].x ] = HEAD ;
arr[ snake[].y ][ snake[].x ] = BODY ;
} void make_food(){
int rx,ry;
while(!food){
rx = rand()%WIDTH;
ry = rand()%HEIGHT;
if( arr[ry][rx] == BLANK ){
arr[ry][rx]=FOOD;
food=;
break;
}
}
} void move(){
int cnt=;
len++; // 准备将当前位置放在snake数组首部
if(DEBUG)printf("len:%d\n",len);
for(cnt=len-;cnt>;cnt--){
snake[cnt].x=snake[cnt-].x;
snake[cnt].y=snake[cnt-].y; // 1234 变为 51234
}
snake[].y+=uldr[direct][];
snake[].x+=uldr[direct][]; // 移动蛇头
} void check_head(){
int y=snake[].y;
int x=snake[].x;
int i=;
int cnt=;
if(y < || y > HEIGHT- || x < || x > WIDTH-){ // 是否越界
alive=;
}
if( arr[y][x] == BODY ){ // 是否吃到自己
alive=;
}
if( arr[y][x] == BLANK){
arr[y][x] = HEAD;
}
if( arr[y][x] == FOOD ){ // 吃到食物
arr[y][x] = HEAD;
score++;
len++;
food=;
snake[len-].y=snake[len-].y; // 蛇尾增加一节蛇身
snake[len-].x=snake[len-].x;
make_food();
}
if(DEBUG)printf("len:%d\n",len);
if(DEBUG){
for(;i<len;i++){
printf("y,x:(%d,%d)\n",snake[i].y,snake[i].x);
}
}
arr[ snake[len-].y ][ snake[len-].x ]=BLANK; // 先清除蛇尾显示
len--;
for(cnt=;cnt<=len-;cnt++){
arr[ snake[cnt].y ][ snake[cnt].x ]=BODY; // 蛇身显示
}
} void handle(){
init();
make_food();
while(alive && len<full){
move();
check_head();
speed=(speed > )?:(score/+);
if(alive){
Sleep(-speed*); // 多久刷新一次
}
}
if( len == full){
printf("congratulations!\n");
}
else{
printf("you lose\n");
}
} LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("snake") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ; if(!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ;
return ;
} hwnd = CreateWindow (szAppName, TEXT("snake"),
WS_CAPTION | WS_SYSMENU , //| WS_THICKFRAME,
, ,
, ,
NULL, NULL, hInstance,
NULL) ; ShowWindow (hwnd, SW_SHOW) ; //显示
UpdateWindow (hwnd) ;
//ShowCursor(FALSE); //隐藏鼠标光标 while (GetMessage (&msg, NULL, , ))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
ShowCursor(TRUE); //显示鼠标光标
return msg.wParam ;
} LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
static HDC hdcMem;
HFONT hFont;
static HBITMAP hBitmap;
static int cxScreen, cyScreen; //屏幕的宽度 高度.
static int iFontWidth=, iFontHeight=; //字体的宽度 高度 switch (message)
{
case WM_CREATE:
cxScreen = GetSystemMetrics(SM_CXSCREEN) ; //屏幕宽度
cyScreen = GetSystemMetrics(SM_CYSCREEN) ; hdc = GetDC(hwnd);
hdcMem = CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc, cxScreen, cyScreen);
SelectObject(hdcMem, hBitmap);
ReleaseDC(hwnd, hdc);
//创建字体
hFont = CreateFont(iFontHeight, iFontWidth-, , , FW_NORMAL, , , ,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DRAFT_QUALITY, FIXED_PITCH | FF_SWISS, TEXT("Fixedsys"));
SelectObject(hdcMem, hFont);
DeleteObject (hFont) ;
SetBkMode(hdcMem, TRANSPARENT); //设置背景模式为 透明
init();
make_food(); case WM_TIMER:
hdc = GetDC(hwnd);
PatBlt (hdcMem, , , cxScreen, cyScreen, BLACKNESS) ; //将内存设备映像刷成黑色
int y,x,size_s,size_p,size_l,size_w;
TCHAR sText[],pText[],lText[],wText[]; move();
check_head();
speed=(speed > )?:(score/+);
SetTimer (hwnd, ID_TIMER, (-speed*), NULL) ;
size_s = wsprintf( sText,TEXT("your score: %d"),score); // 计算字符长度
size_p = wsprintf( pText,TEXT("current speed: %d"),speed);
size_l = wsprintf( lText,TEXT("you lose"));
size_w = wsprintf( wText,TEXT("you win"));
SetTextColor(hdcMem, RGB(, , )); // 字体颜色 TextOut(hdcMem, , , sText, size_s); // hdc、x坐标、y坐标、字符地址、字符长度
TextOut(hdcMem, , , pText, size_p);
if(alive && len<full){
for(y= ; y<HEIGHT ; y++ ){
for(x= ; x<WIDTH ; x++ ){
TextOut(hdcMem, x*, (y+)*, &arr[y][x], );
}
}
}
else{
for(y= ; y<HEIGHT ; y++ )
for(x= ; x<WIDTH ; x++ )
if( y== || y==HEIGHT- || x== || x==WIDTH-){
TextOut(hdcMem, x*, (y+)*, &arr[y][x], );
}
if(alive == ){
TextOut(hdcMem, , (+HEIGHT/)*, lText, size_l);
}else{
TextOut(hdcMem, , (+HEIGHT/)*, wText, size_w);
}
BitBlt(hdc, , , cxScreen, cyScreen, hdcMem, , , SRCCOPY);
KillTimer (hwnd, ID_TIMER) ;
}
BitBlt(hdc, , , cxScreen, cyScreen, hdcMem, , , SRCCOPY);
ReleaseDC(hwnd, hdc);
return ; case WM_RBUTTONDOWN:
KillTimer (hwnd, ID_TIMER) ;
return ; case WM_RBUTTONUP:
SetTimer (hwnd, ID_TIMER, , NULL) ;
return ; // 按下 w a s d 时
case WM_CHAR:
switch (wParam){
case 'w' : direct=(direct == )?:;break;
case 'a' : direct=(direct == )?:;break;
case 's' : direct=(direct == )?:;break;
case 'd' : direct=(direct == )?:;break;
default : direct;
}
return ;
//处理善后工作
case WM_DESTROY:
KillTimer (hwnd, ID_TIMER) ;
DeleteObject(hBitmap);
DeleteDC(hdcMem);
PostQuitMessage () ;
return ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
C图形化第一步的更多相关文章
- scratch少儿编程第一季——01、初识图形化界面编程的神器
各位小伙伴大家好: 说到2018年互联教育的热门事件,那就不得不提Scratch. 相信各位不关注信息技术领域的各位家长也都听说过这个东西. 对于小学阶段想要接触编程或信息技术学生来说,Scratch ...
- MFC入门(一)-- 第一个简单的windows图形化界面小程序(打开计算器,记事本,查IP)
////////////////////////////////序//////////////////////////////// 大约三年前,学过一些简单的编程语言之后其实一直挺苦恼于所写的程序总是 ...
- [EntLib]微软企业库5.0 学习之路——第一步、基本入门
话说在大学的时候帮老师做项目的时候就已经接触过企业库了但是当初一直没明白为什么要用这个,只觉得好麻烦啊,竟然有那么多的乱七八糟的配置(原来我不知道有配置工具可以进行配置,请原谅我的小白). 直到去年在 ...
- Samba在CentOS下的图形化界面的安装
第一步:构建yum仓库(在此用的是北交大的yum仓库) 打开目录/etc/yum.repos.d下的CentOS-Base.repo文件,此处是我自己建的yum仓库,修改里面的链接地址为北交大的镜像的 ...
- 安装oracle11g不能启动图形化界面
问题:安装oracle11g时出现xhost: unable to open display "192.168.2.12:0.0".打不开图形化界面等. 终极解决方法:1.使用X ...
- Sourcetree使用 - git图形化工具(三)
前面两个章节总结了Sourcetree的安装与配置Sourcetree密钥,这个章节主要讲如何使用Sourcetree.以前呢,都是使用git Bash进行命令行方式进行操作git,感觉部分时间浪费在 ...
- linux下c图形化编程之gtk+2.0简单学习
在linux下想做一个图形化的界面,然后自己选择使用gtk+2.0来进行编辑,我的电脑已经安装过gtk+2.0了,所以就在网上找了一个安装方法,结果未测试,大家有安装问题可以说下,一起探讨下. 1.安 ...
- IDEA中使用Docker: 图形化 or 命令行 ,你更稀罕那个??
Docker简介: Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. 容器是完全使用沙箱机 ...
- 2018.4.21 如何正确快速安装/卸载云服务器Centos7安装GUI图形化界面GNOME桌面环境
为云服务哦Centos安装图形化界面GNOME .KDE 1.开始前先验证一下能不能上网 ping www.baidu.com 2.接下来开始安装X(X Window System),命令为 yum ...
随机推荐
- Tomcat运行一段时间后,自动停止关闭,To prevent a memory leak,Druid 数据库连接自动关闭, the JDBC Driver has been forcibly unregistered.
1. Tomcat 错误日志 tail -100f tomcat9/logs/catalina.out 21-Sep-2017 23:05:39.301 INFO [Thread-5] org.apa ...
- 小程序canvas绘制倒计时
如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 效果展示: //广告倒计时 advTimeCountDown:function(advTime ...
- Android笔记(四十) Android中的数据存储——SQLite(二) insert
准备工作: 我们模拟一个注册的页面,先看UI 我们需要创建一个数据库:user,数据库包含表user,user表包含字段id.username.password.mobilephone MainAct ...
- (备忘)Java web项目迁移到Centos7中验证码无法显示
每天多学一点知识. 今天部署项目的时候出现验证码无法显示的问题,如下图所示:
- WLAN实验1:划分不同VLAN及Acess配置
实验环境 公司是一个较大的局域网,二层交换机S1放置在一楼,一楼有IT部门和人事部门.二层交换机S2放置在二楼,二楼有市场部和研发部.公司的策略是:不同部门的主机之间不能相互通信,同一部门的主机才可以 ...
- CentOS7使用阿里yum源安装Docker
yum install -y yum-utils device-mapper-persistent-data lvm2安装所需的包 # yum-config-manager --add-repo ht ...
- 用python实现多线程爬取影视网站全部视频方法【笔记】
我拿这个站点作为案例:https://91mjw.com/ 其他站点方法都是差不多的. 第一步:获得整站所有的视频连接 html = requests.get("https://91mjw ...
- LG2664 树上游戏
树上游戏 题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 $$sum_i=\sum_{j=1}^ns(i,j)$$ 现在他想让 ...
- try catch 场景
面试官:什么情况下用到try-catch?程序员:代码执行预料不到的情况,我会使用try-catch.面试官:什么是预料不到的情况呢?程序员:比如我要计算a除以b,但是b是变量,如果b等于0程序就会出 ...
- LINQ查询表达式(2) - 在 C# 中编写 LINQ 查询
在 C# 中编写 LINQ 查询 C# 中编写 LINQ 查询的三种方式: 使用查询语法. 使用方法语法. 组合使用查询语法和方法语法. // 查询语法 IEnumerable<int> ...