Python на Assembler (Tasm)

в 8:15, , рубрики: game development, игры, Программирование

Сегодня напишем в текстовом режиме с использованием прерываний BIOS и DOS змейку на Assembler. Для этого нужно знать основы, уметь ассемблировать (Tasm) и компоновать (Tlink) код.

Для начала напишем основу — змейку, которая перемещается в одном направлении по игровому полю. Змейка будет состоять из символа "*", координаты каждого символа хранятся в памяти.

Python на Assembler (Tasm)

Посмотреть код

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, отвечающему за направление головы.

Управление стрелками.

Python на Assembler (Tasm)

key_press

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

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 символов, в хвосте будет появляться символ "@". Пишем счетчик и вывод символа:

Python на Assembler (Tasm)

shit

;В сегмент данных добавим строчку
.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

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

Немного магии добавляем после инкремента индексов.

magic

	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 для тех, у кого не запустится.

С прошедшим днём программиста!

Автор:

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js