目 录
摘要………………………………………………………………………1 1 方案论证………………………………………………………………………. 1.1 开发意义………………………………………………………………… 1.2 功能介绍…………………………………………………………………. 2 设计思路………………………………………………………………………… .
3 硬件电路………………………………………………………………………
2.1 74HC573驱动芯片电路…………………………………………………….
2.2 8*8LED点阵的接口电路………………………………………………….. 2.3单片机最小系统电路……………………………………………………….. 2.4整体电路图…………………………………………………………………. 4 系统调试……………………………………………………………………….. 3.1硬件调试……………………………………………………………………… 3.2软件调试……………………………………………………………………..
5 作品展示………………………………………………………………………… .
6 元器件清单…………………………………………………………………….. 7 结束语…………………………………………………………………………….. 致谢…………………………………………………………………………… 参考文献………………………………………………………………………….
游戏机的制作:俄罗斯方块
摘要:
近年来随着计算机在社会领域的渗透, 单片机的应用正在不断地走向深入,应用到各个领域。在实时检测和自动控制的单片机应用系统中,单片机往往是作为一个核心部件来使用,仅单片机方面知识是不够的,还应根据具体硬件结构,以及针对具体应用对象特点的软件结合,以作完善。 我做的题目是一个用51单片机制作的游戏机,大致分位软件和硬件2大部分,硬件主要通过5按键、1个8*8LED点阵屏、一个单片机系统,实现积木的左、右、下、变化、复位五个模式,完全达到俄罗斯方块所实现的功能。 次项目用专门的PROTUES仿真,而采用KEIL软件程序进行程序调试
关键词:ATS52单片机芯片 ;74HC573驱动芯片 ;GYXM-1558ASR-LED点阵屏
1 方案论证
1.1 开发意义:
充分理解点阵显示的原理,已经动态扫描的应用,对生活中的产品有了个全新的认识,不但懂得理论与实际的差距,也时对自己思维的一次强有力的挑战,做出这个东西让我收获良多。 1.2 功能介绍:
开始让他显示个积木,在按键没实现控制的时候,每隔1S下移一次,有触底处理功能,当碰到底的时候图形不能下移,判断能否消行,能消行则消行,不能再判断是否到顶,到底则从新开始,没到底产生下个随即数,中间有5个按键控制,一个实现图形左移,一个实现图形右移,一个实现下移,一个实现旋转,一个复位。 2 设计思路
图形的上下移动: 根据点阵理论可通过图形数据的左右移动和地址变化来实现。 图形的变化: 可通过地址变化来得到。即把需要变化的数据送到一固定地址,通过地址变化再送回显示的地址里面。 图形的碰边处理: 可通过各个边上的数据判断是否到边来实现。 与原有图形相遇: 可通过与原有图形数据进行比较处理来实现。:
图形的旋转: 在固定地址里面实现旋转比较容易,但是在行进中的图形旋转就比较费脑筋,我是用一个地址计数下移的次数,再用一个地址计数左移右移的次数。再根据这些次数确定图形的地址,再把这些地址送到图形变化的一个固定的地址中,变化后再送回到显示的地址中去显示。 图形的碰边处理: 如果不对图形进行边框处理,图形就会一直移动,看不到我们想要的效果。我是用把边框数据与图形数据进行位运算。再判断这些数据就可以得到图形是否到边。 3 硬件电路
2.1 74HC573驱动芯片电路
此芯片时个锁存器,也可以做驱动芯片驱动LED点阵屏幕,这里面的电源和地系统附加了 但是实际中的加上去,不然芯片不能工作。 2.2 8*8LED点阵的接口电路
上面的是仿真的图 上端接数据 下端开片选 但是实际中引脚很不规则,所有的花时间去测 用一节干电池,或者用指针万用表打到电阻10K档。
2.3 单片机最小系统电路
2.4 整体电路图以及仿真效果
但是里面的电源、地、晶振、复位、EA等 在仿真中系统自动加的 要是在实际生活中
的加进去。
4 系统调试
3.1 硬件调试
第一 检查单片机的最小系统是否正常,包括检查晶振、单片机2端电压、复位电路已经EA
第二 看驱动芯片是否工作正常、接法是否正确,再检查LED点阵是否接的
正确,可以用一节干电池测,也可以用指针万用表打到电阻10K档位测。 3.2 软件调试
流程图
开始N节拍到来否Y显示背景和图形N1秒到否YN满一行否Y调消行程序图形下移N有按键否Y去按键处处理到底否Y调下一个图形N 程序代码
。========================================================= 。俄罗斯方块,采用移片选的方法. 。编译时间: 。编译者: 谭华
。实现功能: 俄罗斯方块的旋转,左移,右移
。 消行 碰边 触底 产生随即数等 基本实现右移的基本功能
。==============初始化自定义======================================== 09年1月15
pianxuan shuchu
equ p2 equ p1
bt0 equ 20h.0 bt1 equ 20h.1 bt2 equ 20h.2 bt3 equ 20h.3 bt4 equ 20h.4 bt5 equ 20h.5 bt6 bt8 bt9
equ equ equ
20h.6 21h.0 21h.1 21h.2 21h.3
bt10 equ bt11 equ
。============================================
org 0000h ajmp start org 0bh ljmp intt0 org 30h
。=============主程序初始化================================ start:
mov sp, #60h
mov tmod, #21h mov th0, #0b1h mov tl0, #0e0h mov mov mov
th1, #25 tl1, #25 r1,
#00
call chushihua call chuzhi
setb ea setb et0 setb tr0 setb tr1 clr bt0 clr clr clr clr clr clr clr clr clr
bt1 bt2 bt3 bt4 bt5 bt8 bt9 bt10 bt11
setb bt6 mov mov mov
35h, #0feh r2, r4,
#00 #00
。===================================================== 。
主程序
。====================================================== main:
jnb bt0, main clr bt0 call saomiao call xianshi0 call xianshi jb
。扫描按键
。调用下移显示画面子程序
。调用触边后静态图形显示的子程序
bt10, loop 。判断是否触顶,=1,游戏结束,跳到满屏显示
。调用触底子程序
call chudi
call xiaohang 。调用消行判断子程序
call yanshi_40ms 。调用延时40ms消抖子程序,40ms到,BT5置1 jnb clr
bt5, xia0 bt5
。调用按键判断处理子程序
call panduan
bt9, xia bt9
xia0: jnb
clr
。图形快速下落标志位,=1快速下落
call xialuo ajmp main
。调用图形下落子程序
xia: call yanshi_1s
jnb bt1, main clr
bt1
。延时1s子程序.1s到,BT1=1
call xialuo ajmp main
。调用延时500ms子程序,500ms到bt11=1
loop: call yanshi_500ms
jnb bt11, main clr
bt11
call manping ajmp main
。调用满屏全亮子程序
。===================================================== 。
按键扫描
。===================================================== saomiao:
jb
p3.2, qq0
setb bt2 ajmp qq
p3.1, qq1
qq0: jb
setb bt3 ajmp qq
qq1: jb
p3.0, qq2
setb bt4 ajmp qq
p3.3, qq4
qq2: jb
setb bt8 ajmp qq
qq4: setb bt6 qq:
clr clr clr clr ret
bt2 bt3 bt4 bt8
。===================================================== 。
图形下移子程序
。===================================================== xialuo:
mov rl mov ret
a, a 35h, a
35h
。============================================ 。
判断子程序
。===================================================== panduan:
jnb clr jnb clr
bt2, ww0 bt2 bt6, ww0 bt6
call youyi
ajmp ww
bt3, ww1 bt3 bt6, ww1 bt6
ww0: jnb
clr jnb clr
call zuoyi ajmp ww
bt4, ww2 bt4 bt6, ww2 bt6
ww1: jnb
clr jnb clr
call zhuan ajmp ww
bt8, ww bt8 bt6, ww bt6
ww2: jnb ww:
clr jnb clr
call kuaixia ret
。============================================================ 。
快速下落子程序
。============================================================= kuaixia:
setb bt9 ret
。============================================================ 。
满屏子程序
。============================================================ manping:
mov mov
41h, #0ffh 42h, #0ffh
mov mov mov mov mov mov ret
43h, #0ffh 44h, #0ffh 45h, #0ffh 46h, #0ffh 47h, #0ffh 48h, #0ffh
。============================================================ 。
清屏子程序
。============================================================ qingping:
mov mov mov mov mov mov mov mov ret
41h, #00h 42h, #00h 43h, #00h 44h, #00h 45h, #00h 46h, #00h 47h, #00h 48h, #00h
。============================================ 。
下移显示
。===================================================== xianshi0:
mov mov mov
a, p1, p2,
35h 31h a
call delay rl mov mov
a p1, p1,
#00 32h
mov p2, a
call delay rl mov mov mov
a p1, p1, p2,
#00 33h a
call delay mov ret
p1,
#00
。===================================================== 。
图形右移子程序
。===================================================== zuoyi:
mov a, 31h jnb acc.0, dd1 ajmp dd
dd1: mov a, 32h
jnb acc.0, dd2 ajmp dd
dd2: mov a, 33h
jnb acc.0, dd3 ajmp dd
a,
35h
dd3: mov
cjne a,#0feh,sa0 call sad0 ajmp dd
a,
35h
sa0: mov
cjne a,#0fdh,sa1 call sad1
ajmp dd
a,
35h
sa1: mov
cjne a,#0fbh,sa2 call sad2 ajmp dd
sa2: mov cjne call
ajmp sa3: mov cjne call
ajmp sa4: mov cjne call ajmp dd:
ret
sad0: mov rr mov mov anl
cjne mov mov rr mov
mov
a,
35h
a,#0f7h,sa3 sad3 dd
a,
35h
a,#0efh,sa4 sad4 dd
a,
35h
a,#0bfh,dd sad5 dd a, 33h a 39h,#00 39h, a a,43h
a,#00,dd4 33h, 39h a, 32h a 39h,#00 39h, a
anl a,42h
cjne a,#00,dd4 mov 32h, 39h mov a, 31h rr mov mov anl
cjne mov
dec
dd4: ret
sad1: mov rr mov mov anl
cjne mov mov rr mov mov anl
cjne mov mov rr
mov
a 39h,#00 39h, a a,41h
a,#00,dd4 31h, 39h 51h
a, 33h a 39h,#00 39h, a a,44h
a,#00,dd5 33h, 39h a, 32h a 39h,#00 39h, a a,43h
a,#00,dd5 32h, 39h a, 31h a 39h,#00
mov anl
39h, a a,42h
cjne a,#00,dd5 mov 31h, 39h
dec
dd5: ret
sad2: mov rr mov mov anl
cjne mov mov rr mov mov anl
cjne mov mov rr mov mov anl
cjne mov
dec
dd6: ret
51h
a, 33h a 39h,#00 39h, a a,45h
a,#00,dd6 33h, 39h a, 32h a 39h,#00 39h, a a,44h
a,#00,dd6 32h, 39h a, 31h a 39h,#00 39h, a a,43h
a,#00,dd6 31h, 39h 51h
sad3: mov a, 33h rr mov mov anl
a 39h,#00 39h, a a,46h
cjne a,#00,dd7 mov mov rr mov mov anl
cjne mov mov rr mov mov anl
cjne mov
dec
dd7: ret
sad4: mov rr mov mov anl
cjne 33h, 39h a, 32h a 39h,#00 39h, a a,45h
a,#00,dd7 32h, 39h a, 31h a 39h,#00 39h, a a,44h
a,#00,dd7 31h, 39h 51h
a, 33h a 39h,#00 39h, a a,47h
a,#00,dd8
mov 33h, 39h mov a, 32h rr mov mov anl
cjne mov mov rr mov mov anl
cjne mov
dec
dd8: ret
sad5: mov rr mov mov anl
cjne mov mov rr mov mov
anl
a 39h,#00 39h, a a,46h
a,#00,dd8 32h, 39h a, 31h a 39h,#00 39h, a a,45h
a,#00,dd8 31h, 39h 51h
a, 33h a 39h,#00 39h, a a,48h
a,#00,dd9 33h, 39h a, 32h a 39h,#00 39h, a a,47h
cjne a,#00,dd9 mov 32h, 39h mov a, 31h rr mov mov anl
a 39h,#00 39h, a a,46h
cjne a,#00,dd9 mov 31h, 39h dec
51h
dd9: ret
。===============图形左移子程序====================================== 。通过图形移动一位,与静止图形相与,为零则移动,否则原地不动 。
。===================================================== youyi:
jnb
mov a, 31h acc.7, cc0
ajmp cc20
cc0: mov a, 32h
jnb acc.7, cc1 ajmp cc20
cc1: mov a, 33h
jnb acc.7, cc ajmp cc20
a,
35h
cc: mov
cjne a,#0feh,zz0 call scd0 ajmp cc20
a,
35h
zz0: mov
cjne a,#0fdh,zz1 call scd1 ajmp cc20
a,
35h
zz1: mov cjne a,#0fbh,zz2 call scd2
ajmp zz2: mov cjne call
ajmp zz3: mov cjne call
ajmp zz4: mov cjne call
ajmp cc20: ret
scd0: mov rl mov mov anl
cjne mov mov
rl
cc20
a,
35h
a,#0f7h,zz3 scd3 cc20
a,
35h
a,#0efh,zz4 scd4 cc20
a,
35h
a,#0bfh,cc20 scd5 cc20
a, 33h a 39h,#00 39h, a a,43h
a,#00,cc2 33h, 39h a, 32h a
mov mov anl
39h,#00 39h, a a,42h
cjne a,#00,cc2 mov 32h, 39h mov a, 31h rl mov mov anl
cjne mov
inc
cc2: ret
scd1: mov rl mov mov anl
cjne mov mov rl mov mov anl
cjne mov
mov a 39h,#00 39h, a a,41h
a,#00,cc2 31h, 39h 51h
a, 33h a 39h,#00 39h, a a,44h
a,#00,cc3 33h, 39h a, 32h a 39h,#00 39h, a a,43h
a,#00,cc3 32h, 39h a, 31h
rl mov mov anl
a 39h,#00 39h, a a,42h
cjne a,#00,cc3 mov 31h, 39h
inc
cc3: ret
scd2: mov rl mov mov anl
cjne mov mov rl mov mov anl
cjne mov mov rl mov mov anl
cjne
mov 51h
a, 33h a 39h,#00 39h, a a,45h
a,#00,cc4 33h, 39h a, 32h a 39h,#00 39h, a a,44h
a,#00,cc4 32h, 39h a, 31h a 39h,#00 39h, a a,43h
a,#00,cc4 31h, 39h
inc 51h
cc4: ret
scd3: mov a, 33h rl mov mov anl
cjne mov mov rl mov mov anl
cjne mov mov rl mov mov anl
cjne mov
inc
cc5: ret
scd4: mov rl mov
mov
a 39h,#00 39h, a a,46h
a,#00,cc5 33h, 39h a, 32h a 39h,#00 39h, a a,45h
a,#00,cc5 32h, 39h a, 31h a 39h,#00 39h, a a,44h
a,#00,cc5 31h, 39h 51h
a, 33h a 39h,#00 39h, a
anl a,47h
cjne a,#00,cc6 mov 33h, 39h mov a, 32h rl mov mov anl
cjne mov mov rl mov mov anl
cjne mov
inc
cc6: ret
scd5: mov rl mov mov anl
cjne mov mov rl
mov
a 39h,#00 39h, a a,46h
a,#00,cc6 32h, 39h a, 31h a 39h,#00 39h, a a,45h
a,#00,cc6 31h, 39h 51h
a, 33h a 39h,#00 39h, a a,48h
a,#00,cc7 33h, 39h a, 32h a 39h,#00
mov anl
39h, a a,47h
cjne a,#00,cc7 mov 32h, 39h mov a, 31h rl mov mov anl
a 39h,#00 39h, a a,46h
cjne a,#00,cc7 mov 31h, 39h inc
51h
cc7: ret
。====================================================== 。
图形旋转子程序
。====================================================== zhuan:
cjne r1,#0,
bu0
call zhuan0 ajmp bu
bu1
bu0: cjne r1,#1,
call zhuan1 ajmp bu
bu1: cjne r1,#2,
call zhuan2 ajmp bu
bu2
bu2: cjne r1,#3,
call zhuan3 ajmp bu
bu3
bu3: cjne r1,#4, bu
bu:
call zhuan4 ret
inc
r2
gg0
zhuan0: cjne r2,#1, mov mov 31h, #10h 32h, #18h mov
call
ajmp gg0: cjne mov mov mov
call
ajmp gg1: cjne mov mov mov
call
ajmp gg2: cjne mov mov mov mov
call gg:
ret
zhuan1:
33h, #10h
yizhou gg
r2,#2, 31h, #38h 32h, #10h 33h, #00h
yizhou gg
r2,#3, 31h, #10h 32h, #30h 33h, #10h
yizhou gg
r2,#4, r2,
#00
31h, #10h 32h, #38h 33h, #00h
yizhou inc
r2
gg1
gg2
gg
cjne r2,#1, mov mov mov
31h, #08h 32h, #18h 33h, #10h
ggg0
call yizhou ajmp ggg
ggg0: cjne mov mov mov mov
call ggg: ret zhuan2: cjne mov mov mov
call
ajmp hh0: cjne mov mov mov mov
call hh:
ret
zhuan3:
cjne r2,#2, 31h, #30h 32h, #18h 33h, #00h r2,
#00
yizhou
inc
r2
r2,#1, 31h, #18h 32h, #30h 33h, #00h
yizhou hh
r2,#2, 31h, #10h 32h, #18h 33h, #08h r2,
#00
yizhou inc
r2
r2,#1,
ggg
hh0
hh
hh1
mov mov mov
31h, #20h 32h, #38h 33h, #00h
call yizhou ajmp hh4
hh2
hh1: cjne r2,#2, mov mov mov
call
ajmp hh2: cjne mov mov mov
call
ajmp hh3: cjne mov mov mov mov
call hh4: ret zhuan4: cjne mov mov
mov
31h, #18h 32h, #10h 33h, #10h
yizhou hh4
r2,#3, 31h, #38h 32h, #08h 33h, #00h
yizhou hh4
r2,#4, r2,
#00
31h, #10h 32h, #10h 33h, #30h
yizhou
inc
r2
r2,#1, 31h, #10h 32h, #10h 33h, #18h
hh3
hh4
hh5
call yizhou ajmp hh8
hh6
hh5: cjne r2,#2,
mov mov mov
31h, #38h 32h, #20h 33h, #00h
call yizhou ajmp hh8
hh7
hh6: cjne r2,#3,
mov mov mov
31h, #18h 32h, #08h 33h, #08h
call yizhou ajmp hh8
hh8
hh7: cjne r2,#4,
mov mov mov mov
r2,
#00
31h, #08h 32h, #38h 33h, #00h
call yizhou
hh8: ret
。==================================================== yizhou:
mov
a,
51h
cjne a,#5, tt7 jmp
tt
tt7: cjne a,#6, tt0
call yyizhou jmp
tt
tt0: cjne a,#7, tt1
call yyizhou call yyizhou call zhuanpan0 jmp
tt
tt1: cjne a,#8, tt2 call call call call
jmp
tt2: cjne call call call call call
jmp
tt3: cjne call
jmp
tt4: cjne call call
jmp
tt5: cjne call call
call yyizhou yyizhou yyizhou zhuanpan0 tt
a,#9, tt3 yyizhou yyizhou yyizhou yyizhou zhuanpan0 tt
a,#4, tt4 zyizhou tt
a,#3, tt5 zyizhou zyizhou tt
a,#2, tt6 zyizhou zyizhou zyizhou
call zhuanpan1 jmp
tt
tt6: cjne a,#1, tt tt:
call zyizhou call zyizhou call zyizhou call zyizhou call zhuanpan1 ret
。=========触边旋转判断==================== zhuanpan0:
mov jnb
a,
31h
hui0
acc.0,
call zyizhou ajmp hui
a,
32h
hui1
hui0: mov
jnb
acc.0,
call zyizhou ajmp hui
a,
33h
hui
hui1: mov
jnb
acc.0,
call zyizhou
hui: ret
。========触边旋转判断==================== zhuanpan1:
mov jnb
a,
31h
hui3
acc.7,
call yyizhou ajmp hui2
hui3: mov
jnb
a, 32h
hui4
acc.7,
call yyizhou ajmp hui2
a,
33h
hui2
hui4: mov
jnb
acc.7,
call yyizhou
hui2: ret
。===========X轴右移一位================= yyizhou:
mov rl mov mov rl mov mov rl mov ret
a, a 31h, a a, a 32h, a a, a 33h, a
33h 32h 31h
。=========X轴左移一位================= zyizhou:
mov rr mov mov rr mov mov
a, a 31h, a a, a 32h, a a,
33h 32h 31h
rr mov ret
a 33h, a
。==============显示子程序========================== xianshi:
mov mov
p1, p2,
41h #0feh
call delay mov mov mov
p1, p1, p2,
#00 42h #0fdh
call delay mov mov mov
p1, p1, p2,
#00 43h #0fbh
call delay mov mov mov
p1, p1, p2,
#00 44h #0f7h
call delay mov mov mov
p1, p1, p2,
#00 45h #0efh
call delay mov mov mov
p1, p1, p2,
#00 46h #0dfh
call delay mov mov
p1, p1,
#00 47h
mov p2, #0bfh
call delay mov mov mov
p1, p1, p2,
#00 48h #7fh
call delay mov ret
p1,
#00
。===========消行显示子程序================== xiaohang:
mov
a,
48h
cjne a,#0ffh,zh0 call tiaozhen0 mov
a,
47h
zh0:
cjne a,#0ffh,zh1 call tiaozhen1 mov
a,
46h
zh1:
cjne a,#0ffh,zh2 call tiaozhen2 mov
a,
45h
zh2:
cjne a,#0ffh,zh3 call tiaozhen3 mov
a,
44h
zh3:
cjne a,#0ffh,zh4 call tiaozhen4 mov
a,
43h
zh4:
cjne a,#0ffh,zh5 call tiaozhen5 mov
a,
42h
zh5:
cjne a,#0ffh,zh6
call tiaozhen6 ret
48h, #00 49h, 48h 48h, 47h 47h, 46h zh6:
tiaozhen0: mov mov mov mov
tiaozhen1:
tiaozhen2:
mov 46h, mov 45h, mov 44h, mov 43h, mov 42h, mov 41h, ret
mov 47h, mov 49h, mov 47h, mov 46h, mov 45h, mov 44h, mov 43h, mov 42h, mov 41h, ret
mov 46h, mov 49h, mov 46h, mov 45h, mov 44h, mov
43h, 45h 44h 43h 42h 41h 49h
#00 47h 46h 45h 44h 43h 42h 41h 49h
#00 46h 45h 44h 43h 42h
mov mov ret
42h, 41h 41h, 49h
tiaozhen3: mov mov mov 45h, #00 49h, 45h 45h, 44h
tiaozhen4:
tiaozhen5:
tiaozhen6:
mov 44h, mov 43h, mov 42h, mov 41h, ret
mov 44h, mov 49h, mov 44h, mov 43h, mov 42h, mov 41h, ret
mov 43h, mov 49h, mov 43h, mov 42h, mov 41h, ret
mov 42h, mov 49h, mov 42h, mov 41h, ret
43h 42h 41h 49h
#00 44h 43h 42h 41h 49h
#00 43h 42h 41h 49h
#00 42h 41h 49h
。================================================= 。
延时1秒子程序
。================================================== yanshi_1s:
inc r3 mov
a,
r3
cjne a,4dh, xx mov r3,#00 setb bt1 ret
xx:
yanshi_500ms:
inc r3 mov
a,
r3
cjne a,#25, xx11 mov r3,#00 setb bt11
ret
xx11:
。================================================= 。
延时40m秒子程序
。================================================== yanshi_40ms:
inc r4 cjne r4,#3, ee mov r4, #00 setb bt5 ret mov div
mov b, ab
a, #5
tl1
ee: suiji:
mov ret
r1, b
。==================================================== 。
触底子程序
。====================================================== chudi:
cjne mov
cjne
ljmp bbb0: ljmp bbb1: mov
cjne
ljmp nn7: mov
cjne
ljmp nn8: mov
cjne
ljmp nn9: mov
cjne
ljmp nn10: mov
cjne
ljmp nn11: mov
cjne
ljmp mov
a,
33h a,#00, bbb0
a,
32h
a,#00h, bbb1
bbb bbb3 a,
35h
a,#0bfh,nn7 nn6 a,
35h
a,#0feh,nn8 kk0 a,
35h
a,#0fdh,nn9 kk1 a,
35h
a,#0fbh,nn10 kk2 a,
35h
a,#0f7h,nn11 kk3 a,
35h
a,#0efh,nn12 kk4
nn12:
mov a, 35h
cjne a,#0dfh,kk5 ljmp kk5 mov anl
a, a,
32h 43h
nn0
kk0: cjne a,#00h,
ljmp kk1: mov anl
cjne
ljmp kk2: mov anl
cjne
ljmp kk3: mov anl
cjne
ljmp kk4: mov anl
cjne
ljmp kk5: mov anl
cjne
ljmp nn0: mov
mov
bbb a, 32h a,
44h
a,#00h, nn1
bbb a, 32h a,
45h
a,#00h, nn2
bbb a, 32h a,
46h
a,#00h, nn3
bbb a, 32h a,
47h
a,#00h, nn4
bbb a, 32h a,
48h
a,#00h, nn5
bbb 35h, #0feh a,
32h
orl mov mov orl mov
a, 42h
42h, a a, a,
31h 41h
41h, a
setb bt10 call call
ljmp nn1: mov mov orl mov mov orl mov
call call
ljmp nn2: mov mov orl mov mov orl mov
call call
ljmp suiji chuzhi bbb 35h, #0feh a, 32h a,
43h
43h, a a, 31h a,
42h
42h, a
suiji chuzhi bbb 35h, #0feh a, 32h a,
44h
44h, a a, 31h a,
43h
43h, a
suiji chuzhi bbb
nn3: mov mov orl mov mov orl mov
call call
ljmp nn4: mov mov orl mov mov orl mov
call call
ljmp nn5: mov mov orl mov mov orl mov
call
call 35h, #0feh a, 32h a,
45h
45h, a a, 31h a,
44h
44h, a
suiji chuzhi bbb 35h, #0feh a, 32h a,
46h
46h, a a, 31h a,
45h
45h, a
suiji chuzhi bbb 35h, #0feh a, 32h a,
47h
47h, a a, 31h a,
46h
46h, a
suiji chuzhi
ljmp bbb nn6: mov mov orl mov mov orl mov
call call
ljmp bbb3: mov
cjne
ljmp bb6: mov
cjne
ljmp bb7: mov
cjne
ljmp bb8: mov
cjne
ljmp bb9: mov
cjne
ljmp bb10: mov
cjne
ljmp 35h, #0feh a, 32h a,
48h
48h, a a, 31h a,
47h
47h, a
suiji chuzhi bbb a,
35h
a,#0dfh,bb6 bb5 a,
35h
a,#0feh,bb7 jj0 a,
35h
a,#0fdh,bb8 jj1 a,
35h
a,#0fbh,bb9 jj2 a,
35h
a,#0f7h,bb10 jj3 a,
35h
a,#0efh,bbb9 jj4
bbb9: jj0: ljmp bbb mov anl
a, a,
33h 44h
cjne a,#00h, bb0
mov anl
cjne
ljmp jj1: mov anl
cjne mov anl
cjne
ljmp jj2: mov anl
cjne mov anl
cjne
ljmp jj3: mov anl
cjne mov anl
cjne
ljmp a, 32h a,
43h
a,#00h, bbb a, 33h a,
45h
a,#00h, a, 32h a,
44h
a,#00h, bbb a, 33h a,
46h
a,#00h, a, 32h a,
45h
a,#00h, bbb a, 33h a,
47h
a,#00h, a, 32h a,
46h
a,#00h, bbb
bb0
bb1
bb1
bb2
bb2
bb3
bb3
jj4: mov anl
a, a,
33h 48h
bb11
cjne a,#00h, mov anl
a, a,
32h 47h
cjne a,#00h, bb4
ljmp bb11: ljmp bb0: mov mov orl mov mov orl mov mov orl mov
setb call call
ljmp bb1: mov mov orl mov mov orl
mov
bbb bb4 35h, #0feh a, 33h a,
43h
43h, a a, 32h a,
42h
42h, a a, 31h a,
41h
41h, a
bt10 suiji chuzhi bbb
35h, #0feh a, 33h a,
44h
44h, a a, 32h a,
43h
43h, a
mov orl mov
a, a,
31h 42h
42h, a
call suiji call chuzhi ljmp bbb
bb2: mov mov orl mov mov orl mov mov orl mov
call call
ljmp bb3: mov mov orl mov mov orl mov mov orl
mov
35h, #0feh a, 33h a,
45h
45h, a a, 32h a,
44h
44h, a a, 31h a,
43h
43h, a
suiji chuzhi bbb 35h, #0feh a, 33h a,
46h
46h, a a, 32h a,
45h
45h, a a, 31h a,
44h
44h, a
call suiji call chuzhi ljmp bbb bb4: mov mov orl mov mov orl mov mov orl mov
call call
ljmp bb5: mov mov orl mov mov orl mov mov orl mov
call
call bbb:
ret
35h, #0feh a, 33h a,
47h
47h, a a, 32h a,
46h
46h, a a, 31h a,
45h
45h, a
suiji chuzhi bbb 35h, #0feh a, 33h a,
48h
48h, a a, 32h a,
47h
47h, a a, 31h a,
46h
46h, a
suiji chuzhi
。============================================================== 。
填装初值子程序
。=============================================================== chuzhi: mov mov
cjne mov
ajmp aa1: cjne mov
ajmp aa2: cjne mov
ajmp aa3: cjne mov
ajmp aa4: cjne mov
ajmp aa5: cjne mov mov aa: mov mov
movc mov
inc
mov
51h, #5
4dh, #50h r2,
#00
r1,#0,aa1 dptr, #tab0
aa
r1,#1, aa2
dptr, #tab1
aa
r1,#2, aa3
dptr, #tab2
aa
r1,#3, aa4
dptr, #tab3
aa
r1,#4, aa5
dptr, #tab4
aa
r1,#5, aa6
dptr, #tab5 r1, #00 r3, #00 a,
r3
a, @a+dptr
31h, a r3
mov a, r3 @a+dptr
movc a, mov inc mov
32h, a r3 a,
r3 @a+dptr #0
movc a, mov mov
r3,
33h, a
aa6: ret
。============================================================= 。
初始化设置子程序
。============================================================= chushihua:
mov mov mov mov mov mov mov mov mov mov mov mov mov ret
30h, #00 31h, #00 32h, #00 33h, #00 35h, #0feh 41h, #00 42h, #00 43h, #00 44h, #00 45h, #00 46h, #00 47h, #00 48h, #00
。============================================================= 。
延时子程序,延时1.5ms
。============================================================ delay: d1:
mov
mov r6,
r5, #25 $ d1
#30
djnz r6, djnz r5, ret
。============================================================ 。
各种图形表
。============================================================ tab0: db 10h,38h,00h,00h,00h,00h,00h,00h tab1: db 30h,18h,00h,00h,00h,00h,00h,00h tab2: db 10h,18h,08h,00h,00h,00h,00h,00h tab3: db 10h,10h,30h,00h,00h,00h,00h,00h tab4: db 08h,38h,00h,00h,00h,00h,00h,00h tab5: db 18h,18h,00h,00h,00h,00h,00h,00h
。========================================================== 。
定时器0中断子程序
。========================================================== intt0:
mov th0, #0b1h
mov tl0, #0e0h setb bt0 reti
。========================================================== 。
结束
。==========================================================
end
5 作品展示
6 元器件清单
ATS52芯片一个 8元 5个按键 0.5 74HC573驱动芯片 2元 LED
1个1K的上拉排阻 1元容
元 点阵屏幕 8元 一个10uf电容电解电
8个100的限流电阻 2个30pf
电容无极性
一个LED指示灯
1个330
的电阻
一个10K电阻
1
个11.0592的晶振
合计:24元
7 结束语
我在前面的一些处理还是比较顺利,比如说按键的处理、下移、左右移、旋转、消行、碰边等问题,2天的时间就弄好了。最浪费我时间的是与下面的图形相遇的处理。开始判倒是能够判断,但只能在一个固定的区域里停止下移。后来经过老师指导要我把显示图形的三个地址作为一个整体判断,也弄了好久,还是有些地方不能判断出来,思考好久之后我才想到用这个方法判断出来。还有旋转,开始总想不到算法,最后老师指导我用位地址操作 先把图形放旋转区旋转 在放到操作地址区,记下左右上下移动次数确实帮了我不少的忙 碰边处理用异或处理。触底时把每一行数据放个定义的地址区域,最后与#0FFH判断做很妙。
还有就是硬件处理的比较麻烦,开始不太清楚点阵的引脚排布,这里弄了好久,后
来驱动那里也出现了好多问题,开始我用74HS373来驱动,没注意引脚排列,最后用了74HC573 他们功能一样,但是74HC573输入输出接在一边便于排线。
开始没有规划好地址的用途。到最后出现了地址不够用的现象,所以良好的编程习
惯很重要。 通过这个项目,真的时对自己思维的一次很大的挑战,程序1200多行,ATS51装不下,改用ATS52做。 通过这次项目我找到点成就感,也希望自己以后能经常有这种成就感,在电子领域站一席之地。 致 谢
在此论文撰写过程中,要特别感谢我的导师的指导与督促,同时感谢她的谅解与包容。没有何老师的帮助也就没有今天的这篇论文。求学历程是艰苦的,但又是快乐的。感谢我的班主任XXX老师,谢谢他在这三年中为我们全班所做的一切,他不求回报,无私奉献的精
神很让我感动,再次向他表示由衷的感谢。在这三年的学期中结识的各位生活和学习上的挚友让我得到了人生最大的一笔财富。在此,也对他们表示衷心感谢。 谢谢我的父母,没有他们辛勤的付出也就没有我的今天,在这一刻,将最崇高的敬意献给你们!
本文参考了大量的文献资料,在此,向各学术界的前辈们致敬!
参考文献
余小清、赵恒凯等编.现代通信原理<第5版).北京:清华大学出版社,2007 张辉、曹丽娜编.现代通信原理与技术<第1版).北京:西安电子科技大学出版社,2002
Tsui.I.带宽数字接收机.美:电子工业出版社,2002
单片机编写俄罗斯方块游戏 关于俄罗斯方块程序的一些问题: ****************************************************** Tc2.0中怎么样设置图形显示? Tc2.0中常用图形函数的用法? 怎样获取鍵盘输入? 怎样控制方块的移动? 怎样控制时间间隔(用于游戏中控制形状的下落>? 游戏中的各种形状及整个游戏空间怎么用数据表示? 游戏中怎么判断左右及向下移动的可能性? 游戏中怎么判断某一形状旋转的可能性? 按向下方向键时加速某一形状下落速度的处理? 怎么判断某一形状已经到底? 怎么判断某一已经被填满? 怎么消去已经被填满的一行? 怎么消去某一形状落到底后能够消去的所有的行?(如长条最多可以消去四行> 怎样修改游戏板的状态? 怎样统计分数? 怎样处理升级后的加速问题? 怎样判断游戏结束? 关于计分板设计的问题。 关于“下一个”形状取法的问题。 剩下的问题。
****************************************************** 新的问题: 我想有一个最高记录的显示,应该怎么做呀? 我想实现一个进度存储功能,应该怎么做呀?
Tc2.0中怎么样设置图形显示?
Tc2.0中有两种显示模式,一种是我们所熟知的字符模式,另一种是图形模式。在字符模式下只能显式字符,如ASCII字符。一般是显示25 行,每行80个字符。程序缺省的是字符模式。在字符模式下不能显式图形和进行绘图操作。要想进行图形显示和绘图操作,必须切换到图形模 式下。
Tc2.0中用initgraph(>函数可以切换到图形模式,用closegraph(>可以从图形模式切换回字符模式。initgraph(>和closegraph(>都是图形 函数,使用图形函数必须包括头文件\"graphics.h\"。
void far initgraph(int far *graphdriver,int far *graphmode,char far *pathtodriver>。graphdriver是上涨指向图形驱动序号变量的指针;graphmode是在graphdriver选定后,指向图形显示模式序号变量的指针。pathtodriver表示存放图形驱动文件的路径。
Tc2.0中有多种图形驱动,每种图形驱动下又有几种图形显示模式。在我的程序中图形驱动序号为VGA,图形显示模式序号为VGAHI。这是一种分辨率为0*480(从左到右坐标依次为0-639,从上到下坐标依次为0-479>,能够显示16种颜色的图形模式。别的图形驱动序号和图形显示模式序号,可以从手册或联机帮助中找到。
pathtodriver指示存放图形驱动文件的路径。图形驱动序号不同,图形驱动文件也不同。序号为VGA图形驱动对应\"egavga.bgi\"这个图形驱动文件。\"egavga.bgi\"一般在Tc目录下。
void far closegraph(void>。 没有参数,从图形模式直接返回字符模式。
initgraph(>和closegraph(>的常用用法如下: int gdriver = VGA, gmode=VGAHI, errorcode。 /* initialize graphics mode */ initgraph(&gdriver, &gmode, \"e:\\\c2\">。 /* read result of initialization */ errorcode = graphresult(>。 if (errorcode != grOk> /* an error occurred */ {
printf(\"Graphics error: %s\\n\grapherrormsg(errorcode>>。 printf(\"Press any key to halt:\">。
getch(>。 exit(1>。 /* return with error code */ } /* return to text mode */ closegraph(>。
Tc2.0中常用图形函数的用法?
在这里讲几个游戏中用到的绘图用的图形函数: setcolor(>。 line(>。 rectangle(>。 settextjustify(>。 outtextxy(>。 setfillstyle(>。 bar(>。
void far setcolor(int color>。 设置画线、画框和在图形模式下显示文字的当前颜色。这个函数将影响line(>、rectangle(>和outtextxy(>函数绘图的颜色。 color可以取常的颜色常量: BLACK ? 0 BLUE ? 1 GREEN ? 2 CYAN ? 3 RED ? 4 MAGENTA ? 5 BROWN ? 6 LIGHTGRAY ? 7 DARKGRAY ? 8 LIGHTBLUE ? 9 LIGHTGREEN ?10 LIGHTCYAN ?11 LIGHTRED ?12 LIGHTMAGENTA ?13 YELLOW ?14 WHITE ?15
void far line(int x1,int y1,int x2,int y2>。 用当前颜色从(x1,y1>画一条到(x2,y2>的线段。
void far rectangle(int left,int top,int right,int bottom>。
用当前颜色画一个左上角为(left,top>、右下角为(right,bottom>的矩形框。
void far settextjustify(int horz,int vert>。 设置图形模式下文字输出的对齐方式。主要影响outtextxy(>函数。 horiz和vert可取如下枚举常量: horiz ?LEFT_TEXT ? 0 ?Left-justify text ?CENTER_TEXT ? 1 ?Center text ?RIGHT_TEXT ? 2 ?Right-justify text vert ?BOTTOM_TEXT ? 0 ?Justify from bottom ?CENTER_TEXT ? 1 ?Center text ?TOP_TEXT ? 2 ?Justify from top
void far outtextxy(int x,int y,char * textstring>。 在(x,y>处用当前字体(缺省的字体是DEFAULT_FONT>显示字符串textstring,字符串的对齐方式由settextjustify(>指定。
void far setfillstyle(int pattern,int color>。 设置图形的填充模式和填充颜色,主要影响bar(>等函数。 pattern一般取枚举常量值SOLID_FILL,color的取值与setcolor(int color>中color的取值范围相同。
介绍完了前面两个问题,现在来写一个程序。这个程序演示前了面所介绍的几个图形函数。 程序prog1.c 怎样获取鍵盘输入?
在Tc2.0中有一个处理键盘输入的函数bioskey(>。 int bioskey(int cmd>。 当cmd为1时,bioskey(>检测是否有键按下。没有键按下时返回0;有键按下时返回按键码(任何按键码都不为0>,但此时并不将检测到的按 键码从键盘缓冲队列中清除。 当cmd为0时,bioskey(>返回键盘缓冲队列中的按键码,并将此按键码从键盘缓冲队列中清除。如果键盘缓冲队列为空,则一直等到有键按 下,才将得到的按键码返回。
Escape键的按键码为0x11b,下面的小程序可以获取按键的按键码。 for (。。> {
key=bioskey(0>。 /* wait for a keystroke */ printf(\"0x%x\\n\。 if (key==0x11b> break。 /* Escape */
} 常用按键的按键码如下:
#define VK_LEFT 0x4b00 #define VK_RIGHT 0x4d00 #define VK_DOWN 0x5000 #define VK_UP 0x4800 #define VK_HOME 0x4700 #define VK_END 0x4f00 #define VK_SPACE 0x3920 #define VK_ESC 0x011b #define VK_ENTER 0x1c0d 完整的程序请参见prog2.c、prog3.c。 prog2.c获取按键的按键码,按Escape键退出程序。 prog3.c根据不同的按键进行不同的操作,按Escape键退出程序。 怎样控制方块的移动? 方块移动的实现很简单,将方块原来的位置用背景色画一个同样大小的方块,将原来的方块涂去。然后在新的位置上重新绘制方块就可以 了。这样就实现了方块的移动。完整的程序请参见prog4.c。这个用方向键控制一个黄色的小方块在屏幕上上、下、左、右移动。这个程序用到了前面几个问题讲的内容,如果你有点忘了,还要回头看看哦。:)
怎样控制时间间隔(用于游戏中控制形状的下落>? 解决这个问题要用到时钟中断。时钟中断大约每秒钟发生18.2次。截获正常的时钟中断后,在处理完正常的时钟中断后,将一个计时变量 加1。这样,每秒钟计时变量约增加18。需要控控制时间的时候,只需要看这个计时变量就行了。
截获时钟中断要用到函数getvect(>和setvect(>。 两个函数的声明如下: ?void interrupt (*getvect(int interruptno>>(>。 ?void setvect(int interruptno, void interrupt (*isr> ( >>。
保留字interrupt指示函数是一个中断处理函数。在调用中断处理函数的时候,所有的寄存器将会被保存。中断处理函数的返回时的指令是iret,而不是一般函数用到的ret指令。
getvect(>根据中断号interruptno获取中断号为interruptno的中断处理函数的入口地址。 setvect(>将中断号为interruptno的中断处理函数的入口地址改为isr(>函数的入口地址。即中断发生时,将调用isr(>函数。
在程序开始的时候截获时钟中断,并设置新的中断处理。在程序结束的时候,一定要记着恢复时钟中断哦,不然系统的计时功能会出问题 的。具体演示程序请参见prog5.c。因为中断处理大家可能用的不多,所以我把prog5.c这个程序完整地贴在下面,并加上详细的解释。 /* prog5.c */ This is an interrupt service routine. You can NOT compile this program with Test Stack Overflow turned on and get an executable file which will operate correctly. */
/* 这个程序每隔1秒钟输出一个整数,10秒钟后结束程序。 按escape键提前退出程序 。*/
#include #define TIMER 0x1c /* 时钟中断的中断号 */ /* 中断处理函数在C和C++中的表示略有不同。 如果定义了_cplusplus则表示在C++环境下,否则是在C环境下。 */ #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif int TimerCounter=0。 /* 计时变量,每秒钟增加18。 */ /* 指向原来时钟中断处理过程入口的中断处理函数指针(句柄> */ void interrupt ( *oldhandler>(__CPPARGS>。 /* 新的时钟中断处理函数 */ void interrupt newhandler(__CPPARGS> { /* increase the global counter */ TimerCounter++。 /* call the old routine */ oldhandler(>。 } /* 设置新的时钟中断处理过程 */ void SetTimer(void interrupt (*IntProc>(__CPPARGS>> { oldhandler=getvect(TIMER>。 disable(>。 /* 设置新的时钟中断处理过程时,禁止所有中断 */ setvect(TIMER,IntProc>。 enable(>。 /* 开启中断 */ } /* 恢复原有的时钟中断处理过程 */ void KillTimer(> { disable(>。 setvect(TIMER,oldhandler>。 enable(>。 } void main(void> { int key,time=0。 SetTimer(newhandler>。 /* 修改时钟中断 */ for (。。> { if (bioskey(1>> { key=bioskey(0>。 if (key==VK_ESC> /* 按escape键提前退出程序 */ { printf(\"User cancel!\\n\">。 break。 } } if (TimerCounter>18> /* 1秒钟处理一次 */ { /* 恢复计时变量 */ TimerCounter=0。 time++。 printf(\"%d\\n\。 if (time==10> /* 10秒钟后结束程序 */ { printf(\"Program terminated normally!\\n\">。 break。 } } } KillTimer(>。 /* 恢复时钟中断 */ } 游戏中的各种形状及整个游戏空间怎么用数据表示? 以后我提到的形状都是指下面七种形之一及它们旋转后的变形体。 □□□□□□□□□□□□□□□□□■□□□■■□□□□□□□□□□■□□□■□□□■□□□■■□□■■□□■□□■■■□■■□□□□□□□■□□□□□□□□□□□■□□□□□□■■□□□■□□□■■□□■■□□■□□□■■□ 我定义了一个结构来表示形状。 struct shape { int xy[8]。 int color。 int next。 } -1 0 1 2 -3□□□□ -2□□□□ -1□□□□ 0□■□□ 所有的各种形状都可以放在4x4的格子里。假定第二列,第四行的格子坐标为(0,0>(如上图中黑块所示>,则每个形状的四个方块都可以用4 个数对来表示。坐标x从左向右依次增加,y从上到下依次增加。表示的时候,组成该形状的四个方块从左到右,从上到下(不一定非要按这个顺 序>。如上面七种形状的第一个用数对来表示就是(-2,0>、(-1,0>、(0,0>、(1,0>。结构shape中的xy就是用来表示这4个数对的。为了简化程序,用一维数组xy[8]来表示。 xy[0]、xy[1]表示第一个数对,xy[2]、xy[3]表示第二个数对,依次类推。 shape中的color表示形状的颜色,不同的形状有不同的颜色。七种形状及它们旋转后的变形体一共有19种形状,用一个全局数组表示。假定旋转的方向是逆时针方向(顺时针方向道理一样>。shape中的next就表示当前形状逆时针旋转后的下一个形状的序号。例如:第一种形状及其旋 转变形的形状用结构表示如下。 □□□□□□□□□□□□□□□□□■□□□□□□□■■□□□□□□■□□□□■□□□■□■■■□□■■□■■■□□□■□■□□□ struct shape shapes[19]= { /*{x1,y1,x2,y2,x3,y3,x4,y4, color, next}*/ { 0,-2, 0,-1, 0, 0, 1, 0, CYAN, 1}, /* */ {-1, 0, 0, 0, 1,-1, 1, 0, CYAN, 2}, /* # */ { 0,-2, 1,-2, 1,-1, 1, 0, CYAN, 3}, /* # */ {-1,-1,-1, 0, 0,-1, 1,-1, CYAN, 0}, /* ## */ …… } 游戏空间指的是整个游戏主要的界面(呵呵,这个定义我实在想不出更准确的,还请哪位大虾指点>。实际上是一个宽10格子、高20格子的 游戏板。用一个全局数组board[12][22]表示。表示的时候:board[x][y]为1时表示游戏板上(x,y>这个位置上已经有方块占着了,board[x][y] 为0表示游戏板上这位置还空着。为了便于判断形状的移动是否到边、到底,初始的时候在游戏板的两边各加一列,在游戏板的下面加一行,全 部填上1,表示不能移出界。即board[0][y],board[11][y](其中y从0到21>初始都为1,board[x][21](其中x从1到10>初始都为1。 1 2 3 4 5 6 7 8 910 1□□□□□□□□□□ 2□□□□□□□□□□ 3□□□□□□□□□□ 4□□□□□□□□□□ 5□□□□□□□□□□ 6□□□□□□□□□□ 7□□□□□□□□□□ 8□□□□□□□□□□ 9□□□□□□□□□□ 10□□□□□□□□□□ 11□□□□□□□□□□ 12□□□□□□□□□□ 13□□□□□□□□□□ 14□□□□□□□□□□ 15□□□□□□□□□□ 16□□□□□□□□□□ 17□□□□□□□□□□ 18□□□□□□□□□□ 19□□□□□□□□□□ 20□□□□□□□□□□ prog6.c演示了用结构表示各种形状的方法。虽然程序稍长一些,但并不是特别复杂。其中游戏板初始化部分并没有真正用到,但是后面的程 序会用到的。其中SIZE定义为16,这样将整个屏幕的坐标系由原来的0×480转换成40×30(0/16=40,480/16=30>。游戏中所有的坐标都是基于40×30的坐标系的,这样有助于简化程序。坐标的转换在程序中由DrawBlock(int x,int y>来体现。 新的坐标系如下图所示: -8-7-6-5-4-3-2-1 0 1 2 3 4 5 6 7 8 91122232425262728293031 -4□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ -3□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ -2□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ -1□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 0□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 1□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 2□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 3□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□ 4□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□ 5□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□ 6□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□ 7□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 8□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 9□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 10□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 11□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 12□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 13□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 14□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 15□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 16□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 17□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 18□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 19□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 20□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□ 21□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 22□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 23□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 24□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 25□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 26□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□ 新坐标中最主要的是就是上面两块黑色的部分。左边那块大的就是游戏板<横坐标从1到10,纵坐标从1到20),右边那块小的就是显示“下一个”形状的部分<横坐标从14到17,纵坐标从3到6)。这个新的坐标系是整个游戏的基础,后面所有的移动、变形等的计算都是基于这个坐标系的。 游戏中怎么判断左右及向下移动的可能性? 看懂了前面的各种形状和游戏板等的表示,接下来的东西就都好办多了。先来看一下 某个形状如何显示在游戏板当中。假设要在游戏板中 显示第一个形状。第一个形状在结构中的表示如下: struct shape shapes[19]= { /*{x1,y1,x2,y2,x3,y3,x4,y4, color, next}*/ { 0,-2, 0,-1, 0, 0, 1, 0, CYAN, 1}, …… } 那么这个组成形状四个方块的坐标表示为(0,-2>、(0,-1>、(0,0>和(1,0>。这实际上是相对坐标。假形状的实际坐标指的是4x4方块中的第 二列、第三行的方块的位置,设这个位置为(x,y>。那么组成这个形状的四个小方块的实际坐标<以第一个形状为例)就是(x+0,y-2>、(x+0,y-1>、(x+0,y+0>和(x+1,y+0>。因为所有的形状都可以在4x4的方块阵列中表示,这样就找到了一种统一的方法来表示所有的形状了。 -1 0 1 2 -3□□□□ 相对坐标 -2□■□□ -1□■□□ 组成第一种形状的四个方块的相对坐标为(0,-2>、(0,-1>、(0,0>和(1,0>。 0□■■□ 让我们看看形状是如何显示在游戏板中的<以第一个形状为例)。 1 2 3 4 5 6 7 8 910 1□■□□□□□□□□ 形状的坐标为(2,3>。组成形状的四个方块的坐标由形状的 2□■□□□□□□□□ 坐标加上这四个小方块各自的相对坐标得出。它们分别是: 3□■■□□□□□□□ (2+0,3-2>、(2+0,3-1>、(2+0,3-0>和(2+1,3-0>。即: 4□□□□□□□□□□ (2,1>、(2,2>、(2,3>和(3,3>。如左图所示。 5□□□□□□□□□□ 6□□□□□□□□□□ 7■□□□□□□□□□ 形状的坐标为(1,9>。组成形状的四个方块的坐标分别是: 8■□□□□□□□□□ (1+0,9-2>、(1+0,9-1>、(1+0,9-0>和(1+1,9-0>。即: 9■■□□□□□□□□ (1,7>、(1,8>、(1,9>和(2,9>。如左图所示。 10□□□□□□□□□□ 11□□□□□□□□□□ 12□□□□□□□□□□ 13□□□□□□□□□□ 14□□□□□□□□□□ 15□□□□□□□□□□ 16□□□□□□□□□□ 17□□□□□□□□□□ 18□□□□□□□□■□ 形状的坐标为(9,20>。组成形状的四个方块的坐标分别是: 19□□□□□□□□■□ (9+0,20-2>、(9+0,20-1>、(9+0,20-0>和(9+1,20-0>。即: 20□□□□□□□□■■ (9,18>、(9,19>、(9,20>和(10,20>。如左图所示。 从现在起,我不再举别的示例程序了。从现在开始所有的示例代码均来自于我写的\"Russia.c\"。为了记录游戏板的状态,用了一个全局数组board[12][22]。board[x][y]<其中x从0到11,y从1到21)等于1表示(x,y>这个位置已经被填充了,组成形状的四个方块的坐标都不能为(x,y>,否则将发生冲突。board[x][y]<其中x从1到10,y从1到20)等于表示(x,y>这个位置还没有被填充。 游戏板初始化时,给board[0][y],board[11][y]<其中y从1到21)都赋为1,给board[x][21]<其中x从1到10)都赋为1。这相当于一开始就给游戏板左右和下方加了个“边”。所有的形状都不能够移入这个“边”,否则将发生冲突。 现在我们可以开始讨论如何判断一个形状向左、向右和向下移动的可能性了。先说个概念,“当前形状”是指那个正在下落还没有落到底的那个形状。如果当前形状向左移动,不与游戏板现有状态发生冲突,则可以向左移动。具体做法是:先假设当前形状已经向左移动了,判断此时是否与游戏板现有状态发生冲突。如果不发生冲突,则可以向左移动。否则,不可以向左移动。 判断索引号为ShapeIndex的形状在坐标(x,y>是否与游戏板当前状态发生冲突的代码如下。我把详细的说明加在这段代码中。 enum bool Confilict(int ShapeIndex,int x,int y> { int i。 /* 对组成索引号为ShapeIndex的形状的四个方块依次判断 */ for (i=0。i<=7。i++,i++> /* i分别取0,2,4,6 */ { /* 如果四个方块中有任何一个方块的x坐标小于1或大于10,表示超出左边界或右边界。 此时,发生冲突。 */ if (shapes[ShapeIndex].xy+x<1 || shapes[ShapeIndex].xy+x>10> return True。 /* 如果四个方块中某个方块的y坐标小于1,表示整个形状还没有完全落入游戏板中。 此时,没有必要对这个方块进行判断。*/ if (shapes[ShapeIndex].xy[i+1]+y<1> continue。 /* 如果四个方块中有任何一个方块与游戏板当前状态发生冲突,则整个形状在(x,y>处 与游戏板当前状态冲突 */ if (board[shapes[ShapeIndex].xy+x][shapes[ShapeIndex].xy[i+1]+y]> return True。 } /* 四个方块中没有任何一个方块与游戏板当前状态发生冲突,则整个形状在(x,y>处 没有与游戏板当前状态冲突 */ return False。 } 对以上代码附加说明如下: shapes[ShapeIndex].xy<其中i等于0,2,4,6)表示组成索引号为ShapeIndex的形状的某个方块的x相对坐标。(i等于0时,表示第1个方块的x相对坐标;i等于2时,表示第2个方块的x相对坐标;i等于4时,表示第3个方块的x相对坐标;i等于6时,表示第4个方块的x相对坐标。) shapes[ShapeIndex].xy<其中i等于1,3,5,7)表示组成索引号为ShapeIndex的形状的某个方块的y相对坐标。(i等于1时,表示第1个方块的y相对坐标;i等于3时,表示第2个方块的y相对坐标;i等于5时,表示第3个方块的y相对坐标;i等于7时,表示第4个方块的y相对坐标。) shapes[ShapeIndex].xy+x<其中i等于0,2,4,6)表示索引号为ShapeIndex的形状的坐标为(x,y>时,组成该形状的某个方块的x实际坐标。(i等于0时,表示第1个方块的x实际坐标;i等于2时,表示第2个方块的x实际坐标;i等于4时,表示第3个方块的x实际坐标;i等于6时,表示第4个方块的x实际坐标。) shapes[ShapeIndex].xy+y<其中i等于1,3,5,7)表示索引号为ShapeIndex的形状的坐标为(x,y>时,组成该形状的某个方块的y实际坐 标。(i等于1时,表示第1个方块的y实际坐标;i等于3时,表示第2个方块的y实际坐标;i等于5时,表示第3个方块的y实际坐标;i等于7时,表示第4个方块的y实际坐标。) 现在来看看这句是什么意思吧。 board[shapes[ShapeIndex].xy+x][shapes[ShapeIndex].xy[i+1]+y] 可以这样理解,把上面一句分开来看:: ActualX=shapes[ShapeIndex].xy+x;/* 其中x为0,2,4,6 */ 表示某个方块实际的x坐标。 ActualY=[shapes[ShapeIndex].xy[i+1]+y; 表示某个方块实际的y坐标。 board[ActualX][ActualY]就是与某个方块坐标相同处的游戏板的标志。如果此标志不为0<为1),表示这个方块与游戏板发生冲突。如果此标志为0,表示这个方块没有与游戏板发生冲突。 这段写的比较长,但是不是特别难理解。游戏中很多地方都用到了这种相对坐标向实际坐标的转换方式,看懂了这一段对理解其他部分的代码很有帮助。 仔细看过这段代码后,你可能会提一个问题:不是已经在游戏板的左右两边都加了“边”了吗,为什么还要加下面这个对x坐标的判断呢? /* 如果四个方块中有任何一个方块的x坐标小于1或大于10,表示超出左边界或右边界。 此时,发生冲突。 */ if (shapes[ShapeIndex].xy+x<1 || shapes[ShapeIndex].xy+x>10> return True。 这是因为有一种特殊情况,如下图所示: ■■■ 2 3 4 5 6 7 8 910 1■□□□□□□□□□ 这在当前形状刚出来的时候,是可能发生的。但是我们只给游戏板 2□□□□□□□□□□ 加了一层“边”。对于这个形状的最左边的那个方块将失去判断, 3□□□□□□□□□□ 如果不予理会,这个形状将会“挂”在游戏板的左上角!当初我也 4□□□□□□□□□□ 没有想到这一点,后来发现会有形状“挂”在最顶层,而导致游戏 5□□□□□□□□□□ 提前退出。发现了这个问题。 6□□□□□□□□□□ 7□□□□□□□□□□ 8□□□□□□□□□□ 加了这个判断后,游戏板的左右两个“边”对冲突的判断就是去意 9□□□□□□□□□□ 义了。因为没有这两个“边”,对于冲突的判断也不会出错。不过 10□□□□□□□□□□ 为了程序易于理解,还是保留了游戏板的左右两个“边”。 11□□□□□□□□□□ 12□□□□□□□□□□ 13□□□□□□□□□□ 14□□□□□□□□□□ 15□□□□□□□□□□ 16□□□□□□□□□□ 17□□□□□□□□□□ 18□□□□□□□□□□ 19□□□□□□□□□□ 20□□□□□□□□□□ 如果你对我上面提出的新问题及对于这个问题的解释不太明白,没关系,这并不重要。因为现在才刚刚开始,而且刚才所说的这个问题只 有在特殊情况下才出现<当然,一旦发生上面说的问题,游戏就出错啦!^_^ ),对于理解整个程序的思路影响不大。看多了就会明白了<你 会说:原来就这么简单!) #include #define BACKCOLOR BLACK #define WINX 50 #define WINY 470 #define GAP 6 #define AREAX (WINX+GAP> #define AREAY (WINY-GAP> #define BOXW 15 int oldarea[MAXY+1][MAXX]。 int area[MAXY+1][MAXX]。 int actW,actH,actX,actY。 int curX,curY,curColor,curW,curH。 int newX,newY,newColor,newW,newH。 int active。 int box[4][4]。 int FORCOLOR。 int MESSAGE。 int BOX[7][4][4]={ { {1,1,1,1}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} },{ {1,1,1,0}, {1,0,0,0}, {0,0,0,0}, {0,0,0,0} },{ {1,1,1,0}, {0,0,1,0}, {0,0,0,0}, {0,0,0,0} },{ {1,1,1,0}, {0,1,0,0}, {0,0,0,0}, {0,0,0,0} },{ {1,1,0,0}, {0,1,1,0}, {0,0,0,0}, {0,0,0,0} },{ {0,1,1,0}, {1,1,0,0}, {0,0,0,0}, {0,0,0,0} },{ {1,1,0,0}, {1,1,0,0}, {0,0,0,0}, {0,0,0,0} } }。 void init(>。 void draw(>。 int genBox(>。 int getKey(>。 void lineFull(>。 int moveLeft(>。 int moveRight(>。 int moveDown(>。 int rotate(>。 int getW(>。 int getH(>。 void clearOldBox(>。 void putNewBox(>。 int collisionRotate(int box[][4]>。 void getMessage(>。 void dispatchMessage(>。 int timeCome(>。 void fallDown(>。 int gameOver(>。 main(> { int i。 init(>。 do { getMessage(>。 dispatchMessage(>。 } while(!gameOver(>>。 getch(>。 closegraph(>。 } void getMessage(> { if(MESSAGE> return。 if(timeCome(>> { MESSAGE=mADOWN。 return。 } if(bioskey(1>> { MESSAGE=bioskey(0>>>8。 return。 } } void dispatchMessage(> { switch(MESSAGE> { case mLEFT: moveLeft(>。break。 case mRIGHT: moveRight(>。break。 case mADOWN: moveDown(>。break。 case mSPACE: rotate(>。break。 case mDOWN: fallDown(>。 break。 case mDRAW: draw(>。break。 case mLINE: lineFull(>。break。 case mGEN: genBox(>。break。 case mESC: closegraph(>。 exit(0>。 default: MESSAGE=0。 } } void fallDown(> { while(active> { moveDown(>。 draw(>。 } MESSAGE=mLINE。 } int timeCome(> { static long tm, old。 tm=biostime(0,tm>。 if(tm-old old=tm。 return 1。 } } void init(> { int i,j,x1,y1,x2,y2。 int driver=DETECT, mode=0。 randomize(>。 registerbgidriver(EGAVGA_driver>。 initgraph(&driver,&mode,\"\">。 cleardevice(>。 setfillstyle(SOLID_FILL,BLUE>。 bar(0,0,639,479>。 x1=AREAX。 y1=AREAY-BOXW*MAXY。 x2=AREAX+MAXX*BOXW。 y2=AREAY。 rectangle(--x1,--y1,++x2,++y2>。 setfillstyle(SOLID_FILL,BLACK>。 bar(++x1,++y1,--x2,--y2>。 y1=AREAY-MAXY*BOXW。 y2=AREAY。 setcolor(DARKGRAY>。 for(i=0。i x1=AREAX+i*BOXW。 line(x1,y1,x1,y2>。 } x1=AREAX。 x2=x1+MAXX*BOXW。 for(j=0。j y1=AREAY-j*BOXW。 line(x1,y1,x2,y1>。 } for(j=0。j actX=0。 actY=0。 actW=MAXX-1。 actH=MAXY-1。 draw(>。 MESSAGE=mGEN。 } int genBox(> { int i,j,boxidx。 boxidx=random(7>。 FORCOLOR=random(7>+1。 for(j=0。j<4。j++> for(i=0。i<4。i++> box[j][i]=BOX[boxidx][j][i]。 curW=getW(>。 curH=getH(>。 curX=(MAXX+curW>/2。 if(curX+curW>=MAXX>curX=MAXX-1-curW。 curY=MAXY-1-curH。 newX=curX。 newY=curY。 actX=curX。actY=curY。 actW=newW=curW。 actH=newH=curH。 active=1。 if(collision(box>> return 0。 putNewBox(>。 draw(>。 MESSAGE=0。 return 1。 } void lineFull(> { int row,col, rowEnd,full,i,j。 rowEnd=newY+newH。 if(rowEnd>=MAXY-1> rowEnd=MAXY-2。 for(row=newY。 row<=rowEnd。> { full=1。 for(col=0。col actX=0。actY=row。 actW=MAXX-1。 actH=MAXY-1-row。 draw(>。 rowEnd--。 } MESSAGE=mGEN。 } void draw(> { int row,col,x1,y1,x2,y2。 for(row=actY。row<=actY+actH。row++> for(col=actX。col<=actX+actW。col++> if(area[row][col]!=oldarea[row][col]> { if(area[row][col]==0> setfillstyle(SOLID_FILL,BACKCOLOR>。 else setfillstyle(SOLID_FILL,FORCOLOR>。 x1=AREAX+col*BOXW。 x2=x1+BOXW。 y1=AREAY-(row+1>*BOXW。 y2=y1+BOXW。 bar(++x1,++y1,--x2,--y2>。 oldarea[row][col]=area[row][col]。 } MESSAGE=0。 } int moveLeft(> { newX=curX-1。 clearOldBox(>。 if(collision(box>> { newX=curX。 putNewBox(>。 MESSAGE=0。 return 0。 } putNewBox(>。 actW=curW+1。 actX=curX=newX。 MESSAGE=mDRAW。 return 1。 } int moveRight(> { newX=curX+1。 clearOldBox(>。 if(collision(box>> { newX=curX。 putNewBox(>。 MESSAGE=0。 return 0。 } putNewBox(>。 actW=curW+1。 actX=curX。 curX=newX。 MESSAGE=mDRAW。 return 1。 } int moveDown(> { int i,j。 newY=curY-1。 clearOldBox(>。 if(collision(box>> { newY=curY。 putNewBox(>。 active=0。 MESSAGE=mLINE。 return 0。 } putNewBox(>。 actH=curH+1。 actY=newY。 curY=newY。 MESSAGE=mDRAW。 return 1。 } int rotate(> { int newBox[4][4]。 int i,j。 clearOldBox(>。 for(j=0。j<4。j++> for(i=0。i<4。i++> newBox[j][i]=0。 for(j=0。j<4。j++> for(i=0。i<4。i++> newBox[curW-i][j]=box[j][i]。 newW=curH。 newH=curW。 if(collisionRotate(newBox>> { newW=curW。 newH=curH。 newX=curX。 putNewBox(>。 MESSAGE=0。 return 0。 } for(j=0。j<4。j++> for(i=0。i<4。i++> box[j][i]=newBox[j][i]。 putNewBox(>。 actH=newH>curH? newH:curH。 actW=curX+actH-newX。 actX=newX。 actY=newY。 curX=newX。 curY=newY。 curW=newW。 curH=newH。 MESSAGE=mDRAW。 return 1。 } int getW(> { int i,j。 for(i=3。i>0。i--> for(j=0。j<4。j++> if(box[j][i]> return i。 return 0。 } int getH(> { int i,j。 。 newY=curY for(j=3。j>0。j--> for(i=0。i<4。i++> if(box[j][i]> return j。 return 0。 } void clearOldBox(> { int i,j。 for(j=0。j<=curH。 j++> for(i=0。i<=curW。 i++> if(box[j][i]> area[curY+j][curX+i]=0。 } void putNewBox(> { int i,j。 for(j=0。j<=newH。j++> for(i=0。i<=newW。i++> if(box[j][i]> area[newY+j][newX+i]=FORCOLOR。 } int collision(int cbox[][4]> { int i,j。 if(newX<0> return 1。 if(newX+newW>=MAXX> return 1。 if(newY<0> return 1。 for(j=0。j<=newH。j++> for(i=0。i<=newW。i++> if(area[newY+j][newX+i]&&cbox[j][i]> return 1。 return 0。 } int collisionRotate(int cbox[][4]> { int i,j。 if(newX+newW>=MAXX> newX=MAXX-1-newW。 if(newY+newH>=MAXY> newY=MAXY-1-newH。 if(collision(cbox>> return 1。 for(i=0。i<=newW。i++> for(j=0。j<=newH。j++> if(area[newY+j][newX+i]> { newX-=newW-i+1。 goto L。 } L: return collision(cbox>。 } int gameOver(> { if(!active &&(curY+curH>MAXY-3>> return 1。 else return 0。 } 1 ★★PC可乐吧系列教程之 C语言写的俄罗斯方块程序 大概在最近两天之内编码完成,但此前一天开始构思。第一天晚上主要完成了方块旋转算法,第二天也就是今天加了消方块的处理算法。但是可能还有一些考虑不周的地方,比如,没有采用定时中断,而是图方便采用了和cpu频率有关的delay<)函数来模拟时间间隔,这是需要改进的地方。 其中的主要逻辑有: <1)因为c的随机性函数不好,所以每次游戏开始根据bios时间设置种子。 <2)得分越高,方块下降速度越快<每200分为单位)。 <3)每下落一个方块加1分,每消除一行加10分,两行加30分,三行加70分,四行加150分。初试分数为100分。 游戏控制: up-旋转;空格-下落到底; 左右下方向键-控制方向。P-开始或暂停游戏。 ESC-退出。 特点: <1)因为tc不支持中文,所以基本都是英文注释。 <2)函数命名尽可能规范的表达其内部处理目的和过程。 <3)代码加上注释仅有577行。<我下载过的两个俄罗斯方块代码一个在1087行,一个在993行,我的比它们代码少)。 <4)除了消除空格时算法比较复杂,其他算法都比较简单易读。 <5)绘图效率和局部代码效率扔有待提高。 <6)FrameTime参数可能依据不同硬件环境进行具体设置,InitGame需要正确的TC路径。 俄罗斯方块源于大约9年前上大一时的一个梦,我们在学习c语言时,我的同寝室友邀请我合作一起完成俄罗斯方块<课外作业性质),但是当时限于我们的水平比较菜和学习状态比较懒散,我们没有完成。大一的时候我在机房里无意发现别人留下的俄罗斯方块程序,运行,老师发现后激动的问我是我写的吗,我惭愧的摇摇头。那时看到别人做c的大程序深感羡慕<自己只是写几十行的程序)。数年后我仍然看到有不同样式的实现,但是我一直没有实现它,知道今天忽然有这个想法去做,算是弥补多年前的遗憾和心愿吧。 -----------------------【以下是我的代码文件:】----------------------------------------------- /********************************/ /* Desc: 俄罗斯方块游戏 */ /* By: hoodlum1980 */ /* Email: */ /* Date: 2008.03.12 22:30 */ /********************************/ #include #include #define BoardWidth 12 #define BoardHeight 23 #define _INNER_HELPER /*inner helper method */ /*Scan Codes Define*/ enum KEYCODES { K_ESC =0x011b, K_UP =0x4800, /* upward arrow */ K_LEFT =0x4b00, K_DOWN =0x5000, K_RIGHT =0x4d00, K_SPACE =0x3920, K_P =0x1970 }。 /* the data structure of the block */ typedef struct tagBlock { char c[4][4]。 /* cell fill info array, 0-empty, 1-filled */ int x。 /* block position cx [ 0,BoardWidht -1] */ int y。 /* block position cy [-4,BoardHeight-1] */ char color。 /* block color */ char size。 /* block max size in width or height */ char name。 /* block name (the block's shape> */ } Block。 /* game's global info */ int FrameTime= 1300。 int CellSize= 18。 int BoardLeft= 30。 int BoardTop= 30。 /* next block grid */ int NBBoardLeft= 300。 int NBBoardTop= 30。 int NBCellSize= 10。 /* score board position */ int ScoreBoardLeft= 300。 int ScoreBoardTop=100。 int ScoreBoardWidth=200。 int ScoreBoardHeight=35。 int ScoreColor=LIGHTCYAN。 /* infor text postion */ int InfoLeft=300。 int InfoTop=200。 int InfoColor=YELLOW。 int BorderColor=DARKGRAY。 int BkGndColor=BLACK。 int GameRunning=true。 int TopLine=BoardHeight-1。 /* top empty line */ int TotalScore=100。 char info_score[20]。 char info_help[255]。 char info_common[255]。 /* our board, Board[x][y][0]-isFilled, Board[x][y][1]-fillColor */ unsigned char Board[BoardWidth][BoardHeight][2]。 char BufferCells[4][4]。 /* used to judge if can rotate block */ Block curBlock。 /* current moving block */ Block nextBlock。 /* next Block to appear */ /* function list */ int GetKeyCode(>。 int CanMove(int dx,int dy>。 int CanRotate(>。 int RotateBlock(Block *block>。 int MoveBlock(Block *block,int dx,int dy>。 void DrawBlock(Block *block,int,int,int>。 void EraseBlock(Block *block,int,int,int>。 void DisplayScore(>。 void DisplayInfo(char* text>。 void GenerateBlock(Block *block>。 void NextBlock(>。 void InitGame(>。 int PauseGame(>。 void QuitGame(>。 /*Get Key Code */ int GetKeyCode(> { int key=0。 if(bioskey(1>> { key=bioskey(0>。 } return key。 } /* display text! */ void DisplayInfo(char *text> { setcolor(BkGndColor>。 outtextxy(InfoLeft,InfoTop,info_common>。 strcpy(info_common,text>。 setcolor(InfoColor>。 outtextxy(InfoLeft,InfoTop,info_common>。 } /* create a new block by key number, * the block anchor to the top-left corner of 4*4 cells */ void _INNER_HELPER GenerateBlock(Block *block> { int key=(random(13>*random(17>+random(1000>+random(3000>>%7。 block->size=3。/* because most blocks' size=3 */ memset(block->c,0,16>。 switch(key> { case 0: block->name='T'。 block->color=RED。 block->c[1][0]=1。 block->c[1][1]=1, block->c[2][1]=1。 block->c[1][2]=1。 break。 case 1: block->name='L'。 block->color=YELLOW。 block->c[1][0]=1。 block->c[1][1]=1。 block->c[1][2]=1, block->c[2][2]=1。 break。 case 2: block->name='J'。 block->color=LIGHTGRAY。 block->c[1][0]=1。 block->c[1][1]=1。 block->c[1][2]=1, block->c[0][2]=1。 break。 case 3: block->name='z'。 block->color=CYAN。 block->c[0][0]=1, block->c[1][0]=1。 block->c[1][1]=1, block->c[2][1]=1。 break。 case 4: block->name='5'。 block->color=LIGHTBLUE。 block->c[1][0]=1, block->c[2][0]=1。 block->c[0][1]=1, block->c[1][1]=1。 break。 case 5: block->name='o'。 block->color=BLUE。 block->size=2。 block->c[0][0]=1, block->c[1][0]=1。 block->c[0][1]=1, block->c[1][1]=1。 break。 case 6: block->name='I'。 block->color=GREEN。 block->size=4。 block->c[1][0]=1。 block->c[1][1]=1。 block->c[1][2]=1。 block->c[1][3]=1。 break。 } } /* get next block! */ void NextBlock(> { /* copy the nextBlock to curBlock */ curBlock.size=nextBlock.size。 curBlock.color=nextBlock.color。 curBlock.x=(BoardWidth-4>/2。 curBlock.y=-curBlock.size。 memcpy(curBlock.c,nextBlock.c,16>。 /* generate nextBlock and show it */ EraseBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize>。 GenerateBlock(&nextBlock>。 nextBlock.x=1,nextBlock.y=0。 DrawBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize>。 } /* rotate the block, update the block struct data */ int _INNER_HELPER RotateCells(char c[4][4],char blockSize> { char temp,i,j。 switch(blockSize> { case 3: temp=c[0][0]。 c[0][0]=c[2][0], c[2][0]=c[2][2], c[2][2]=c[0][2], c[0][2]=temp。 temp=c[0][1]。 c[0][1]=c[1][0], c[1][0]=c[2][1], c[2][1]=c[1][2], c[1][2]=temp。 break。 case 4: /* only 'I' block arived here! */ c[1][0]=1-c[1][0], c[1][2]=1-c[1][2], c[1][3]=1-c[1][3]。 c[0][1]=1-c[0][1], c[2][1]=1-c[2][1], c[3][1]=1-c[3][1]。 break。 } } /* judge if the block can move toward the direction */ int CanMove(int dx,int dy> { int i,j,tempX,tempY。 for(i=0。i for(j=0。j if(curBlock.c[i][j]> { /* cannot move leftward or rightward */ tempX = curBlock.x + i + dx。 if(tempX<0 || tempX>(BoardWidth-1>> return false。 /* make sure x is valid! */ /* cannot move downward */ tempY = curBlock.y + j + dy。 if(tempY>(BoardHeight-1>> return false。 /* y is only checked lower bound, maybe negative!!!! */ /* the cell already filled, we must check Y's upper bound before check cell ! */ if(tempY>=0 && Board[tempX][tempY][0]> return false。 } } } return true。 } /* judge if the block can rotate */ int CanRotate(> { int i,j,tempX,tempY。 /* update buffer */ memcpy(BufferCells, curBlock.c, 16>。 RotateCells(BufferCells,curBlock.size>。 for(i=0。i for(j=0。j if(BufferCells[i][j]> { tempX=curBlock.x+i。 tempY=curBlock.y+j。 if(tempX<0 || tempX>(BoardWidth-1>> return false。 if(tempY>(BoardHeight-1>> return false。 if(tempY>=0 && Board[tempX][tempY][0]> return false。 } } } return true。 } /* draw the block */ void _INNER_HELPER DrawBlock(Block *block,int bdLeft,int bdTop,int cellSize> { int i,j。 setfillstyle(SOLID_FILL,block->color>。 for(i=0。i for(j=0。j if(block->c[i][j] && (block->y+j>>=0> { floodfill( bdLeft+cellSize*(i+block->x>+cellSize/2, bdTop+cellSize*(j+block->y>+cellSize/2, BorderColor>。 } } } } /* Rotate the block, if success, return true */ int RotateBlock(Block *block> { char temp,i,j。 int b_success。 if(curBlock.size==2> return。 if(( b_success=CanRotate(>>> { EraseBlock(block,BoardLeft,BoardTop,CellSize>。 memcpy(curBlock.c,BufferCells,16>。 DrawBlock(block,BoardLeft,BoardTop,CellSize>。 } return b_success。 } /* erase a block, only fill the filled cell with background color */ void _INNER_HELPER EraseBlock(Block *block,int bdLeft,int bdTop,int cellSize> { int i,j。 setfillstyle(SOLID_FILL,BkGndColor>。 for(i=0。i for(j=0。j if(block->c[i][j] && (block->y+j>=0>> { floodfill( bdLeft+cellSize*(i+block->x>+cellSize/2, bdTop+cellSize*(j+block->y>+cellSize/2, BorderColor>。 } } } } /* move by the direction if can, donothing if cannot * return value: true - success, false - cannot move toward this direction */ int MoveBlock(Block *block,int dx,int dy> { int b_canmove=CanMove(dx,dy>。 if(b_canmove> { EraseBlock(block,BoardLeft,BoardTop,CellSize>。 curBlock.x+=dx。 curBlock.y+=dy。 DrawBlock(block,BoardLeft,BoardTop,CellSize>。 } return b_canmove。 } /* drop the block to the bottom! */ int DropBlock(Block *block> { EraseBlock(block,BoardLeft,BoardTop,CellSize>。 while(CanMove(0,1>> { curBlock.y++。 } DrawBlock(block,BoardLeft,BoardTop,CellSize>。 return 0。/* return value is assign to the block's alive */ } /* init the graphics mode, draw the board grid */ void InitGame(> { int i,j,gdriver=DETECT,gmode。 struct time sysTime。 /* draw board cells */ memset(Board,0,BoardWidth*BoardHeight*2>。 memset(nextBlock.c,0,16>。 strcpy(info_help,\"P: Pause Game. --by hoodlum1980\">。 initgraph(&gdriver,&gmode,\"c:\\\c\\\\\">。 setcolor(BorderColor>。 for(i=0。i<=BoardWidth。i++> { line(BoardLeft+i*CellSize, BoardTop, BoardLeft+i*CellSize, BoardTop+ BoardHeight*CellSize>。 } for(i=0。i<=BoardHeight。i++> { line(BoardLeft, BoardTop+i*CellSize, BoardLeft+BoardWidth*CellSize, BoardTop+ i*CellSize>。 } /* draw board outer border rect */ rectangle(BoardLeft-CellSize/4, BoardTop-CellSize/4, BoardLeft+BoardWidth*CellSize+CellSize/4, BoardTop+BoardHeight*CellSize+CellSize/4>。 /* draw next block grids */ for(i=0。i<=4。i++> { line(NBBoardLeft+i*NBCellSize, NBBoardTop, NBBoardLeft+i*NBCellSize, NBBoardTop+4*NBCellSize>。 line(NBBoardLeft, NBBoardTop+i*NBCellSize, NBBoardLeft+4*NBCellSize, NBBoardTop+ i*NBCellSize>。 } /* draw score rect */ rectangle(ScoreBoardLeft,ScoreBoardTop,ScoreBoardLeft+ScoreBoardWidth,ScoreBoardTop+ScoreBoardHeight>。 DisplayScore(>。 /* set new seed! */ gettime(&sysTime>。 srand(sysTime.ti_hour*3600+sysTime.ti_min*60+sysTime.ti_sec>。 GenerateBlock(&nextBlock>。 NextBlock(>。 /* create first block */ setcolor(DARKGRAY>。 outtextxy(InfoLeft,InfoTop+20,\"Up -rotate Space-drop\">。 outtextxy(InfoLeft,InfoTop+35,\"Left-left Right-right\">。 outtextxy(InfoLeft,InfoTop+50,\"Esc -exit\">。 DisplayInfo(info_help>。 } /* set the isFilled and fillcolor data to the board */ void _INNER_HELPER FillBoardData(> { int i,j。 for(i=0。i for(j=0。j if(curBlock.c[i][j] && (curBlock.y+j>>=0> { Board[curBlock.x+i][curBlock.y+j][0]=1。 Board[curBlock.x+i][curBlock.y+j][1]=curBlock.color。 } } } } /* draw one line of the board */ void _INNER_HELPER PaintBoard(> { int i,j,fillcolor。 for(j=max((TopLine-4>,0>。j for(i=0。i fillcolor=Board[i][j][0]? Board[i][j][1]:BkGndColor。 setfillstyle(SOLID_FILL,fillcolor>。 floodfill(BoardLeft+i*CellSize+CellSize/2,BoardTop+j*CellSize+CellSize/2,BorderColor>。 } } } /* check if one line if filled full and increase the totalScore! */ void _INNER_HELPER CheckBoard(> { int i,j,k,score=10,sum=0,topy,lines=0。 /* we find the top empty line! */ j=topy=BoardHeight-1。 do { sum=0。 for(i=0。i< BoardWidth。 i++> { sum+=Board[i][topy][0]。 } topy--。 } while(sum>0 && topy>0>。 /* remove the full filled line (max remove lines count = 4> */ do { sum=0。 for(i=0。i< BoardWidth。 i++> sum+=Board[i][j][0]。 if(sum==BoardWidth>/* we find this line is full filled, remove it! */ { /* move the cells data down one line */ for(k=j。 k > topy。k--> { for(i=0。i Board[i][k][0]=Board[i][k-1][0]。 Board[i][k][1]=Board[i][k-1][1]。 } } /*make the top line empty! */ for(i=0。i Board[i][topy][0]=0。 Board[i][topy][1]=0。 } topy++。 /* move the topline downward one line! */ lines++。 /* lines <=4 */ TotalScore+=score。 score*=2。 /* adding: 10, 30, 70, 150 */ } else j--。 } while(sum>0 && j>topy && lines<4>。 /* speed up the game when score is high, minimum is 400 */ FrameTime=max(1200-100*(TotalScore/200>, 400>。 TopLine=topy。/* update the top line */ /* if no lines remove, only add 1: */ if(lines==0> TotalScore++。 } /* display the score */ void _INNER_HELPER DisplayScore(> { setcolor(BkGndColor>。 outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score>。 setcolor(ScoreColor>。 sprintf(info_score,\"Score: %d\。 outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score>。 } /* we call this function when a block is inactive. */ void UpdateBoard(> { FillBoardData(>。 CheckBoard(>。 PaintBoard(>。 DisplayScore(>。 } /* pause the game, and timer handler stop move down the block! */ int PauseGame(> { int key=0。 DisplayInfo(\"Press P to Start or Resume!\">。 while(key!=K_P && key!=K_ESC> { while(!(key=GetKeyCode(>>>{} } DisplayInfo(info_help>。 return key。 } /* quit the game and do cleaning work. */ void QuitGame(> { closegraph(>。 } /* the entry point function. */ void main(> { int i,flag=1,j,key=0,tick=0。 InitGame(>。 if(PauseGame(>==K_ESC> goto GameOver。 /* wait until a key pressed */ while(key!=K_ESC> { /* wait until a key pressed */ while(!(key=GetKeyCode(>>> { tick++。 if(tick>=FrameTime> { /* our block has dead! (can't move down>, we get next block */ if(!MoveBlock(&curBlock,0,1>> { UpdateBoard(>。 NextBlock(>。 if(!CanMove(0,1>> goto GameOver。 } tick=0。 } delay(100>。 } switch(key> { case K_LEFT: MoveBlock(&curBlock,-1,0>。 break。 case K_RIGHT: MoveBlock(&curBlock,1,0>。 break。 case K_DOWN: MoveBlock(&curBlock,0,1>。 break。 case K_UP: RotateBlock(&curBlock>。 break。 case K_SPACE: DropBlock(&curBlock>。 break。 case K_P: PauseGame(>。 break。 } } GameOver: DisplayInfo(\"GAME OVER! Press any key to exit!\">。 getch(>。 /* wait the user Press any key. */ QuitGame(>。 } 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- igat.cn 版权所有 赣ICP备2024042791号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务