game making (c) demon/xpc/cpu

приветствую тебя, забредший сюда... речь здесь опять ( смотри adv#10 ) о говеном гаме-макинге >: -> ну, начнем со спрайт-выводилок, все просто и ясно - бывают они:
- с попиксельными координатами вывода и с знакоместовыми;
- с масочкой и без масочки;
- с атрибутами и без.
дальше идут комбинации вышеперечисленной лажи. делить на виды по способу организации вывода (зависит от структуры хранения инф-ции в спрайтах) я не буду, все равно все не перечислить, даже не помню, как хранились спрайты в сраном спрайт генераторе от thd (козлы), который был для меня первой программой такого рода. несколько слов о выводилках спрайтов: по моему мнению они должны соответствовать определенным условиям, например, для меня не нужны были stack-fast 'овые, и до охереннных размеров раздекранченные, т.к. юзались оба экрана, то выводилка должна была сидеть в основной памяти спека (#5b00-#bfff), а кроме нее еще много чего там сидело. расскажу о трех выводилках; по y они пиксельные, по x две из них знакоместовые и одна пиксельная.

1. х - знакоместовая без маски

тут все стандартно и без всяких гребаных наворотов со стеком и др. причудами, чем проще, тем меньше #бли. но если у тебя есть желание трахаться с прерываниями и трассировать стек, то флаг тебе в руки... итак 32 ldi - это rulez, всего 16 тактов на байт (и на моем четно-тактовом скорпе тоже). задаем координаты в de, размер спрайта в bc и сам спрайт в hl, делаем call ssp, и он на экране (если задано не правильно, то на экране скорее всего появится говно). процедурка эта ничего не проверяет и ничего не возвращает, т.к. это низший уровень ядра проги. хочешь - переделай или вообще лучше сделай свою, будет чем гордиться...

внимание! в листингах присутствует ненормативная лексика - директивы xas 'a.

;sprite x_symbol print without mask
;average_speed= 18.5 t/b (scorp)
;prog_len=120 b
;--------------
;in : hl- sprite
;     de- coord (x-sim,y-pix)
;     bc- size  (y-pix,x-sym)
;--------------
ssp            push    ix
               ld      ix,wo_r_ok+4; рассчитываем и
               ld      a,c;          смещаем цикл
               add     a,a;          по ldi
               sub     64;           через jp (ix)
               neg
               ld      c,a
               ld      a,b
               ld      b,0
               add     ix,bc
               ld      b,a
               push    hl
               call    adres_y;      расчет адреса
               ex      de,hl
               pop     hl
               jr      wo_r_ok;      входим в цикл...
wo_rinc                            28+
               ld      a,e;        4
               add     a,32;       8 (7)
               ld      e,a;        4
               jr      c,wo_r_ok;  8 (7)/12
               ld      a,d;        4
               sub     8;          8 (7)
               ld      d,a;        4
               jp      wo_r_ok;    10

wo_ylop        inc     d;          4
               ld      a,d;        4
               and     7;          8 (7)
               jr      z,wo_rinc;  8 (7)

wo_r_ok        push    de;         10
               ld      c,d ;       4  шоб было c>32
               jp      (ix);       8
               !assm   32;         32-е инструкции ldi
               ldi     ;           16
               !cont
               pop     de;         12 (11)
               djnz    wo_ylop;    14 (13)
               pop     ix
               ret
;------------- расчет адреса в экране
;in:  de- x(sym), y(pix)
;out: hl- adres in screen
;-------------
adres_y        ld      l,d
               ld      a,e
               and     7
               ld      h,a
               ld      a,e
               and     #38
               rlca
               rlca
               or      l
               ld      l,a
               ld      a,e
               and     #c0
               rra
               rra
               rra
               or      h
               ld      h,a
               ld      a,(how_scr)
               or      h
               ld      h,a
               ret

;------------- var
how_scr        db      #40

такты указаны в критичных местах, первые цифры справедливы для скорпа ,в скобках - для всего остального. кстати, на моем скорпе тесты кажут 74884 t в прерывании по четнo-t-вым и от 71141 до 71440 по нечетно-t-вым командам. переменная how_scr является определяющей для того, с каким экраном в данный момент работает прога (не видимый, а рабочий! ), #40 для 5-го и #c0 для 7-го, например: рисуем 5-й экран (how_scr=#40), а видим 7-й, вдруг прерывание: определяем по переменной pag_or (см.ниже), что включен 7-й экран, меняем how_scr на #c0 и стрелку выводим на 7-ом; т.к. все gfx процы, работают через эту переменную, то и адреса все будут рассчитаны для соответствующего экрана. можно вякать, что это тупо и надо бы просто 5-й врубать с #c000 ( sorry, elf ), но при работе с двумя экранами я пришел именно к этому методу.

2. х - знакоместовая с маской

;(c) demon/xpc
;sprite x_symbol printer with mask
;average_speed= 50 t/b (scorp)
;len= 287 b
;-------------
;in: hl- sprite with mask
;    de- coord x(sym), y(pix)
;    bc- size  y(pix), x=(sym)
;-------------
ssp_m          push    ix;          усе тоже самое
               ld      ix,wm_r_ok+3
               ld      a,c
               add     a,a
               add     a,a
               add     a,c
               add     a,c
               add     a,c
               sub     224
               neg
               ld      c,a
               ld      a,b
               ld      b,0
               add     ix,bc
               ld      b,a
               push    hl
               call    adres_y
               ld      d,b
               ld      b,h
               ld      c,l
               pop     hl
               jr      wm_r_ok;    опять цикл...
wm_rinc;                          28+
               ld      a,c ;       4
               add     a,32;       8 (7)
               ld      c,a ;       4
               jr      c,wm_r_ok;  4 (7)/12
               ld      a,b ;       4
               sub     8;          8 (7)
               ld      b,a ;       4
               jp      wm_r_ok;    10

wm_ylop        inc     b;          4
               ld      a,b ;       4
               and     7;          8 (7)
               jr      z,wm_rinc;  8 (7)

wm_r_ok        ld      e,c ;       4
               jp      (ix);       8

               !assm   32
               ld      a,(bc) ;    8 (7) на байт экрана
               and     (hl);       8 (7)  накладываем маску
               inc     hl;         6     и байт спрайта
               or      (hl);       8 (7)  ложим на результат
               inc     hl;         6
               ld      (bc),a ;    8 (7) кладем в экран
               inc     c;          4
               !cont

               ld      c,e         4
               dec     d           4
               jp      nz,wm_ylop; 14
               pop     ix
               ret

спрайт должон иметь следующую структуру: байт-маска, байт-дата, байтмаска и т.д., как делает sprite land от dr. насчет этих двух проц действует следующее правило: , "лучше шире и короче, чем уже и длиннее" , т.е. спрайт размером х=32 и y=10 нарисуется быстрее, чем размером х=10 и y=32, хотя размер в байтах одинаковый.

3. попиксельная с маской

сделал эту процу в основном elf , xn0bys чего-то тоже делал. когда костян (elf) заявил, что это самое, мол, быстрое, то на спор я ее, родимую, зафастил. выигрыш по сравнению со старой в среднем составил 5000-7000 тактов, но если брать спрайт больших размеров (испытуемый кушал около 45000 тактов), то он (выигрыш) пропорционально возрастает. а все за счет использования недокументированных команд; думаю, что можно еще ускорить, но влом...

;fast pixel's sprite with maska...
;by elf/auryn & xn0bys/sg

;...fastest
;by demon/xpc'99

;in: hl adr_of sprite
;    d  coord x in pixels
;    e  coord y in pixels
;    c  -x_size symbol
;    b  -y_size pixel

spr_pxm
               push    hl
               call    adres_p
               ex      de,hl
               add     a,a
               push    bc
               ld      c,a
               ld      b,0
               ld      hl,rol_tab
               add     hl,bc
               ld      a,(hl)
               inc     hl
               ld      h,(hl)
               ld      l,a
               ld      (pxspr+1),hl
               pop     iy
               pop     hl
pxspr          jp      bit_0
;in iy-y & x size
;   hl-sprite with mask
;   de-adres on screen

bit_0
               ld      c,ly
bit_0l1
               ld      b,c
               ld      lx,e
bit_0l2
               ld      a,(de)
               and     (hl)
               inc     hl
               or      (hl)
               ld      (de),a
               inc     hl
               inc     e
               djnz    bit_0l2
               ld      e,lx
               call    down_de
               dec     hy
               jr      nz,bit_0l1
               ret
bit_1
               ex      de,hl
               ld      a,hy
               ld      hx,a
bit1_l1
               ld      hy,ly
               ld      a,l
               ex      af,af' 
bit1_l2
               ld      bc,#ff
               ld      a,(de)
               scf
               rra
               rr      c
               and     (hl)
               ld      (hl),a
               inc     de
               ld      a,(de)
               rra
               rr      b
               or      (hl)
               ld      (hl),a
               inc     l
               inc     de
               ld      a,c
               and     (hl)
               or      b
               ld      (hl),a
               dec     hy
               jr      nz,bit1_l2
               ex      af,af' 
               ld      l,a
               call    down_hl
               dec     hx
               jr      nz,bit1_l1
               ret
bit_2
               ex      de,hl
               ld      a,hy
               ld      hx,a
bit2_l1
               ld      hy,ly
               ld      a,l
               ex      af,af' 
bit2_l2
               ld      bc,#ff
               ld      a,(de)
               scf
               !assm   2
               rra
               rr      c
               !cont
               and     (hl)
               ld      (hl),a
               inc     de
               ld      a,(de)
               !assm   2
               rra
               rr      b
               !cont
               or      (hl)
               ld      (hl),a
               inc     l
               inc     de
               ld      a,c
               and     (hl)
               or      b
               ld      (hl),a
               dec     hy
               jr      nz,bit2_l2
               ex      af,af' 
               ld      l,a
               call    down_hl
               dec     hx
               jr      nz,bit2_l1
               ret
bit_3
               ex      de,hl
               ld      a,hy
               ld      hx,a
bit3_l1
               ld      hy,ly
               ld      a,l
               ex      af,af' 
bit3_l2
               ld      bc,#ff
               ld      a,(de)
               scf
               !assm   3
               rra
               rr      c
               !cont
               and     (hl)
               ld      (hl),a
               inc     de
               ld      a,(de)
               !assm   3
               rra
               rr      b
               !cont
               or      (hl)
               ld      (hl),a
               inc     l
               inc     de
               ld      a,c
               and     (hl)
               or      b
               ld      (hl),a
               dec     hy
               jr      nz,bit3_l2
               ex      af,af' 
               ld      l,a
               call    down_hl
               dec     hx
               jr      nz,bit3_l1
               ret
bit_4
               ex      de,hl
               ld      a,hy
               ld      hx,a
bit4_l1
               ld      hy,ly
               ld      a,l
               ex      af,af' 

bit4_l2
               ld      bc,#ff
               ld      a,(de)
               scf
               !assm   4
               rra
               rr      c
               !cont
               and     (hl)
               ld      (hl),a
               inc     de
               ld      a,(de)
               !assm   4
               rra
               rr      b
               !cont
               or      (hl)
               ld      (hl),a
               inc     l
               inc     de
               ld      a,c
               and     (hl)
               or      b
               ld      (hl),a
               dec     hy
               jr      nz,bit4_l2
               ex      af,af' 
               ld      l,a
               call    down_hl
               dec     hx
               jr      nz,bit4_l1
               ret
bit_5
               ex      de,hl
               ld      a,hy
               ld      hx,a
bit5_l1
               ld      hy,ly
               ld      a,l
               ex      af,af' 
bit5_l2
               ld      a,(de)
               ld      c,a
               ld      a,#ff
               !assm   3
               sli     c
               rla
               !cont
               and     (hl)
               ld      (hl),a
               inc     de
                 ld      a,(de)
               ld      b,a
               xor     a
               !assm   3
               rl      b
               rla
               !cont
               or      (hl)
               ld      (hl),a
               inc     l
               inc     de
               ld      a,c
               and     (hl)
               or      b
               ld      (hl),a
               dec     hy
               jr      nz,bit5_l2
               ex      af,af' 
               ld      l,a
               call    down_hl
               dec     hx
               jr      nz,bit5_l1
               ret
bit_6
               ex      de,hl
               ld      a,hy
               ld      hx,a
bit6_l1
               ld      hy,ly
               ld      a,l
               ex      af,af' 
bit6_l2
               ld      a,(de)
               ld      c,a
               ld      a,#ff
               !assm   2
               sli     c
               rla
               !cont
               and     (hl)
               ld      (hl),a
               inc     de
               ld      a,(de)
               ld      b,a
               xor     a
               !assm   2
               rl      b
               rla
               !cont
               or      (hl)
               ld      (hl),a
               inc     l
               inc     de
               ld      a,c
               and     (hl)
               or      b
               ld      (hl),a
               dec     hy
               jr      nz,bit6_l2
               ex      af,af' 
               ld      l,a
               call    down_hl
               dec     hx
               jr      nz,bit6_l1
               ret
bit_7
               ex      de,hl
               ld      a,hy
               ld      hx,a
bit7_l1
               ld      hy,ly
               ld      a,l
               ex      af,af' 
bit7_l2
               ld      a,(de)
               ld      c,a
               ld      a,#ff
               sli     c

               rla
               and     (hl)
               ld      (hl),a
               inc     de
               ld      a,(de)
               ld      b,a
               xor     a
               rl      b
               rla
               or      (hl)
               ld      (hl),a
               inc     l
               inc     de
               ld      a,c
               and     (hl)
               or      b
               ld      (hl),a
               dec     hy
               jr      nz,bit7_l2
               ex      af,af' 
               ld      l,a
               call    down_hl
               dec     hx
               jr      nz,bit7_l1
               ret
down_hl
               inc     h
               ld      a,h
               and     7
               ret     nz
               ld      a,l
               add     a,32
               ld      l,a
               ret     c
               ld      a,h
               sub     8
               ld      h,a
               ret
down_de
               inc     d
               ld      a,d
               and     7
               ret     nz
               ld      a,e
               add     a,32
               ld      e,a
               ret     c
               ld      a,d
               sub     8
               ld      d,a
               ret
adres_p
               ld      a,e
               and     a
               rra
               scf
               rra
               and     a
               rra
               xor     e
               and     #f8
               xor     e
               ld      h,a
               ld      a,d
               rlca
               rlca
               rlca
               xor     e
               and     #c7
               xor     e
               rlca
               rlca
               ld      l,a
               ld      a,d
               and     #07
               ret
rol_tab
               dw      bit_0,bit_1,bit_2,bit_3
               dw      bit_4,bit_5,bit_6,bit_7

смысл в следующем: вычисляется на сколько придется роллировать байты спрайта с маской, из таблицы берется соответствующая проца, и процесс цикла начинается. спрайт имеет такую же структуру, как описывалось выше. наверно в этой проце можно че-нибудь подчистить, если есть желание, хотя работает она без проблем и уже довольно долго нами юзается в таком виде. все эти выводилки работают с монохромными спрайтами, т.к. вывести атрибуты с точностью до пиксела по y очень и очень проблематично >: ->

прежде чем перейти к следующей части своего повествования, хочу рассказать о том, как у меня свапуется память и экран.

;-------------------page lister
;in: a- page logic nomber (0...7),
;    if a=#ff then goto old_pag

pager          ex      af,af'
               ld      a,r
               jp      pe,pg_n_im
               ld      a,r
pg_n_im        push    af
               di
               ex      af,af' 
               and     a
               jp      m,old_pag;     a=0...7

pg_f_op        ld      (sav_pag),a ;   for old_pag
now_pag        equ     $+1
               ld      a,7
               ld      (old_pag+1),a
sav_pag        equ     $+1
               ld      a,0
               ld      (now_pag),a

pg_f_sw        and     7;             for scr_swp
pag_or         equ     $+1
               or      0
               out     (#fd),a
               ld      (23388),a
               pop     af
               di
               ret     po
               ei
               ret

old_pag        ld      a,0
               jr      pg_f_op

;----------------------screen swaper
;in: a- 0 is #4000, other is #c000 viewing

scr_swp        ex      af,af'
               ld      a,r
               jp      pe,sw_n_im
               ld      a,r
sw_n_im        push    af
               di
               ex      af,af
               or      a
               ld      a,(pag_or)
               jr      nz,sw_is_7; if a=0 then scr#5
               res     3,a

sw_f_7         ld      (pag_or),a
               ld      a,(now_pag)
               jr      pg_f_sw

sw_is_7        set     3,a
               jr      sw_f_7


;----------------- #fd mask detecter
;out: a- mask for pager
fd_mask        ld      a,#10
               ld      bc,#7ffd
               out     (c),a
               ld      hl,#ffff
               ld      e,(hl)
               ld      a,#50
               ld      (hl),a
               out     (c),a
               cp      (hl)
               ld      a,#10
               out     (c),a
               ld      (hl),e
               ret     nz
               ld      a,#50
               ret

все вышеперечисленные процы составляют один пакет для работы с памятью 128 кб. - проца fd_mask запускается один раз в самом начале для определения 512ти килограммовых компов, если нет, то щелкаем память с включенным 6-м битом ( для скорпа а ). - проца pager свапует 128-ю память, запоминает текущую страницу в now_pag, предыдущую в old_pag и все свапует через pag_or. mаразм с регистром r и определением состояния прерываний взят из статьи ивана рощина , за что огромное ему спасибо. таким макаром у меня ни разу не было глюков по определению текущей страницы. а почему щелкаю по #fd, а не по #7ffd? да вот нравится так. - scr_swp работает через pager, поэтому когда щелкаю память не болит голова о том, какую маску ставить для экрана.

ну теперь про int (прерывания). очень рулезная вещь, эти самые прерывания, можно вешать на них, что хочешь, хоть весь движок. но лучше повесить такие вещи, как сканирование кнопок и мыши, движение курсора (если он присутствует), какие-нибудь фишки, типа мини-скролла с хелпом, либо небольшой анимации где-нибудь в углу экрана и, конечно, музыку и эффекты в конце. при работе с int может возникнуть множество неприятностей, все даже не предсказать; расскажу о своих. в adv#10 был приведен мой обработчик прерываний, аналогичный сидит в "full shit" , в котором: - маленькая проца по переключению видимого экрана, юзает глобальные переменные now_pag, page_or; - сохраняется номер текущей страницы памяти и определяется видимый экран, при этом сохраняется, а затем меняется переменная how_scr; - врубается страница #7, т.к. в ней сидят все процы. следует учесть, что int-таблица содержит 257 байт и находится во 2-м банке, чтоб хоть как-то не обидеть оригинальный спек . на возможный вопрос: "почему 7-й банк?" , ответ таков: юзаются оба экрана, места в #5b00-#bfff мало, а в 7-ом за вычетом экрана и скрина локации остается целых 3 кило. - восстанавливается экран под курсором, но если ранее сработало переключение видимого экрана, то дерьмо со старого не восстанавливается; - сканируется клава на предмет нажатия кнопок "6, 7, 8, 9, 0, break, q, a, o, p, space" и движения мыши (на пц - эмулях какой-то голюн с нашим драйвером: пц маст дай); - идет обращение к проце под именем int_gfx. это и есть разные фишки, состоит в основном из кучи векторов, которые меняются в зависимости от действий геймера, например: появляется менюха, где крутится предмет (надо отрубить лампочку на фонаре, а потом повесить вращающийся предмет, а если вызвать карман, то 4-е предмета; мультики тоже играются по int) или диалоговое окно, все по int на х..; - запоминается кусок в новом месте, если было перемещение (иначе в старом), рисуется курсор, после всех наворотов, чтоб не попасть под какой-нибудь спрайт или текст; - в последнюю очередь играется музон и для прикола меняются атрибуты на светофоре; - восстанавливаем страницу памяти, переменную how_scr и назад.

первый глюк возник, когда я решил все заоптимизить: убрал собственные процы вывода графики из прерываний, чтоб все делалось через единые процы. и тут началось... на экране стало появляться всякое дерьмо, без всякой закономерности, иногда вообще все висло или сбрасывалось. а при трейсе все работало без проблем. такие глюки ненавижу, т.к. причина сразу-то и не ясна. а вся херня была из-за того, что в старом варианте выводилки сохранялись локальные переменные (размер спрайта) и при попадании на int они киллились, т.к. int тоже юзал эти процы. вывод: если процу юзают все, то при ее работе все переменные надо хранить на регистрах или толкать их в стэк, иначе в прерываниях придется сохранять все переменные. второй глюк возник с переключением экранов, но об этом я, по-моему, уже говорил... в общем, если все в проге тщательно проверить, то глюков обычно возникает мало и не советую вешаться на im 1, хотя кому как нравится, хоть на im 0 работайте >: -> теперь о структуре "full shit" , которая оставляет желать лучшего, но что есть, на том и кашу сварим...

	  can: on/off [t],all process; lock [c]
  +========+=======+======+=======+=====+  +------------+
  w        w       w      w       w     |  | int_mode 2 |
         begin <------------+           |  +------------|
        +------>------+     |           |  | 1.scr_swp  |
   +------+   pass    |     |           |  | 2.key_scn  |
+--|  go  |<------[t]<|     |           +==| 3.cr_proc  |
|  +------+           |     ^              |            |
|   +------+  pass    |     +---<--+       | 4.int_gfx  |
| +-| menu |<-----[t]<|     |      |       | 5.play_mz  |
| | +------+          |     |      |       |            |
| |  +------+ pass    |     |n     |       +-----+------+
| | +| time |<----[c]<+     |o     |             |
| | |+------+   +-------+   |      |             |
| | +-----------|chk_cnt|>[time?]  |             |
| +---------+   +-------+   |      |         save all
|           |               |      |          and use
|+-------+  |+-------+      |      ^             |
+|clc_way|  +|chk_map++     |y     |             |
 +---+---+   +-------+|     |      |             |
     |                |     |e     |             |
     v  is not    no  |     |s     |             |
  [way?]---->-+-<--[thing?] +-+    |             |
     |        |       |       |    |             |
+----+        |    +--+       v    |             |
|             |    |          |    |             |
|+-------+    v    |+-------+ |    |             |
+|mak_way| return  +|win_put| |    +<-----+      |
 +---+---+   to     +---+---+ |    |      |      |
+----+    "begin" +-----|     |    |      |      |
|                 |     |     |    |      |      |
|+-------+        | +---+---+ |    |   use "go"  |
+|go_draw|        | |actions| |    |      |      |
 +---+---+        | +---+---+ |    ^      ^      |
     |    +----<-----------<--+    |      |      |
     |    |       |     +------->[doing]--+      |
     |    |       |    +-----------|             |
     |    v       v    |       +---+---+         |
     |                 v       v       v         |
     v                      +-----+ +-----+      |
          gfx_engine        |death| |happy|      |
   +---------------------+  | cut | | cut |      |
   | draw location:      |  +--+--+ +--+--+      |
   | 1. background       |     |       |         |
   | 2. hero             |     +---+---+         |
   | 3. upground         |         |             |
   | 4. turn on "scr_swp"|         |             |
   | use many primitive  |         v             |
   | gfx_procs           |         |             |
   +---------------------+         |             |
             |                     |             |
   +---------------------+         |             |
   | low level procs     | <-------+---------<---+
   +---------------------+
     |        |        |
     v        v          v
   video     ram     disk


           loc_map
  +------------------------+
  |    32*20=640 bytes     |
  +---------------+ use it:|
  %%+=+%%%% ******|cal_way - read
  ##|#о##### *+o+*|chk_map - read
  ##|#о###### ++ *|actions - read & write
  #=+=########++ *+--------+

пояснилова


1) обозначения:
[t] - порог (#0 или #с9);
[c] - порог-счетчик (пропускает через n-ое кол-во вызовов;
[time?] - условие (например: время);
2) подпроги:
go: - проца, отвечающая за перемещение героя;
clc_way - просчет пути, если нет, то нет перемещения;
mak_way - иначе делает специальный управляющий массив;
go_draw - работа со спрайтами перемещения по упр. массиву.
menu: - действия с предметами;
chk_map - проверяет статус курсора "на предмете или нет", если нет, то игнорирует юзера
win_put - иначе выводит окно действий и ждет действий геймера;
actions - производит выбранные действия, сопровождая это дело выводом сообщений и анимации, и согласно им делает переход на соотв. процу либо возвращается в основной цикл.
time: - постоянно перерисовывает игровой экран;
chk_cnt - периодически добавляет разную анимацию (автобус, вышибала, герой...)
int_mode2 - контролирует все процессы с помощью "порогов входа" в процы (nop or ret), свапует, сканирует, рисует и поет...
gfx_engine - участвует всегда в перерисовке экрана либо выводе чего-либо на экран.
low level procs - утилиты-примитивы, работающие именно с ресурсами машины.
loc_map - это массив размером 32*20 элементов, являющийся картой локации. в основном используется при расчете пути и работе с предметами.

now пойдет речь о процедуре рассчета пути в карте локации для того самого мудака, которого ты видел в "full shit". алгоритм взят у славы медноногова (который его тоже где-то взял и т.д. и т.п.) из его статьи в одном из zx-fоrmat 'ов. для начала лучше почитать эту статью, а уж потом суйся сюда, т.к. я прос-то приведу ассемблерный вариант этого метода... сразу скажу, что это дело для меня оказалось несколько проблематичным, т.к. мой чиж (ну, персонаж) получился не элементом 1х1, а педрюком 1х4. поэтому я просто зае...ся точить прогу для этого говнюка, чтоб он хоть как-то нормально ходил по локации, тем более из-за ограничений по памяти он не мог ходить по диагонали. в общем процесс написания этого куска движка затормозил вообще весь процесс. ладно, вот вообщем оно-самое:

;(c) demon / xpc'99
;----------------------------
;wawe algoritm for search way
;main idea v.mednonogov
;realized by me,of course...
s_cod          equ     #50;      start cod
gc_mint        equ     s_cod+45; max iteration
;-----------------

go_wawe        ret     ;   turn
               ld      a,#c9
               ld      (go_wawe),a

;-------------------- make work dim  34*22 =748 b
;делается окантовочка, чтоб лишний раз не проверять выход
;за границу массива

               ld      b,20
               ld      hl,#6200;        map_loc
               ld      de,gc_wdim+35
gd_lop         ld      c,h
               !assm   32
               ldi
               !cont
               inc     de
               inc     de
               djnz    gd_lop


;-------------------- set fin & start inside go_dim
;в скопированной карте ставим код старт и цель

gc_ctar        ld      bc,0
               ld      a,c
               sub     4
               ld      c,a
               call    gc_ccrd
               ld      (hl),128;           target cod
gc_csrt        ld      bc,0
               ld      a,c
               sub     4
               ld      c,a
               call    gc_ccrd
               ld      (hl),s_cod;           start cod
               inc     hl
               ld      (hl),s_cod
               inc     hl
               ld      (hl),s_cod
               inc     hl
               ld      (hl),s_cod
               ld      lx,s_cod

;-------------------- main ()
gc_main        call    gc_sway
               jr      nz,gc_found
               dec     a
               ld      (go_way),a ;         #ff
               ret


;----------------- make way
; если нашли цель...

gc_found       exx
               ld      hl,gcb_way-2
               exx
               ld      c,lx
               inc     lx
               inc     lx
               ld      de,34

gc_b_lp        dec     c
               call    gc_lb
               jr      z,gcb_fin
               call    gc_rb
               jr      z,gcb_fin
               call    gc_db
               jr      z,gcb_fin
               call    gc_ub
               jr      z,gcb_fin
               inc     c
               ld      a,lx
               cp      c
               ret     c
               jr      gc_b_lp+1

;----------------- found iteration (-1)
gcb_fin        ld      a,b
               exx
               ld      (hl),a
               dec     hl
               exx
               ld      (hl),#81
               jr      gc_b_lp

;----------------- make normal way_map
gc_reway       pop     af
               ld      a,b

               exx
               ld      (hl),a
               ld      de,go_way
gcrw_lp        ld      b,(hl)
               ld      a,b
               cp      #ff
               jr      z,gcrw_end
               call    gcw_sub
               ld      (de),a
               inc     hl
               inc     de
               jr      gcrw_lp
gcrw_end       ld      (de),a
               jp      rewayer

;----------------- invert way_step
gcw_sub        ld      a,"l"
               cp      b
               ld      a,"r"
               ret     z
               cp      b
               ld      a,"l"
               ret     z
               ld      a,"u"
               cp      b
               ld      a,"d"
               ret     z
               ld      a,"u"
               ret

;----------------- back_search
gc_lb          ld      b,"l"
               dec     hl
               ld      a,(hl)
               cp      s_cod
               jr      z,gc_reway
               cp      c
               ret     z
               inc     hl
               ret
;-----------------
gc_rb          ld      b,"r"
               inc     hl
               ld      a,(hl)
               cp      s_cod
               jr      z,gc_reway
               cp      c
               ret     z
               dec     hl
               ret
;-----------------
gc_ub          ld      b,"u"
                 and     a
               sbc     hl,de
               ld      a,(hl)
               cp      s_cod
               jr      z,gc_reway
               cp      c
               ret     z
               add     hl,de
               ret
;-----------------
gc_db          ld      b,"d"
               add     hl,de
               ld      a,(hl)
               cp      s_cod
               jr      z,gc_reway
               cp      c
               ret     z
               and     a
               sbc     hl,de
               ret

;-------------------- is way being ?
;if no way then a=0

gc_sway        ld      a,lx
               ld      hl,gc_wdim+35
               ld      bc,679
gc_cpir        cpir
               jr      z,gc_l1
               inc     lx
               ld      a,gc_mint
               cp      lx
               jr      nz,gc_sway
               xor     a
               ret

;----------------- i_cod founded
gc_l1          push    hl,bc
               dec     hl
               ld      (element),hl
               call    gc_left
               call    gc_right
               call    gc_down
               call    gc_up
               pop     bc,hl
               ld      a,lx
               jr      gc_cpir

;-------------------- step left
gc_left
element        equ     $+1
               ld      hl,0
               dec     hl
               ld      a,(hl)
               or      a
               ret     p
               cp      128
               jr      z,glo_end
               ld      a,lx
               inc     a
               ld      (hl),a
               ret

;-------------------- step right
gc_right       ld      hl,(element)
               inc     hl
gc_v_jr        ld      a,(hl)
               or      a
               ret     p
               cp      128
               jr      z,glo_end
               ld      a,lx
               inc     a
               ld      (hl),a
               ret

;-------------------- step down
gc_down        ld      hl,(element)
               ld      bc,34
               add     hl,bc
gcu_jr         push    hl
               call    gc_c_4b
               pop     hl
               jp      m,gc_c_ok
               ret

;-------------------- step up
gc_up          ld      hl,(element)
               ld      bc,34
               and     a
               sbc     hl,bc
               jr      gcu_jr

;-------------------- up or down way is ok!
gc_c_ok
               ld      a,128
               ex      af,af' 
               ld      a,lx
               inc     a

               !assm   4
               ex      af,af
               cp      (hl)
               jr      z,glo_end
               ex      af,af' 
               ld      (hl),a
               inc     hl
               !cont

               ret

;-------------------- check 4 bytes
gc_c_4b        ld      a,(hl)
               inc     hl
               and     (hl)
               inc     hl
               and     (hl)
               inc     hl
               and     (hl)
               ret

;-------------------- it's start !!!
glo_end        pop     de,de ,de
               or      a
               ret

;----------------- in bc- r (x,y) > out hl- adr of ...
gc_ccrd        inc     c
               inc     b
               ld      a,b
               ld      b,c
               ld      hl,gc_wdim
gc_mlp         ld      de,34
               add     hl,de
               djnz    gc_mlp
               add     a,l
               ld      l,a
               ld      a,0
               adc     a,h
               ld      h,a
               ret

               !assm   !off
;-------------------- in hl- il in dim> out de- x,y
gc_c_el        ld      de,0
               ld      bc,34
               and     a
gc_dlp         sbc     hl,bc
               jr      c,dv_end
               jr      z,dv_end+1
               inc     e
               jr      gc_dlp
dv_end         add     hl,bc
               ld      d,l
               dec     e
               dec     d
               ret
               !cont

;----------------- very fatly array
gc_wdim        ds      748,#3030
go_way         ds      50,#ffff
gcb_way

вначале карта локации копируется в буфер, равный размером ей самой, чтоб не обосрать ее родимую своими итерациями. как видно не вооруженным взглядом, массивно юзается команда cpir, так, я думаю, быстрее получается, хотя я мало чего оптимизил, итак времени утрахал на саму процу. если ты все-таки удосужился прочесть ту статью, про которую я упомянул ранее, то тебе, друг мой, все будет ясно... командой cpir ищем итерацию, проверяем ее на вшивость, потом ищем другую и так до конца массива. я думаю, все предельно ясно. когда весь массив обработан (забит дерьмом), начинаем обратный отсчет, пока не приходим к цели. делается это все довольно мудово, и даже заметно в игре, хотя int, конечно, не стопорится >: -> максимальное время на расчет пути уходит, когда этого пути просто нет. тогда массив 32х20 элементов полностью замуживается и у меня это отнимает аж 13 прерываний, то бишь 900 000 тактов !!! мудово...

так как предметы на локации у меня являются непроходимыми, то при указании стрелкой на них выбирается уже заранее забитые координаты допустимого места, куда может быть просчитан путь для моего мудака. т.е. если ты выберешь, например, вышибалу, то программа определит, что ты выбрал предмет, и возьмет из таблицы координаты для него (точнее для героя, чтоб подойти к предмету) и подсунет их считалке пути, а не реальные координаты курсора, как это было бы иначе.

и еще... проца хождения героя у меня сделана таким образом, что она работает через команды (понятные только ей, of couse). в специальном буфере ей передается строка команд, которые надо выполнить, типа: "l, 10, u, 2, r, 3, ff" - это означет, что надо сделать 10 шагов влево, потом 2 вверх и затем 3 шага вправо, #ff - end. все просто, но зато очень удобно, теперь переделывая движок под цветные спрайты, я просто поменяю значения в таблице размеров спрайтов и все! так что не удивляйся значениям типа "l" или "d" в вышеприведенном коде.

также сделаны и другие процы, так что прошу мотать на ус...

итак, пипл, прошло довольно много времени с момента написания первой части статьи, поэтому можете считать все вышенаписанное полным отстоем. "а что не отстой ?" - спросишь ты меня, мой дорогой друг. все, что я или ты сделал является отстоем, т.к. ты это уже сделал! а вот то, чего мы пока не можем - по сути и является для нас самоцелью. тут недавно узнал такую вещь - маску для спрайта можно хранить черезстрочно, т.е. в два раза меньше! такая простая и крутая идея, а сама по себе ни хрена ни пришла, эх, если б раньше знать... для тех, кто не понял: у маски хранятся только четные или, наоборот, нечетные линии. при выводе недостача компенсируется дублированием линий. все просто - а спрайт занимает аж в 1, 5 раза меньше места (например, при размере 16 кило имеем экономию аж в 6 кило! ). я думаю эта фишка давно известна гейммэйкерам, но я лично благодарен volgasoft за данную идею. можно с этой фигней экскрементировать как угодно, может у кого вообще получится какой-нибудь рулез.

ща ant и vaniac перерисовывают с нуля графику для full shit , и т.к. она вся цветная, то соответственно мне пришлось столкнуться с рядом проблем...

спрайты рисуются спец-методом (рис.1):

cпрайт рисуется какими угодно инками и паперами, но по границе должон не использовать цветов, это окантовка позволяет квадратную атрибутную графику превратить во вполне приемлемую картину.

на рис.2 показана суть метода:

все геморы (от слова "геморой") начинаются, когда всю эту туеву хучу кусочков надо вывести на экран как единое целое. тут, в принципе, нет ничего особо сложного, но я сделал так:

1. все "куски" представляют собой отдельные спрайты, цветные выводятся как спрайт с атрибутами (put), а окантовка как простые (lines) по or-методу (правда можно и по маске, но тактов жрать больше будет, а эффектом не особо отличается).

2. соответственно пишем (или берем) програмку для вывода спрайтов данного формата (хранить и выводить можете как угодно, у меня таким методом: 8 линий данных, потом для них линия атрибутов, снова 8 линий...) и делаем менеджер...

3. "куски" одного спрайта хранятся у меня в одном массиве: +0 x, y (у первого всегда по нулям) +2 x_size, y_size +4 смещение до следующего спр. (nn) +6 тип спрайта (attr, lines... = 0, 1, ...) +7 сам спрайт .. ............ .. ............

+nn x, y относительно самого первого спр.
nn+1 x_size, y_size...

... и так далее...

вот теперь пишем менеджер, который будет все эти массивы разгребать и решать, какой выводилкой рисовать следующий "кусок" и где его рисовать (переводить относительные корды в реальные).

понятно, что все это будет работать не так быстро, как хотелось бы, но вопервых, вполне нормально, а во-вторых оптимизация не знает границ ! можно уже готовые массивы конвертить в другой формат таким образом, чтобы не пересчитывать для каждого "куска" корды. мне лично в лом, но если будет тозить, то, конечно, я это сделаю... а так, можно конвертить уже готовые массивы "кусков" так, чтобы не пересчитывать каждый раз корды для них, ясно ? ну ладно, на хрен, достало писать, пока!