首页
社区
课程
招聘
我编了一个俄罗斯方块程序,怎么画的图老是一闪一闪的?大家帮我看看。
发表于: 2005-12-5 20:51 9034

我编了一个俄罗斯方块程序,怎么画的图老是一闪一闪的?大家帮我看看。

2005-12-5 20:51
9034
大概会是什么问题??

这是我用Win32写的第一个程序,写得很乱,但为什么会闪很奇怪。附件:ab.rar

[课程]Linux pwn 探索篇!

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
收藏拉
用gdi写的吧,gdi不支持页面翻转和双缓冲,所以每次刷新都会直接改变内存区域,从而在屏幕上引起闪烁。
当年dos下游戏通常都会出现这种情况,后来人们用双缓冲模式和页面翻转解决了这个问题,也就是预先在不可见的区域将图形拷贝上去,再将显示指针指向这个区域,比如常用的模式X。
至于解决问题,用direct是最好的,可是比较复杂;在gdi下可以判断一下那些区域需要更新,哪些不需要,并只更新部分rect区域。
对于这个程序,各个方块的位置不重叠,比较好办,方块下落的时候将上一个位置的方块擦除即可。在下对c++还比较在行,对于win32汇编是新手,就不献丑了,不好意思(拜托,不要乱扔果皮)
2005-12-5 22:53
0
雪    币: 217
活跃值: (99)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
建议使用DirectDraw,使用起来一点不复杂.
找个源码对照者学学.
2005-12-6 13:32
0
雪    币: 216
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
上次那个有点问题,变形后可能超出边界报错,空格可以加速下落。。

不过显示还是有问题啊。。。。。
我想问题是出在用InvalidateRect发送WM_PAINT消息时,我用的是:
invoke InvalidateRect,hWnd,NULL,TRUE    这种方法
也就是先擦除背景,再重新画图,这样每次收到WM_PAINT消息的时候屏幕就被全部画为白色后再重新画图,看起来就是一闪一闪的。

我把 InvalidateRect函数改了一下:
invoke InvalidateRect,hWnd,NULL,NULL,也就是不擦除背景。
再设置只有被移动的方块才重画,停在下方的方块不再重画,对移动的方块我是把方块上一个位置先擦除,再画下一个位置。
  
  但结果还是很难看,不移动的方块不需要重画就不会闪,可是移动的方块看起来还是闪得相当厉害,真是没办法了。

  我想问下二楼的就是“后来人们用双缓冲模式和页面翻转解决了这个问题,也就是预先在不可见的区域将图形拷贝上去,再将显示指针指向这个区域,比如常用的模式X。”显示指针是什么东西?怎么把图形拷贝到不可见的区域
2005-12-6 20:36
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
由于现在的图形硬件实在是复杂,我大概说一下早期的dos vga模式,水平有限,大家不要拿砖拍我。
VGA是IBM兼容机的标准配置(我说的是n年以前),是一块非常简单的芯片。官方资料称他可支持640*480 16色,一般用out指令向端口发送数据控制。内部工作是以4个64kb的“位面”工作的,挺复杂的。幸好我可以利用硬件来做这些转换工作而把显示缓存看成是线性的。在分辨率较低时,显存(当时不是这么叫得)大于屏幕区域,这样就可以随意设置初始位置寄存器(crtc),具体端口是3D5H,是只写的,只读的端口是3B5H,这个16位的地址就是我说的那个“指针”,只要改变它的值,就可以确定显存中哪一块区域要显示。
-〉显示开始地址
|主显示区
-〉翻页指向的地址
|附显示区
―剩下的空间

基本就是这样,当然vga其他寄存器还有很多,设置很复杂,不小心就会造成可怕的后果。要设置好这些大约需要四五十行代码(汇编),在nt下更始麻烦,呵呵。现在的显卡好复杂,各位大哥有了解的给讲讲吧?
2005-12-7 09:45
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
6
用 GDI 做一些速度不快的游戏,是可以的

首先准备一个图像 buffer

每一次更新画面时,把图像 buffer 清空  (例如画上背景图) ,然后把你需要画的东西都全画上去

最后来一个 BitBlt 把整个 buffer 内容复制到你的窗口去

上面提及的 directx (direct draw)方法,是正式编写游戏时的基本技巧,我们在 display card 的内存里,建立一块 “back buffer”,每一次画面更新时都把内容画到 back buffer 去,完成绘图后,便执行一个 directx 的 “flip” 指令,意思是命令 display card 把显示影像的 pointer 指向 back buffer,同时把现在的前景内存当成 back buffer (前景和 back buffer 两者角色交换了) ,这样,当 monitor 下一次向 display card 查询画面影像时,便会很自然地显示了你刚才画好的图像

一次游戏的画面更新速度极快,例如一秒 60 次,那么游戏的绘图程序只需要每次把内容画到 back buffer 再进行一个 flip ,便可以很有效地显示新画面
2005-12-7 10:04
0
雪    币: 519
活跃值: (1223)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
7
这个的确很恼人,记得我以前写一个下棋的游戏,不需要重画很多东西的,结果也是闪的厉害。解决思路就是先在内存中画好,具体实现忘记是怎么做的了,应该就是riijj提到的那种。
2005-12-7 16:21
0
雪    币: 212
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
用VC会容易一些
2005-12-9 22:33
0
雪    币: 216
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
问题已经解决了,就是用双缓存的办法。。。。
2005-12-11 20:22
0
雪    币: 204
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
InvalidateRect这个函数其实也可以解决问题
只不过要注意刷新区域就可以解决
我做过一个推箱子的游戏,刷新的是整个窗口区域
也是一闪闪的
后来把刷新区域改成只是刷新图片改变的区域
问题就解决了
不过要考虑计算刷新区域
2005-12-12 13:13
0
游客
登录 | 注册 方可回帖
返回
//