Консультация № 179396
04.07.2010, 20:16
0.00 руб.
0 21 1
Уважаемые эксперты, подправьте, пожалуйста, программу, данную ниже. Она выводит на экран прямоугольник, который можно перемещать стрелками, а при нажатии на Пробел должна выводить три движущихся к верхнему края экрана спрайта, по достижении которого спрайты исчезают. У меня выводится только один спрайт, и он не двигается. Где-то ошибся я, а где не пойму. Вроде каждая из процедур по-отдельности работает нормально. Процедуры Draw proc и DrawSprite proc практически одинаковы, за исключением количества передаваемых параметров в стеке и нескольких команд привязки спрайтов к маске.


Приложение:
locals @@
.model tiny, C
N_MASK = 3 ; количество выводимых спрайтов

T_MASK STRUC ; положение спрайта и шаг смещения
x dw ?
y dw ?
dy dw ?
T_MASK ENDS

.code
.startup

mov ax, 0012h ;vga 640х480х16
int 10h

mov dx, 03CEh ;индексный порт графического контроллера
mov ax, 0F01h ;разрешение установки/сброса
out dx, ax

mov ax, 0a000h
mov es, ax
MainLoop:
call Draw,offset msk ;адрес прямоугольной маски

mov ah,1
int 16h
jz MainLoop
mov ah, 0
int 16h

cmp ah, 1 ;по Esc выходим
je Exit
cmp ah, 39h ;Пробел
je S
cmp ah, 4bh ;стрелка влево
je left
cmp ah, 4dh ;стрелка вправо
je right
cmp ah, 48h ;стрелка вверх
je up
cmp ah, 50h ;стрелка вниз
je down

jne MainLoop

left:
call Draw,offset black
sub column,1 ;шаг смещения
jmp MainLoop

right:
call Draw,offset black
add column,1 ;шаг смещения
jmp MainLoop

up:
call Draw,offset black
sub row,1 ;шаг смещения
jmp MainLoop

down:
call Draw,offset black
add row,1 ;шаг смещения
jmp MainLoop
S:
call Space ;вывод трёх спрайтов
jmp MainLoop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Exit:
mov ax, 0003h ;восстановим текстовый режим
int 10h

mov ax, 4c00h
int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Space proc
mov ax,offset msk1
call drawAll ; рисуем все спрайты
call DELAY

mov ax,offset black1
call drawAll ; стираем спрайты
call raise ; сдвигаем спрайты вверх
call Proverka
ret
Space endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Рисуем прямоугольную маску
.386
Draw proc maska:word
; вычислить номер байта в видеопамяти
mov ax, [row] ;AX = строка
mov bx, 80
mul bx ;AХ = АХ * 80

mov di, ax ;сохранить адрес начала строки в di
mov ax,[column]
mov cl, al
shr ax, 3 ;AX = номер байта в строке
add di, ax ;
and cl, 7 ;вычислить номер бита в байте

mov ch, 80h
shr ch, cl ;нужный бит установлен в 1
mov dx, 03CEh ;индексный порт графического контроллера

mov si,[maska]
mov bl,[si] ; число строк
inc si
mov cl,[si] ; число столбцов
inc si
@@next_row:
push di ; сохраняем смещение начала маски в видеобуфере
push cx

@@next_pixel:
mov ah, [si] ;цвет
mov al, 0 ;al = регистр установки/сброса
out dx, ax

mov al, 8 ; al = битовая маска
mov ah, ch
out dx, ax

xchg es:[di],ah ;заполнить регистры-защелки и вывести на экран пиксель

inc si ; к следующему байту маски
ror ch,1 ; маска для следующего пикселя
adc di,0 ; если был перенос, то к следующему байту видеобуфера

@@2:
dec cl
jnz @@next_pixel
pop cx ; восстанавливаем маску
pop di
add di,80 ; к следующей строке
dec bl
jnz @@next_row
ret
Draw endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

drawAll proc
mov cx,N_MASK
mov si,offset pos
@@draw:
push ax cx si
call DrawSprite, [si].x, [si].y, ax ; x, y - адрес маски ;в ax адрес offset msk1
pop si cx ax
add si,SIZE T_MASK
loop @@draw
ret
drawAll endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; сдвигаем спрайты вверх
raise proc
mov cx,N_MASK
mov si,offset pos
@@next:
mov ax,[si].dy ; шаг движения
sub [si].y,ax ;add новая позиция по вертикали
add si,SIZE T_MASK ;к следующей маске
loop @@next
ret
raise endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;Рисуем спрайты, привязывая их к прямоугольнику;;
.386
DrawSprite proc _x: word, _y: word, maska: word
;привязка спрайтов к зелёной линии маски прямоугольника
push ax
mov ax,column ;колонка маски прямоугольника
add ax,5 ;отсюда начинается зелёная линия в маске
mov _x,ax ;сохраним значение в переменной
xor ax,ax
mov ax,row ;строка маски прямоугольника
sub ax,10 ;откуда выводим спрайт, 10=высота спрайта
mov _y,ax ;сохраним
pop ax
; вычислить номер байта в видеопамяти
mov ax, [_y] ;AX = строка
mov bx, 80
mul bx ;AХ = АХ * 80

mov di, ax ;сохранить адрес начала строки в di
mov ax, [_x]
mov cl, al
shr ax, 3 ;AX = номер байта в строке
add di, ax
and cl, 7 ;вычислить номер бита в байте

mov ch, 80h
shr ch, cl ;нужный бит установлен в 1
mov dx, 03CEh ;индексный порт графического контроллера

mov si,[maska]
mov bl,[si] ; число строк
inc si
mov cl,[si] ; число столбцов
inc si
@@next_row:
push di ; сохраняем смещение начала маски в видеобуфере
push cx

@@next_pixel:
mov ah, [si] ;цвет
mov al, 0 ;al = регистр установки/сброса
out dx, ax

mov al, 8 ; al = битовая маска
mov ah, ch
out dx, ax

xchg es:[di],ah ;заполнить регистры-защелки и вывести на экран пиксель

inc si ; к следующему байту маски
ror ch,1 ; маска для следующего пикселя
adc di,0 ; если был перенос, то к следующему байту видеобуфера
dec cl
jnz @@next_pixel
pop cx ; восстанавливаем маску
pop di
add di,80 ; к следующей строке
dec bl
jnz @@next_row
ret
DrawSprite endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
time equ 30 ;число интервалов по 10мс
DELAY:
pusha ;сохраним все регистры
mov ah,2dh ;сбросим время
xor cx,cx
xor dx,dx
int 21h

dl2:
mov ah,2ch ; читаем время, GET SYSTEM TIME
int 21h ; Return: CH = hour, CL = minute, DH = second, DL = 1/100 seconds
;считаем сотни мс
mov al,100
mul dh ;секунды умножаем на 100 - ax = количество интервалов по 10мс
xor dh,dh ;dx - число сотых
xchg ax,dx ;поменяем местами
mov cl,10
div cl ;ax = количество интервалов по 10мс из сотых
add ax,dx ;складываем с количеством из секунд
cmp ax,time ;сравним с ожидаемым интервалом
jl dl2 ;ждем, если меньше
popa ;восстановим все регистры
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Proverka proc
mov cx,N_MASK
mov si,offset pos
xor ax,ax
@@next:
cmp [si].y,1
ja @@1
mov [si].y,470
@@1: cmp [si].x,630
jb @@2
mov [si].x,1
@@2:
cmp [si],ax
ja @@3
mov [si].x,630
@@3:
add si,SIZE T_MASK ; к следующей маске
loop @@next
ret
Proverka endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
column dw 320
row dw 240

Msk db 10, 16 ; размер маски в точках: строк, столбцов
db 9,9,9,9,9,10,10,10,10,10,10,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9

black db 10, 16 ; размер маски в точках: строк, столбцов
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

pos T_MASK <x,y,5>
T_MASK <x,y,5>
T_MASK <x,y,5>

Msk1 db 10, 6 ; размер маски в точках: строк, столбцов
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10

black1 db 10, 6 ; размер маски в точках: строк, столбцов
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
END

Обсуждение

Неизвестный
06.07.2010, 10:37
общий
У меня есть нижеприведённый код, очень удобный, и относительно несложный, но в нём нажатием на Пробел выводится один спрайт, а мне нужен вывод нескольких спрайтов. Скорость движения прямоугольника и спрайтов одинакова, а мне нужно, чтобы спрайт двигался хотя бы раза в 2 быстрее. При нажатии двух клавиш одновременно, спрайт выводится только в комбинации клавиш - стрелки вверх-вправо, остальные комбинации двух клавиш не срабатывают.
В программе, которая приведена выше в вопросе топика, используются два разных способа вывода на экран: один для маски прямоугольника, а другой с помощью структуры для вывода спрайтов. Совместить способы я пока не могу. Мне кажется, что первая программа предпочтительней для программ с небольшим количеством объектов, а вторая с большим количеством.

model tiny
.code
.186
;структура объекта
AirPlane struc
;свойства:
;координаты:
X dw ?;горизонталь
Y dw ?;вертикаль
;рисунок:
image dw ?;указатель на него
sz_X dw ?;размер горизонтальный
sz_Y dw ?;размер вертикальный
;считается один раз при рисовании
buffer dw ?;адрес видеобуфера для Show и Hide
;
;методы:
methodShow dw ?;п/п-мма рисования объекта
methodHide dw ?;п/п-мма стирания объекта
methodMove dw ?;п/п-мма перемещения объекта
AirPlane ends
;коды управляющих клавиш
keyESC equ 01h
keySpace equ 39h
keyUp equ 48h
keyDown equ 50h
keyLeft equ 4Bh
keyRight equ 4Dh
;
org 100h
begin: mov ax,13h
int 10h
;читаем старый и ставим свой обработчики
mov ax,3509h
int 21h
mov old09o,bx
mov old09s,es
mov ax,2509h
mov dx,offset new09
int 21h
;видео буфер
mov ax,0A000h
mov es,ax
isLoopGame:
;готовимся рисовать объекты
mov cx,sz_Object
mov bx,offset Interceptor
ShowLoop:
push cx
mov di,[bx].methodShow
call di
pop cx
add bx,sz_Plane
loop ShowLoop
;задержка
mov cx,5000
isWaitB: push cx
mov cx,5000
isWaitA: loop isWaitA
pop cx
loop isWaitB
;готовимся стирать объекты
mov cx,sz_Object
mov bx,offset Interceptor
HideLoop: push cx
mov di,[bx].methodHide
call di
pop cx
add bx,sz_Plane
loop HideLoop
;готовимся изменять координаты
mov cx,sz_Object
mov bx,offset Interceptor
MoveLoop:
push cx
mov di,[bx].methodMove
call di
pop cx
add bx,sz_Plane
loop MoveLoop
;проверяем пробел
cmp byte ptr DataKey[keySpace],1
jnz noSpace
;поиск свободного места для спрайта
mov cx,countMissile
mov di,offset isMissile
searchMissile: mov ax,offset Blank
cmp ax,[di].methodShow
jnz isNext
;загружаем новый объектыпрайт
call SetMissile
jmp noSpace
isNext: add di,sz_Plane
loop searchMissile
noSpace: cmp byte ptr DataKey[keyESC],1
jnz isLoopGame
;выход
mov ax,2509h
mov dx,old09o
mov bx,old09s
mov ds,bx
int 21h
Blank: ret
;тут сами объекты
Interceptor AirPlane <160,150,offset img_Interceptor,sz_Interceptor_H,sz_Interceptor_V,?,offset ShowPlane,offset HidePlane,offset MoveInterceptor>
sz_Plane equ $ - Interceptor

isMissile AirPlane <0,0,offset img_Missile,sz_Missile_H,sz_Missile_V,?,offset Blank,offset Blank,offset Blank>
AirPlane <0,0,offset img_Missile,sz_Missile_H,sz_Missile_V,?,offset Blank,offset Blank,offset Blank>
AirPlane <0,0,offset img_Missile,sz_Missile_H,sz_Missile_V,?,offset Blank,offset Blank,offset Blank>
AirPlane <0,0,offset img_Missile,sz_Missile_H,sz_Missile_V,?,offset Blank,offset Blank,offset Blank>
AirPlane <0,0,offset img_Missile,sz_Missile_H,sz_Missile_V,?,offset Blank,offset Blank,offset Blank>

sz_Object equ ($ - Interceptor)/sz_Plane
countMissile dw ($ - isMissile) / sz_Plane
;
;тут спрайт
img_Interceptor db 9,9,9,9,9,10,10,10,10,10,10,9,9,9,9,9
sz_Interceptor_H equ $ - img_Interceptor
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
db 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
sz_Interceptor_V equ ($ -img_Interceptor)/sz_Interceptor_H
;
img_Missile db 10,10,10,10,10,10
sz_Missile_H equ $ - img_Missile
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
sz_Missile_V equ ($ - img_Missile) / sz_Missile_H
;
;данные для обработчика клавиатуры
old09o dw ?
old09s dw ?
DataKey db 256 dup(0)
;обработчик контролера клавиатуры
new09: pusha
in al,60h
xor bx,bx
mov bl,al
mov al,1
mov cs:DataKey[bx],al
xor bl,80h
xor al,al
mov cs:DataKey[bx],al
in al,61h
push ax
or al,80h
out 61h,al
pop ax
out 61h,al
mov al,20h
out 20h,al
popa
iret
;считаем адрес вывода в буффер
CalcDi: mov ax,320
xor dx,dx
mul cx
add di,ax
ret
;открываем новый объект
SetMissile: mov bx,offset Interceptor
mov ax,[bx].X
add ax,5
mov [di].X,ax
mov ax,[bx].Y
;add ax,9
sub ax,10
mov [di].Y,ax
mov [di].methodShow,offset ShowPlane
mov [di].methodHide,offset HidePlane
mov [di].methodMove,offset MoveMissile
mov byte ptr DataKey[keySpace],0
ret
;берем данные с рисуемого объекта
ShowPlane: mov cx,[bx].Y ;считываем координаты на экране
mov di,[bx].X
call CalcDi ;считаем адрес в видеобуфере
mov [bx].buffer,di;запоминаем его
mov si,[bx].image;загружаем изображение
mov cx,[bx].sz_Y;загружаем его размер
mov dx,[bx].sz_X;
ShowSprayt: push cx
mov cx,dx
push di
;рисуем одну линию, не затирая уже нарисованное
ShowLine: lodsb
or al,al
jnz noZero
mov al,es:[di]
noZero: stosb
loop ShowLine
pop di
add di,320
pop cx
loop ShowSprayt
ret
;берем данные из объекта
HidePlane: mov di,[bx].buffer
mov cx,[bx].sz_Y
mov dx,[bx].sz_X
;стираем объект
HideSprayt: push cx
mov cx,dx
push di
xor ax,ax
rep stosb
pop di
add di,320
pop cx
loop HideSprayt
ret
;движение спрайта
MoveMissile: mov ax,[bx].Y
dec ax
jnz goNext
;закрываем объект
mov [bx].methodShow,offset Blank
mov [bx].methodHide,offset Blank
mov [bx].methodMove,offset Blank
goNext: mov [bx].Y,ax
ret
MoveInterceptor: xor cx,cx
xor dx,dx
add dl,byte ptr DataKey[keyDown]
add cl,byte ptr DataKey[keyRight]
sub dl,byte ptr DataKey[keyUp]
sub cl,byte ptr DataKey[keyLeft]
;контроль координат
mov di,320
sub di,[bx].sz_X
mov ax,[bx].X
xchg ax,cx
cbw
add ax,cx
jz noSaveX
cmp ax,di
jae noSaveX
mov [bx].X,ax
noSaveX: mov di,200
sub di,[bx].sz_Y
mov ax,[bx].Y
xchg ax,dx
cbw
add ax,dx
jz noSaveY
cmp ax,di
jae noSaveY
mov [bx].Y,ax
noSaveY: ret
end begin
давно
Старший Модератор
31795
6196
06.07.2010, 17:50
общий
Adsorores:
Цитата: 289969
но в нём нажатием на Пробел выводится один спрайт, а мне нужен вывод нескольких спрайтов.

А кто Вам мешает организовать сразу три спрайта? К примеру так:
Код:
SetMissile:	mov	cx,3
mov bx,offset Interceptor
nextMissile: mov ax,[bx].X
add ax,5
mov [di].X,ax
mov ax,[bx].Y
add ax,9
mov [di].Y,ax
mov [di].methodShow,offset ShowPlane
mov [di].methodHide,offset HidePlane
mov [di].methodMove,offset MoveMissile
mov bx,di
add di,sz_Plane
loop NextMissile
mov byte ptr DataKey[keySpace],0
ret

Создаются три спрайта смещенные относительно друга на 5:9 позиций.

Цитата: 289969
Скорость движения прямоугольника и спрайтов одинакова, а мне нужно, чтобы спрайт двигался хотя бы раза в 2 быстрее.

Аналогичный вопрос? Что мешает перемещать спрайты, как Вам нужно?
Код:
MoveMissile:	mov	ax,[bx].Y
dec ax; -1
jz goStop
dec ax;-1=-2
jnz goNext
;закрываем объект
goStop: mov [bx].methodShow,offset Blank
mov [bx].methodHide,offset Blank
mov [bx].methodMove,offset Blank
goNext: mov [bx].Y,ax
ret



Цитата: 289969
У меня выводится только один спрайт, и он не двигается. Где-то ошибся я, а где не пойму.

Вот участок Вашего кода:
Код:
locals	@@
.model tiny, C
N_MASK = 3 ; количество выводимых спрайтов

T_MASK STRUC ; положение спрайта и шаг смещения
x dw ?
y dw ?
dy dw ?
T_MASK ENDS
. . .
cmp ah, 1 ;по Esc выходим
je Exit
cmp ah, 39h ;Пробел
je S
. . .
S:
call Space ;вывод трёх спрайтов
jmp MainLoop
. . .
Space proc
mov ax,offset msk1
call drawAll ; рисуем все спрайты
call DELAY
mov ax,offset black1
call drawAll ; стираем спрайты
call raise ; сдвигаем спрайты вверх
call Proverka
ret
Space endp
. . .
drawAll proc
mov cx,N_MASK
mov si,offset pos
@@draw:
push ax cx si
call DrawSprite, [si].x, [si].y, ax ; x, y - адрес маски ;в ax адрес offset msk1
pop si cx ax
add si,SIZE T_MASK
loop @@draw
ret
drawAll endp
. . .
; сдвигаем спрайты вверх
raise proc
mov cx,N_MASK
mov si,offset pos
@@next:
mov ax,[si].dy ; шаг движения
sub [si].y,ax ;add новая позиция по вертикали
add si,SIZE T_MASK ;к следующей маске
loop @@next
ret
raise endp
. . .
.data
. . .
pos T_MASK <x,y,5>
T_MASK <x,y,5>
T_MASK <x,y,5>

Смотрим, что там:
1) нажата клавиша Space;
2) вызывается одноименная подрограмма Space;
3) вызывается подпрограмма drawAll;
4) настраиваемся на объекты : mov si,offset pos
5) вызываете DrawSprite, [ si ].x, [ si ].y, ax
Вот собственно и всё, т.к., чему равны [ si ].x и [ si ].y в коде нет определения, так же как и присваивания им новых значений, зависящих от нажатия клавиши Space и положения основного спрайта.

Но за Вас постарался компилятор:
Код:
seg000:044C aControl        db 'control',0
seg000:0454 dw 0
seg000:0456 dw 2
seg000:0458 dw 5
seg000:045A dw 0
seg000:045C dw 2
seg000:045E dw 5
seg000:0460 dw 0
seg000:0462 dw 2
seg000:0464 dw 5
seg000:0466 aControl_0 db 'control',0

Он подставил смещения переменнных в структуре T_MASK<x,y,5>.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
12.07.2010, 11:55
общий
это ответ
Здравствуйте, Adsorores.

Смотрите приложение.
Вопросы задавайте в мини-форум.
Удачи!

Приложение:
locals @@
.model tiny, C
OBJ_MASK struc
next dw ?;указатель на следующий объект
;координаты
x dw ?;горизонталь
y dw ?;вертикаль
;прирощение координат
d_x dw ?;горизонталь
d_y dw ?;вертикаль
;информация
img dw ?;изображение
img_x dw ?;горизонталь
img_y dw ?;вертикаль
img_z dw ?;адрес в памяти видеобуфера
;методы обработки
method_A dw ?;первый метод
method_B dw ?;второй метод
method_C dw ?;третий метод
OBJ_MASK ends
.code
.startup
.186
keyE equ 1
mov ax,12h;vga 640х480х16
int 10h
;свой обработчик
mov ax,3509h
int 21h
mov old09o,bx
mov old09s,es
mov ax,2509h
mov dx,offset new09
int 21h
;открываем порт
mov dx, 03CEh;индексный порт графического контроллера
mov ax, 0F01h;разрешение установки/сброса
out dx, ax
;настраиваесмся на вывод
mov ax, 0a000h
mov es, ax
;основной цикл праограммы
mov bx,offset obj_A
MainLoop: CALL Main_Loop , method_A
CALL Dalay
CALL Main_Loop , method_B
CALL CheckKey
CALL Main_Loop , method_C
cmp byte ptr DataKey[KeyE] , 1
jnz MainLoop
;востанавливаем страрый обработчик
mov dx,old09o
mov ds,old09s
mov ax,2509h
int 21h
;выходим в ДОС
mov ax, 0003h
int 10h
mov ax, 4c00h
int 21h
;
;обработчик прерывания клавиатуры
; :-)
old09o dw ?
old09s dw ?
DataKey db 256 dup (0)
New09: pusha
xor bx,bx
in al,60h
mov bl,al
mov byte ptr DataKey[ bx ],1
xor bl,80h
mov byte ptr DataKey[ bx ],0
in al,61h
push ax
or al,80h
out 61h,al
pop ax
out 61h,al
mov al,20h
out 20h,al
popa
iret
;
;подпроаграмма организации просмотра списка объектов в системе
Main_Loop proc CallProc:word
push bx
;цикл просмотра
Loop_Main: mov si , CallProc
mov si, [bx + si]
call si
mov bx , [ bx ].next
or bx , bx
jnz Loop_Main
pop bx
ret
Main_Loop endp
;объект номер 1
obj_A Obj_Mask <offset obj_B,100,200,0,0,offset img_A,sz_img_A_x,sz_img_A_y,?,offset Show,offset Hide,offset Move>
;объект номер 2
obj_B Obj_Mask <offset obj_C,100,200, 0,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;объект номер 5
obj_E Obj_Mask <offset obj_F,100,200, 0,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;объект номер 8
obj_H Obj_Mask <offset obj_I,100,200,0,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;объект номер 3
obj_C Obj_Mask <offset obj_D,100,200,-1,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;объект номер 6
obj_F Obj_Mask <offset obj_G,100,200,-1,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;объект номер 9
obj_I Obj_Mask <offset obj_J,100,200,-1,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;объект номер 4
obj_D Obj_Mask <offset obj_E ,100,200, 1,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;объект номер 7
obj_G Obj_Mask <offset obj_H ,100,200, 1,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;объект номер 10
obj_J Obj_Mask < 0 ,100,200,1,-2,offset img_B,sz_img_B_x,sz_img_B_y,?,offset Blank,offset Blank,offset Blank>
;
;подпрограмма задержки отбражения объектов на экране
Dalay proc
const_Wait_A equ 5000
const_Wait_B equ 20000
mov cx , const_Wait_A
Loop_A: push cx
mov cx , const_Wait_B
Loop_B: loop Loop_B
pop cx
loop Loop_A
ret
Dalay endp
;
;основной объект
img_A db 09,09,09,09,09,10,10,10,10,10,10,09,09,09,09,09
sz_img_A_x equ $ - img_A
;короткая запись для данного спрайта
db 9 dup (sz_img_A_x dup(09))
comment ~
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;1
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;2
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;3
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;4
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;5
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;6
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;7
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;8
db 09,09,09,09,09,09,09,09,09,09,09,09,09,09,09,09;9
~
sz_img_A_y equ ($ - img_A) / sz_img_A_x
;
;спрайт клавиши "пробел"
img_B db 10,10,10,10,10,10
sz_img_B_x equ $ - img_B
;короткая запись для данного спрайта
db 9 dup(sz_img_B_x dup(10))
comment ~
db 10,10,10,10,10,10;1
db 10,10,10,10,10,10;2
db 10,10,10,10,10,10;3
db 10,10,10,10,10,10;4
db 10,10,10,10,10,10;5
db 10,10,10,10,10,10;6
db 10,10,10,10,10,10;7
db 10,10,10,10,10,10;8
db 10,10,10,10,10,10;9
~
sz_img_B_y equ ($ - img_B) / sz_img_B_x
;
;подпрограмма контроля выхода за пределы экрана
Move proc
max_x equ 500
max_y equ 400
call Control , y , [ bx ].d_y , max_y
call Control , x , [ bx ].d_x , max_x
ret
Move endp
;
;подпрограмма контроля положения на экране
Control proc dataPoint:word , dataPlus:word , Maximum:word
mov di , dataPoint
mov ax , [ bx + di ]
add ax , dataPlus
jz @@A
cmp ax , Maximum
ja @@A
;в пределах экрана записываем новое значение координаты
mov [ bx + di ],ax
ret
;вышли за пределы экрана
;проверяем первый объект, да - пропускаем
@@A: mov ax,offset img_A
cmp ax,[ bx ].img
jz @@B
;закрываем объект
mov [ bx ].method_A , offset Blank
mov [ bx ].method_B , offset Blank
mov [ bx ].method_C , offset Blank
@@B: ret
Control endp
;
;подпрограмма заглушка закрывающая объекты
Blank proc
ret
Blank endp
;
;контроль нажатых клавиш
CheckKey proc
KeyS equ 39h;
KeyU equ 48h;
KeyD equ 50h;
KeyR equ 4Dh;
KeyL equ 4BH;
;начинаем проверку направления движения основного спрайта
call CheckDirect , d_x , KeyL , KeyR
call CheckDirect , d_y , KeyU , KeyD
;проверяем кнопку пуск
cmp byte ptr DataKey [ KeyS ] , 1
jnz @@C
;нажата - создаем объекты
Call SetObject , [ bx ].x , [ bx ].y
;закрываем нажатие
@@C: mov byte ptr DataKey [ KeyS ] , 0
ret
CheckKey endp
;
;контроль направления движения
CheckDirect proc dd_a:word , key_one:word , key_two:word
xor ax , ax
;смещение в массивах
mov si , key_one
mov di , key_two
;считаем смещение напралвения движения
sub al , DataKey [ si ]
add al , DataKey [ di ]
;разширяем до слова
cbw
;записываем текущее направление
mov si , dd_a
mov [ bx + si ] , ax
ret
CheckDirect endp
;
;подпрограмма инициализации трех объектов
SetObject proc c_x:word , c_y:word
push bx
;готовимся к циклу открытия спрайтов
mov cx , 3
mov di , c_x
mov si , c_y
mov ax , offset Blank
;проверяем окончание наличия слотов спрайта
@@XX: mov bx , [ bx ].next
or bx , bx
jz @@YY
;прорускаем занятый слот спрайта
@@ZZ: cmp ax , [ bx ].method_A
jnz @@XX
;То, чего у Вас нет :-)
;присваиваем новые координаты
mov [ bx ].x , di
mov [ bx ].y , si
;устанавливаем методы обработки
mov [ bx ].method_A , offset Show
mov [ bx ].method_B , offset Hide
mov [ bx ].method_C , offset Move
loop @@XX
@@YY: pop bx
ret
SetObject endp
;
;подпрограмма стирания спрайта на экране
Hide proc
call Draw , [ bx ].x , 0 , [ bx ].img_x, [ bx ].img_y , [ bx ].img_z
ret
Hide endp
;
;подпрограмма рисования спрайта на экране
Show proc
;общие вычисления для рисования-стирания
mov ax , [ bx ].y
mov cx , 80
xor dx , dx
mul cx
mov cx , [ bx ].x
shr cx , 3
add ax , cx
mov [ bx ].img_z , ax
call Draw , [ bx ].x , [ bx ].img , [ bx ].img_x , [ bx ].img_y , [ bx ].img_z
ret
Show endp
;
;подпрограмма рисования-стирания спрайта
Draw proc yy:word , images:word , szImageX:word , szImageY: word , buffer:word
push bx
mov cx , yy
and cl , 7
mov ax , 8008h
shr ah , cl
mov dx , 03CEh
mov si , images
mov di , buffer
;
@@AA: push di
push ax
mov bx , szImageX
;
@@BB: push ax
xor ax , ax
or si , si
jz @@CC
mov ah , [ si ]
inc si
;выводим бит на экран
@@CC: out dx , ax
pop ax
push ax
out dx , ax
xchg es: [ di ] , al
;следующий бит
pop ax
ror ah , 1
adc di , 0
dec bx
jnz @@BB
;следующая строка
pop ax
pop di
add di , 80
dec szImageY
jnz @@AA
pop bx
ret
Draw endp
END
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
12.07.2010, 12:35
общий
Adsorores:
Цитата: 289969
В программе, которая приведена выше в вопросе топика, используются два разных способа вывода на экран: один для маски прямоугольника, а другой с помощью структуры для вывода спрайтов. Совместить способы я пока не могу. Мне кажется, что первая программа предпочтительней для программ с небольшим количеством объектов, а вторая с большим количеством.

Количество объектов для программы не имеет значения. Важен подход к программированию. В моем ответе, вся информация об отображаемых объектах хранится в одинаковых структурах. Это позволяет для вывода-стирания-перемещения использовать одинаковые процедуры. Ещё обратите внимание на то как хранится информация об объектах, последовательность самих объектов перемешана. Такой подход ближе к современному программированию. к примеру возникает любое событие(нажата клавиша "Пробел"), программа обработала его, запросила память у системы, для храниения информации об создаваемом объекте, заполняет нужными значениями и записывает указатель на этот участок памяти в очередь отображаемых объетов. После того, как объект отработает свою задачу (долетит до врехненго края экрана), он будет убран из очереди и память занимаемая им, освобождена.
Приблизительно так.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
15.07.2010, 15:14
общий
У меня спрайты при нажатии на Пробел выводятся только при движении прямоугольника (нажаты 2 клавиши) «верх-право», а как заставить выводиться спрайты при нажатии «верх-лево», «вниз-влево», «вниз-право»? В чём причина, разобраться не могу.
Обратил внимание, на различных компьютерах скорость передвижения и даже угол перемещения прямоугольника при нажатии 2 клавиш одновременно очень различны.
"Важен подход к программированию" - согласен, потому я и хотел в одной программе совместить 2 разных способа, в первую очередь, для лучшего уяснения, так сказать, в самообразовательных целях, чтобы можно было увидеть разницу между одним и другим в одной программе. А совместить оба способа вовсе не так просто, хотя по-отдельности и знаю вывод каждым способом, но вместе - нет.
давно
Старший Модератор
31795
6196
15.07.2010, 16:39
общий
Adsorores:
Цитата: 289969
выводятся только при движении прямоугольника (нажаты 2 клавиши) «верх-право», а как заставить выводиться спрайты при нажатии «верх-лево», «вниз-влево», «вниз-право»?

У меня не работает только «верх-лево», возможно, это из-за того, что различные РС, сейчас у меня под рукой только - система:ХР3, процессор: Р4 - 2,4Г, сборка: НР. Проверить на другой ОСи и железе не могу, хотя раньше похожий код работал на WMe.
Можно ещё проверить и чистом BIOS, загрузившись с дискеты, в режиме авто загрузки, но я не уверен, что современные видеокарты работают в старых видеорежимах.

Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
17.07.2010, 15:07
общий
Зенченко Константин Николаевич:
А как это в "чистом BIOS"? Записать программу на дискету и выбрать в БИОСе загрузку с floppy с этой программой? Но в программе есть прерывание int21h, которое не БИОСное. Будет ли работать?
давно
Старший Модератор
31795
6196
17.07.2010, 20:15
общий
Adsorores:
1 - ?
2 - ДА.
3-
Код:
mov ax,2509h
int 21h

Вы об этом, но разговор уже был о том как заменить данные в таблице векторов прерываний без использования DOS'a.
4 - Должно работать,
Цитата: Зенченко Константин Николаевич
но я не уверен, что современные видеокарты работают в старых видеорежимах.

Моя старая видеокарта это позволяла делать (РIII - 800Ghz, MB-Compaq, VIDEO-built-in), сейчас не знаю, возможно, т.к. проверял под WXP, а она основные режимы эммулирует.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
18.07.2010, 13:50
общий
Зенченко Константин Николаевич:
Пробовал грузиться с дискеты - не получается. Предварительно заменил данные в таблице векторов прерываний без использования DOS'a.
xor ax, ax
mov es, ax
; читаем старый обработчик
mov ax, es:[4*9]
mov old09o, ax
mov ax, es:[4*9+2]
mov old09s, ax
; ставим новый обработчик (запрет прерываний - обязательно!)
cli
mov word ptr es:[4*9], offset new09
mov es:[4*9+2], cs
sti
С HDD программа нормально запускается, а с загрузки с дискеты не получается. Пишется стандартное сообщение: Remove disks or other media. Press aty key to restart. Может, это из-за команд выхода в DOS, там тоже int 21h и int 20h есть, хотя, по идее, выход в DOS же не нужен. Может, выходить только перезагрузкой с последующей загрузкой с HDD или выключением питания.
давно
Старший Модератор
31795
6196
19.07.2010, 10:59
общий
Adsorores:
При загрузке с дискеты, первой должна быть загрузочная дискета с ОС, а после этого сама программа.
Возможно ещё код программы переделать под автоматический запуск с дискеты.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
20.07.2010, 08:15
общий
Зенченко Константин Николаевич:
Получилось! Выбрал Форматировать - Создание загрузочного диска MS-DOS, потом записал программу, которая и запустилась. Только почему-то нельзя посмотреть содержимое диска C: и расчитан этот загрузочный диск на работу с картами EGA.
давно
Старший Модератор
31795
6196
20.07.2010, 18:53
общий
Adsorores:
Цитата: 289969
расчитан этот загрузочный диск на работу с картами EGA

Основное назначение дискеты - аварийное востановление системы после сбоя, а для этого особая графика не нужна
Цитата: 289969
Только почему-то нельзя посмотреть содержимое диска C:

Скореев всего у Вас диск отформатирован под NTFS, для просмотра нужны специальные драйвера
Цитата: из следующего Вашего вопроса
взятый с дискеты к книге Кулакова

В этой книге есть содержимое загрузочной дискеты для работы с описаными программами.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
21.07.2010, 13:10
общий
Зенченко Константин Николаевич:
Да, под NTFS отформатировано. Скачал Paragon ntfs for dos. Всё получилось.
"В этой книге есть содержимое загрузочной дискеты для работы с описаными программами" - Вы имеете в виду вот это: Disk for Book\SYSTEM\DOS_6_22. Там 2 файла AUTOEXEC.BAT и CONFIG.SYS. И 2 драйвера ещё, находящихся в Disk for Book\VESA_DRV\ATI_TECH, у меня карта ATI.
давно
Старший Модератор
31795
6196
21.07.2010, 14:29
общий
Adsorores:
Сожалею, но прилагаемая дискета у меня не сохранилась, что там есть не знаю.
В главе "Введение" есть список файлов, которые должны быть на загрузочной дискете.

ХР - формирует только краткий список нужных файлов, но для единичного запуска программы в чистом ДОСе достаточно.

Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
22.07.2010, 11:01
общий
Зенченко Константин Николаевич:
Разобрался. На прилагаемой к книге дискете этих фалов нет. Их нужно скачать из директории C:\DOS или C:\WINDOWS\COMMAND в зависимости от установленной ОС. Во время написания книги Windows ХР не было, потому и директорий таких там нет. Нужно копировать эти файлы с загрузочного диска Windows9х.
По адресу Disk for Book\SYSTEM\DOS_6_22 находятся прототипы системных файлов для загрузочного диска - AUTOEXEC.BAT и CONFIG.SYS, которые нужно скопировать на дискету.
Неизвестный
22.07.2010, 11:02
общий
Зенченко Константин Николаевич:
«чему равны [ si ].x и [ si ].y в коде нет определения, так же как и присваивания им новых значений, зависящих от нажатия клавиши Space и положения основного спрайта.»

Я заменил call DrawSprite, [si].x, [si].y, ax на call DrawSprite, column, row, ax,
где column dw 320, row dw 240. Изменил и написание переменных структуры с
pos T_MASK <x,y,5>
на
pos T_MASK <column,row,5>
всё равно спрайты не двигаются. На вывод одного спрайта сделал, но и он не перемещается. У меня проблема не в привязке, а в движении спрайта структуры, т.е в dy, а dy определён явно, т.е. 5. Чего он двигаться не хочет – непонятно. Вот здесь он должен, по идее, двигаться:
@@next:
mov ax,[si].dy
sub [si].y,ax
а он не двигается. Из [si].y, т.е. row – номера строки, вычитается 5 строк – вроде всё правильно же.
давно
Старший Модератор
31795
6196
24.07.2010, 05:02
общий
Adsorores:
Давайте начнем сначала.
Код:
locals	@@
.model tiny, C
N_MASK = 3 ; количество выводимых спрайтов

T_MASK STRUC ; положение спрайта и шаг смещения
x dw ?
y dw ?
dy dw ?
T_MASK ENDS
. . .
cmp ah, 1 ;по Esc выходим
je Exit
cmp ah, 39h ;Пробел
je S
. . .
S:
call Space ;вывод трёх спрайтов
jmp MainLoop

. . .
Space proc
mov ax,offset msk1
call drawAll ; рисуем все спрайты
call DELAY
mov ax,offset black1
call drawAll ; стираем спрайты
call raise ; сдвигаем спрайты вверх
call Proverka
ret
Space endp
. . .
drawAll proc
mov cx,N_MASK
mov si,offset pos
@@draw:
push ax cx si
call DrawSprite, [si].x, [si].y, ax ; x, y - адрес маски ;в ax адрес offset msk1
pop si cx ax
add si,SIZE T_MASK
loop @@draw
ret
drawAll endp
. . .
; сдвигаем спрайты вверх
raise proc
mov cx,N_MASK
mov si,offset pos
@@next:
mov ax,[si].dy ; шаг движения
sub [si].y,ax ;add новая позиция по вертикали
add si,SIZE T_MASK ;к следующей маске
loop @@next
ret
raise endp
. . .
.data
. . .
pos T_MASK <x,y,5>
T_MASK <x,y,5>
T_MASK <x,y,5>

Рисованием спрайтов у Вас занимается процедура Space - правильно?
Когда она получает управление? Только тогда, когда нажата клавиша "Пробел", т.к. дополнительного перехода на метку S нет - правильно?
Цитата: 289969
Я заменил

Компилятор подставляет смещение относительно начала сегмента(обратите внимание, какие значения). Изменений нет.
Код:
seg000:044C aControl        db 'control',0
seg000:0454 dw 304h
seg000:0456 dw 306h
seg000:0458 dw 5
seg000:045A dw 304h
seg000:045C dw 306h
seg000:045E dw 5
seg000:0460 dw 304h
seg000:0462 dw 306h
seg000:0464 dw 5
seg000:0466 aControl_0 db 'control',0

Найдите этот участок кода в программе:
Код:
seg000:02FE loc_2FE:                                ; CODE XREF: sub_2D3+23j
seg000:02FE add si, 6
seg000:0301 loop loc_2DB
seg000:0303 retn
seg000:0303 sub_2D3 endp
seg000:0303
seg000:0303 ; ---------------------------------------------------------------------------
seg000:0304 word_304 dw 140h ; DATA XREF: start+5Bw
seg000:0304 ; start+72w ...
seg000:0306 word_306 dw 0F0h ; DATA XREF: start+89w
seg000:0306 ; start+A0w ...


Я Вам писал, что:
Цитата: Зенченко Константин Николаевич
После пуска все ракеты живут самостоятельно, внезависимости от положения истребителя.

Пуск, это только нажатие клавиши "пробел", т.е. спрайты, должны только инициализироватся, ещё раз т.е. становится доступными для отображения на экране. Отображением и стиранием занимаются другие подпрограммы. В моём коде бланкированием(не выводом закрытого объекта) занимается
Код:
Blank	proc
ret
Blank endp

В другом коде, признаком закрытого объекта, был NULL вместо адреса изображения.

Простите, ещё раз повторяю в коде ДОЛЖНО БЫТЬ:
клавиша Space -> инициализация -> [ si ].x=[ column ], [ si ].y=[ row ](сразу скажу, нужны значения переменных, а не смещения на эти переменные), а дальше уже вывод спрайта, внезависимости, от того нажата клавиша Space или нет, т.е. самостоятельность, этого у Вас нет. Нет самостоятельного цикла на вывод спрайтов. Попробуйте нарисовать блок-схему самой программы (своей и моей) и прогнать на листочке, что, как и после чего выполняется.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
25.07.2010, 18:49
общий
Зенченко Константин Николаевич:
Я уже понял, что у меня спрайты накладываются друг на друга, выводятся в одно место и не двигаются. Я хотел спрайты по такому же шаблону выводить, как и amnick в ответе на мой вопрос № 179122, несколько переделав его вывод не сразу 7 спрайтов с разных мест, а по одному спрайту и с определённого места. Наверное, не получится по его способу сделать.
"нужны значения переменных, а не смещения на эти переменные" - это понятно, но как это сделать! Просто так любые значения переменных подставить не получится, спрайты будут выводиться с другого места, а не с нужного, тем более что нужное место подвижно. Всё равно придётся спрайты привязывать к координатам прямоугольника через offset. Попробую сделать, как у Вас в AirPlane < 0, 0, offset img, ...>, где 0, 0 - координаты спрайта, предварительно привязав к координатам прямоугольника.
Неизвестный
27.07.2010, 03:50
общий
Зенченко Константин Николаевич:
Начал с самого простого – вывода одного движущегося спрайта по нажатию на Пробел. И не могу правильно написать это в виде структуры. По замыслу при нажатии на клавишу, выводится с определённого места спрайт, который достигнув верхней границы экрана исчезает. При повторных нажатиях клавиши спрайт опять выводится. Но у меня выводится не один, а два спрайта: один неподвижный, другой - подвижный, причём подвижный при первом нажатии выводится с одного места, а при последующих нажатиях чуть левее. Мне непонятно, откуда берётся изображение неподвижного спрайта, что его выводит, ведь он, по идее, должен быть стёртым.
Когда координаты спрайта оформляю не в виде структуры, а через переменные column dw 320 и row dw 240, то всё получается.

locals @@
.model tiny, C
T_MASK STRUC ; положение спрайта
column dw ?
row dw ?
T_MASK ENDS
.code
.startup
mov ax, 0012h ;vga 640х480х16
int 10h

mov dx, 03CEh ;индексный порт графического контроллера
mov ax, 0F01h ;разрешение установки/сброса
out dx, ax

mov ax, 0a000h
mov es, ax
MainLoop:
mov ah,1
int 16h
jz MainLoop
mov ah, 0
int 16h

cmp ah, 1 ;по Esc выходим
je Exit
cmp ah, 39h ;Пробел
je S
jne MainLoop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
S:
call Space ;вывод спрайта
jmp MainLoop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Exit:
mov ax, 0003h ;восстановим текстовый режим
int 10h
mov ax, 4c00h
int 21h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Space proc
mov bx,offset pos
@@1:
call DrawSprite,offset msk1 ;рисуем спрайт
call DELAY
call DrawSprite,offset black1 ;стираем
cmp [bx].row,10
jbe @@2
sub [bx].row,5 ;передвигаем спрайт на 5 строк вверх
loop @@1 ;пока не дойдём почти до верха экрана
@@2:
mov [bx].column,320 ;восстановим первоначальные значения переменных
mov [bx].row,240
ret
Space endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;Рисуем спрайт
.386
DrawSprite proc maska: word
; вычислить номер байта в видеопамяти
mov ax, [bx].row ;AX = строка
mov bx, 80
mul bx ;AХ = АХ * 80

mov di, ax ;сохранить адрес начала строки в di
mov ax, [bx].column
mov cl, al
shr ax, 3 ;AX = номер байта в строке
add di, ax
and cl, 7 ;вычислить номер бита в байте

mov ch, 80h
shr ch, cl ;нужный бит установлен в 1
mov dx, 03CEh ;индексный порт графического контроллера
;;сохраним bx, там переменные структуры,
push bx ;которые затрутся командой mov bl,[si]
mov si,[maska]
mov bl,[si] ; число строк
inc si
mov cl,[si] ; число столбцов
inc si
@@next_row:
push di ; сохраняем смещение начала маски в видеобуфере
push cx

@@next_pixel:
mov ah, [si] ;цвет
mov al, 0 ;al = регистр установки/сброса
out dx, ax

mov al, 8 ; al = битовая маска
mov ah, ch
out dx, ax
xchg es:[di],ah ;заполнить регистры-защелки и вывести на экран пиксель
inc si ; к следующему байту маски
ror ch,1 ; маска для следующего пикселя
adc di,0 ; если был перенос, то к следующему байту видеобуфера
dec cl
jnz @@next_pixel
pop cx ; восстанавливаем маску
pop di
add di,80 ; к следующей строке
dec bl
jnz @@next_row
pop bx ;;восстановим bx и переменные структуры
ret
DrawSprite endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
time equ 30 ;число интервалов по 10мс
DELAY:
pusha ;сохраним все регистры
mov ah,2dh ;сбросим время
xor cx,cx
xor dx,dx
int 21h

dl2:
mov ah,2ch ; читаем время, GET SYSTEM TIME
int 21h ; Return: CH = hour, CL = minute, DH = second, DL = 1/100 seconds
;считаем сотни мс
mov al,100
mul dh ;секунды умножаем на 100 - ax = количество интервалов по 10мс
xor dh,dh ;dx - число сотых
xchg ax,dx ;поменяем местами
mov cl,10
div cl ;ax = количество интервалов по 10мс из сотых
add ax,dx ;складываем с количеством из секунд
cmp ax,time ;сравним с ожидаемым интервалом
jl dl2 ;ждем, если меньше
popa ;восстановим все регистры
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
pos T_MASK <320,240> ;произвольные координаты

Msk1 db 10, 6 ; размер маски в точках: строк, столбцов
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10
db 10,10,10,10,10,10

black1 db 10, 6 ; размер маски в точках: строк, столбцов
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
db 0,0,0,0,0,0
END
давно
Старший Модератор
31795
6196
27.07.2010, 16:57
общий
Adsorores:
Ну очень окровенная ошибка:
Код:
mov ax, [ bx ].row ;AX = строка
mov bx, 80
mul bx ;AХ = АХ * 80
mov di, ax ;сохранить адрес начала строки в di
mov ax, [ bx ].column

Равно ли значение регистров ВХ(и чему) в выделенных строках?

Просто комментарии:
Код:
Space proc
mov bx,offset pos
; 1
mov [ bx ].column,320 ;восстановим первоначальные значения переменных
mov [ bx ].row,240

@@1:
call DrawSprite,offset msk1 ;рисуем спрайт
call DELAY
call DrawSprite,offset black1 ;стираем
; 2
sub [bx].row,5 ;передвигаем спрайт на 5 строк вверх
cmp [bx].row,10
jbe @@2
; ставите одно из следующих условий перехода:
JA @@1
JNBE @@1

sub [bx].row,5 ;передвигаем спрайт на 5 строк вверх
; 3
loop @@1 ;пока не дойдём почти до верха экрана
@@2:
mov [ bx ].column,320 ;восстановим первоначальные значения переменных
mov [ bx ].row,240

ret


1)
У Вас, готовимся к выводу следующего объекта при нажатии, на Space;
У меня, начинаем вывод нового объекта в нужной позиции, при нажатии, на Space.
Позиция привязывается к текущему положению основного спрайта.

2)
Перенос этой строки позволяет: - сократить код и лишние проверки с переходами.


3)
С каким регистром работает команда loop и чему равны значения в момент выполнения команды?
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
28.07.2010, 09:32
общий
Зенченко Константин Николаевич:
Спасибо, очень помогло! Исправил на:
mov ax, [bx].row
push bx ;;сохраним, т.к. bx затрётся следующей командой mov bx,80
mov bx, 80
mul bx
pop bx ;;восстановим
mov ax, [ bx ].column
Плюс другие Ваши замечания помогли!
Форма ответа