Сегодня напишем в текстовом режиме с использованием прерываний BIOS и DOS змейку на Assembler. Для этого нужно знать основы, уметь ассемблировать (Tasm) и компоновать (Tlink) код.
Для начала напишем основу — змейку, которая перемещается в одном направлении по игровому полю. Змейка будет состоять из символа "*", координаты каждого символа хранятся в памяти.
model small
.data ;Сегмент данных. Храним координаты тела змейки
snake dw 0000h
dw 0001h
dw 0002h
dw 0003h
dw 0004h
dw 7CCh dup('?')
.stack 100h
.code
;В начале сегмента кода будем размещать процедуры
delay proc
push cx
mov ah,0
int 1Ah
add dx,3
mov bx,dx
repeat:
int 1Ah
cmp dx,bx
jl repeat
pop cx
ret
delay endp
start:
mov ax,@data
mov ds,ax
mov es,ax
mov ax,0003h
int 10h ;Очищаем игровое поле
mov cx,5
mov ax,0A2Ah
int 10h ;Выводим змейку из 5 символов "*"
mov si,8 ;Индекс координаты символа головы
xor di,di ;Индекс координаты символа хвоста
mov cx,0001h ;Регистр cx используем для управления головой. При сложении от значения cx будет изменяться координата x или y
main: ;Основной цикл
call delay
xor bh,bh
mov ax,[snake+si] ;Берем координату головы из памяти
add ax,cx ;Изменяем координату x
inc si
inc si
mov [snake+si],ax ;Заносим в память новую координату головы змеи
mov dx,ax
mov ax,0200h
int 10h ;Вызываем прерывание. Перемещаем курсор
mov ah,02h
mov dl,002Ah
int 21h ;Прерывание выводит символ '*'
mov ax,0200h
mov dx,[snake+di]
int 10h
mov ax,0200h
mov dl,0020h
int 21h ;Выводим пробел, тем самым удаляя хвост
inc di
inc di
jmp main
end start
Добавим процедуру «key_press» обработки нажатия клавиши и присваивания значения регистру CX, отвечающему за направление головы.
Управление стрелками.
key_press proc
mov ax, 0100h
int 16h
jz en ;Без нажатия выходим
xor ah, ah
int 16h
cmp ah, 50h
jne up
cmp cx,0FF00h ;Сравниваем чтобы не пойти на себя
je en
mov cx,0100h
jmp en
up: cmp ah,48h
jne left
cmp cx,0100h
je en
mov cx,0FF00h
jmp en
left: cmp ah,4Bh
jne right
cmp cx,0001h
je en
mov cx,0FFFFh
jmp en
right: cmp cx,0FFFFh
je en
mov cx,0001h
en:
ret
key_press endp
Вызовем её сразу после вызова процедуры delay:
main:
call delay
call key_press
Накормим змейку, создаём процедуру «add_food». Эта процедура будет на игровом поле размещать еду, символы "$". В качестве случайных чисел будем брать время.
add_food proc
sc:
inc bl ;В регистре BL рандомное число
cmp bx,50h ;Проверяем границу числа
jng ex
shr bl,1 ;Если больше, делим на 2 логическим сдвигом
jmp sc
ex:
mov dl,bl ;Запись координаты
sc2:
cmp bx,19h
jng ex2
shr bl,2
jmp sc2
ex2:
mov dh,bl ;Запись координаты
mov ax,0200h
int 10h
mov ax,0800h
int 10h
cmp al,2Ah ;Проверяем пустое ли место
je sc
cmp al,40h
je sc ;Если нет повторяем
mov ax,0200h
mov dl,0024h
int 21h
ret
add_food endp
Вызовем 1 раз в начале.
mov bl,51h
call add_food
main:
Делаем проверку, съела змея еду или нет. Если съела, вызываем процедуру «add_food» и не удаляем хвост.
Проверку добавляем в код перед выводом символа головы:
mov ah,02h
int 10h ;Вызываем прерывание. Перемещаем курсор
mov ax,0800h
int 10h ;Читает символ
mov dh,al
mov ah,02h
mov dl,002Ah
int 21h ;Прерывание выводит символ '*'
cmp dh,24h
jne next
call add_food
jmp main
next:
Усложним игру. После того, как питон съест 5 символов, в хвосте будет появляться символ "@". Пишем счетчик и вывод символа:
;В сегмент данных добавим строчку
.data
tick dw 0 ;Счетчик
--------------------------------------------------------------------
cmp dh,24h
jne next
push cx ;В стек регистр
mov cx,[tick]
inc cx
cmp cx,5
jne exl
xor cx,cx
mov ax,0200h
mov dx,[snake+di-2]
int 10h
mov ax,0200h
mov dl,0040h
int 21h
exl:mov [tick],cx
pop cx
call add_food
jmp main
next:
Какая игра без Game Over. Пишем процедуру проверки границы поля, а также врезание в себя и символ "@".
game_over proc
;Проверяем границы
cmp dl,50h
je exit
cmp dl,0
jl exit
cmp dh,0
jl exit
cmp dh,19h
je exit
;Проверяем символы
cmp al,2Ah
je exit
cmp al,40h
je exit
jmp good
exit:
mov ax,4c00h
int 21h
good:
ret
game_over endp
Вызываем её после считывания символа:
mov ax,0800h
int 10h ;Считываем символ
call game_over
mov dh,al
Немного магии добавляем после инкремента индексов.
inc si
inc si
cmp si,7CAh
jne nex
xor si,si
nex:
---------------------------------------------------------------------
inc di
inc di
cmp di,7CCh
jne main
xor di,di
Ну вот и всё, также можно добавить меню с выбором уровня, паузу, заставку Game Over, счет очков.
По ссылке архив с исходным кодом, exe'шником и DosBox для тех, у кого не запустится.
С прошедшим днём программиста!
Автор: