开题报告

项目介绍

贪吃蛇街机小游戏是一款在8*8的LED显示灯上运行的贪吃蛇小游戏,通过红外线遥控器输入设备进行游戏控制,在LED显示灯上显示游戏画面,使用数码管显示当前得分,使用灯光和蜂鸣器营造游戏氛围。

功能模块划分

  • 游戏整体逻辑控制模块

整个项目的入口,控制其他各个模块的调度。

  • 贪吃蛇逻辑控制模块

贪吃蛇运行逻辑的控制,负责计算出下一秒贪吃蛇的状态(移动、增长、死亡)、食物位置的刷新、当前得分的计算等。

  • LED显示控制模块

将内容(游戏菜单、当前画面、)显示到8*8的LED灯上。

  • 全局时钟控制模块

通过8253每10ms产生一个中断,用于控制游戏进程的同步。

  • 声音控制模块

使用蜂鸣器产生游戏音效与背景音乐。

  • 灯光控制模块

使用LED灯产生一些光效。

  • 数码管显示模块

使用数码管显示出当前游戏的得分。

  • 红外线输入模块

使用红外线输入,产生中断,控制贪吃蛇的运动。

核心功能代码测试

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
; LED显示
show_led proc
    push ax
    push bx
    push cx
    push dx

    ;写入方式控制字
    mov dx , 283h
    mov al , 80h
    out dx , al
    
    ;逐列刷新 红  si控制红行 di控制绿行
    mov si,offset red_buffer ;控制每一列的红8行
    mov di,offset green_buffer ;控制每一列的绿8行
    mov cl,10000000b ;第一列 颜色通过列线进行输出,281h输出则为第零列为红,282h输出则为第零列为绿 
again_show_led_col:
    ;红列  是控制哪一列是什么颜色的 红:281h 绿:282h 第0列为红色 
    mov al,cl
    mov dx,281h
    out dx,al
    ;每一列控制哪一行的红灯亮    这里有问题 对于控制行线来讲,若要红灯亮绿灯不亮则都不会亮(但是由于时间间隔很短,所以我在实验室的效果就是看起来不太亮)
    mov al,[si]                 ;所以这里必须解决红绿灯互相影响的问题
    add si,1                    ;因为时按列亮灯,共用列,所以不可能在一列中同时显示红灯和绿灯。
    mov dx,280h                 ;要不试试逐个点亮  
    out dx,al                   ;我觉得实验室器材不太好,必不能支持如此高频率的数据传送
                                ;所以贪吃蛇只能做到食物和蛇一个颜色,让食物闪烁吧。
    ;mov bx ,10000
    ;call delay
    ;绿列  
    ;mov al,cl
    ;mov dx,282h
    ;out dx,al
    ;每一列控制哪一行的绿灯亮
    ;mov al,[di]
    ;add di,1
    ;mov dx,280h    
    ;out dx,al

    ;显示完每一列进行delay 以bx为参数
    mov bx,10
    call delay

    ;关闭所有的列显示
    mov al,cl
    mov dx,281h
    out dx,al   
    ;mov dx,282h
    ;out dx,al

    shr cl,1    ;下一列
    cmp cl,0
    jnz again_show_led_col

show_led_end:
    pop dx
    pop cx
    pop bx
    pop ax
    ret
show_led endp
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
;运行贪吃蛇的程序   所有按键信息由中断进行扫描,程序只管从缓冲区中读取即可
snake_gluttony proc
    push ax
    push bx
    push cx
    push dx
;蛇的时间量,每经过100个全局时间量 加一,即蛇每1s移动一次 
snake_time word 0 
snake_gluttony_begin:
snake_count_time:
    mov ax,sync_time_buffer
    mov bl,100
    div bl      ;得到余数在ah中 商在al
    xor ah,ah
    cmp ax,[snake_time]     ;当前时间比之前的时间高
    ja snake_flush
    ;为防止因为溢出而造成的错误判断
    mov [snake_time],ax
    jmp snake_count_time
;snake的时间到了,可以刷新
snake_flush:
    ;ax中存放当前贪吃蛇时间,放入snake_time
    mov [snake_time],ax
    ;判断按键,进行贪吃蛇的逻辑操作  ;蛇的前近方向 3:上  0:下  2:左   1:右
    mov ax,keyboard_input_buffer
    ;处理键盘的W A S D  10-13位存放
    shr ax,10
    and al,00001111B
    cmp al,00001000B
    jz snake_fulsh_process_key_w
    cmp al,00000100B
    jz snake_fulsh_process_key_s
    cmp al,00000010B
    jz snake_fulsh_process_key_a
    cmp al,00000001B
    jz snake_fulsh_process_key_d

    ;没有任何按键按下则直接进行处理
    jmp snake_flush_process

;处理按键w
snake_fulsh_process_key_w:
    mov al,snake_direction
    cmp al,0    ;当前方向不为下时改变方向为上
    jz snake_flush_process
    mov snake_direction,3
    jmp snake_flush_process
;处理按键s
snake_fulsh_process_key_s:
    mov al,snake_direction
    cmp al,3    ;当前方向不为上时改变方向为下
    jz snake_flush_process
    mov snake_direction,0
    jmp snake_flush_process
;处理按键a
snake_fulsh_process_key_a:
    mov al,snake_direction
    cmp al,1    ;当前方向不为右时改变方向为左
    jz snake_flush_process
    mov snake_direction,2
    jmp snake_flush_process
;处理按键d
snake_fulsh_process_key_d:
    mov al,snake_direction
    cmp al,2    ;当前方向不为左时改变方向为右
    jz snake_flush_process
    mov snake_direction,1
    jmp snake_flush_process

;按键处理完了,处理贪吃蛇的位置
snake_flush_process:
    ;将按键信息清零
snake_flush_process_clear_key:
    mov ax,keyboard_input_buffer
    ;处理键盘的W A S D 都置为零
    and ax,1100001111111111B
    mov keyboard_input_buffer,ax

;位置刷新,根据上一次是否吃了食物决定身体更新策略
;若上一次刷新吃到了食物,则这一次蛇头变为蛇尾的一部分,然后蛇头向前走一步,若没有吃到,则从最后一节开始,每一节的位置时前一个的位置,第一个位置更新为蛇头的位置。
move_snake_body:
    ;每个位置需要两个字节
    mov si,offset snake_body_buffer 
    mov di,snake_body_length        ;其实有没有吃都从最后一节向前更新即可,无非是length的不同
    dec di          ;减一 方便指向每一节
    shl di,1    
    add di,si   ;指向最后一节 目标地址
    mov si,di
    sub si,2    ;源地址
;更新蛇的身体的每一节,第一节不更新
move_snake_body_every_section:
    ;跟新蛇的尾巴信息 si所指向的
    mov al,[si]
    mov snake_tail_position_x,al
    mov al,[si+1]
    mov snake_tail_position_y,al
    ;串传送的个数 (word)第一节不传送
    mov cx,snake_body_length
    dec cx              
    std         ;反向传送       
    rep movsw       

;更新第一节,将头的位置赋予即可
move_snake_body_first_section:
    ;高位存放纵坐标
    mov si,offset snake_body_buffer
    mov ah,snake_head_position_y
    mov al,snake_head_position_x
    mov [si],ax

    ;位置刷新,将贪吃蛇头朝对应方向移动一格
move_snake_head:
    mov al,snake_direction
    cmp al,3    ;上
    jz move_snake_head_up
    cmp al,0    ;下
    jz move_snake_head_down
    cmp al,2    ;左
    jz move_snake_head_left
    cmp al,1    ;右
    jz move_snake_head_right
    ;不可能哪个方向都不对
    ;jmp move_snake_head_direction_error

;上
move_snake_head_up:
    mov al,snake_head_position_y
    sub ax,1    
    jnc snake_judge_conflict
    mov ax,7    ;小于0,则从下面钻出来
    jmp snake_judge_conflict
;下
move_snake_head_down:
    mov al,snake_head_position_y
    add ax,1
    cmp ax,8    
    jnz snake_judge_conflict
    mov ax,0    ;等于8,超界,则从上面钻出来
    jmp snake_judge_conflict
;左
move_snake_head_left:
    mov al,snake_head_position_x
    sub ax,1    
    jnc snake_judge_conflict
    mov ax,7    ;小于0,则从下右面钻出来
    jmp snake_judge_conflict
;右
move_snake_head_right:
    mov al,snake_head_position_x
    add ax,1
    cmp ax,8    
    jnz snake_judge_conflict
    mov ax,0    ;等于8 ,则从左面钻出来
    jmp snake_judge_conflict

;判断是否冲突
snake_judge_conflict:
    ;首先判断是否蛇头和食物重合,若没有重合则蛇尾向前一步走,若重合则蛇尾不动,将蛇的身体信息全部向后移动一位
    ;清空上一次吃到食物的信息
    mov food_eaten,0
    mov ah,snake_head_position_x
    mov al,food_x
    cmp al,ah
    jnz snake_judge_conflict_not_eat
    mov ah,snake_head_position_y
    mov al,food_y
    cmp al,ah
    jnz snake_judge_conflict_not_eat
    ;下面时蛇吃了食物 
    mov food_eaten,1
    add snake_body_length,1
;生成新的食物 位置为(7-当前蛇头x,7-当前蛇尾y)
snake_create_new_food:
    mov ax,7
    mov bx,snake_head_position_x
    sub ax,bx
    mov food_x,al
    mov ax,7
    mov bx snake_tail_position_y
    sub ax,bx
    mov food_y,al

    
;蛇这一步没有吃到食物
snake_judge_conflict_not_eat:
    mov food_eaten,0

;在led点阵中点亮蛇阵 使用红色
snake_lighten_led_red:
    ;首先点亮食物
    ;写入红色灯亮,ah为行号,al为列号 注意这里 (0,0)在左下角    即ah为y al为x
    ;make_it_red proc
    mov ah,food_y
    mov al,food_x
    call make_it_red
    ;点亮头
    mov ah,snake_head_position_y
    mov al,snake_head_position_x
    call make_it_red
    ;点亮身体
    mov si,offset snake_body_buffer
    mov cx,snake_body_length
snake_lighten_led_red_body:
    mov al,[si]
    mov ah,[si+1]
    add si,2
    loop snake_lighten_led_red_body

    jmp snake_gluttony_begin

snake_gluttony_end:

    pop dx
    pop cx
    pop bx
    pop ax
    ret
snake_gluttony endp

任务分工

岳希航:贪吃蛇逻辑控制模块、LED显示模块、声音控制模块、数码管显示模块

崔文耀:游戏整体逻辑控制模块、全局时钟控制模块、灯光控制模块、红外线输入模块