Если проводить параллели со спековскими играми, то я бы обратил внимание на old tower Дениса Грачева
Вид для печати
Если проводить параллели со спековскими играми, то я бы обратил внимание на old tower Дениса Грачева
Сделал новую версию "Binorum"
Что изменено:
- подключена возможность управлять Джойстиком П (на кнопках - рестарт уровня / он же старт игры)
(спасибо ivagor, svofski, Improver за помощь с вопросами по Джойстику П)
- в заставке название игры преобразилось ( надеюсь в лучшую сторону) :)
- был убран (немного "глючный") спецэффект при взятии монеты
Позже (после того как пройдёт проверка на реальном Векторе) выложу новую версию в начало темы.
Проверка на реальном Векторе прошла успешно - можно скачать новую версию в первом посте в самом низу (вложения) - файл BinorumJP.
Также если можно, то прошу svofski заменить (или добавить) в Картотеке старую версию на новую.
Обнаружил, что последняя версия игры не работает у меня в эмуляторе Emu80 (также как и в emu от b2m).
Логично было предположить, что проблема в добавленной поддержке джойстика, стал разбираться, но понимание не пришло.
В эмуляторе опрашивается порт B второго ППА (06h). Насколько я понимаю, разомкнутые контакты джойстика - это 1 в соответствующем разряде, нажатие кнопки либо отклонение джойстика приводит к появлению 0.
В Emu80 джойстик (пока) не эмулируется. Загрузчик по умолчанию программирует все 3 порта второго ППА на ввод, никаких подтягивающих резисторов на входах нет, стало быть, без подключенного джойстика из порта B считывается 0, что игра ошибочно воспринимает как нажатые клавиши джойстика.
Но как оно в таком случае работает на реале (без джойстика)? Что я не учитываю?
Ramiros, логично. Могу ошибаться, конечно, но почему-то мне запомнилось, что на моем Апогее в подобном случае из ВВ55 стабильно считывались нули... Проверю еще раз вечером...
Ramiros, провел тесты на том, что было под рукой - Апогее. Там также имеется ВВ55, все входы/выходы которого просто выведены на внешний разъем. При программировании на ввод из портов стабильно считываются нули. Более того, именно этот эксперимент побудил меня изменить это поведение в Emu80. В версиях до 4.0.350 включительно из портов считывалось FF, и на них Binorum без проблем работает. В общем, насколько надежно полагаться на то, что без джойстика будет всегда считываться FF, я не знаю :( Может быть, поведение зависит от партии ВВ55 или разводки платы или еще чего-то? Кто-нибудь из форумчан может что-то подсказать?
Кстати, если порт запрограммирован на вывод и на нем установлено FF, то при перепрограммировании на ввод нули начинают считываться не сразу и не одновременно во всех разрядах, переходные процессы занимают некоторое время. Могу проиллюстрировать скриншотом с экрана Апогея, но тут это наверное будет оффтопик...
Работу игры в следующей версии Emu80 восстановлю, а пока при желании можно взять версию 4.0.350 от 13 марта года из архива.
Pyk, Может зависит от ревизии, партии ВВ55-й? но игру проверили на реале и она работает. Вообще я считаю это косяк игры и игру по уму надо бы допилить, т.к. есть вероятность что не на всех Векторах она запустится.
parallelno, при сборке tasm-ом я просто склеиваю отдельные бинарные файлы в процессе сборки, проще всего. db64 - это фишка Прекрасма, в нем можно вставлять большие куски прямо в base64. Когда на скорую руку хочется какой-нибудь графики добавить, удобно.
cat code.bin data.bin > test.rom, ну или copy/b head.bin+data.bin test.rom, в зависимости от системы. Смещение на приплюсованные данные легко вычисляется с помощью метки в конце ассемблерного файла.
А если нужно два бинарных файла приклеить?
Так же, cat и copy можно сколько угодно файлов склеивать. Если несколько массивов данных на которые нужны ссылки, тут тяжелее. Тогда размеры файлов и смещения можно вычислить перед компиляцией основного модуля и передать их как параметры. Например вот тут так делается (наверное это трудночитаемый кусок, но суть в том, что ZSTART получается как 256+VMSIZE+STARTSIZE и потом -DZPU_CODE_START=$$ZSTART
https://gitlab.com/svofski/zpu8080/-...common.mk#L117
Это все по своему красиво, но может быть неоправданно и если проще сконвертировать данные в db, которые включаются директивой include, то так лучше и сделать. Объемы-то все комически крохотные: самая громадная глыба данных, которую Вектор сможет охватить, современному компьютеру даже L2 кеш не завалит.
А как передать в tasm параметры? Я не смог найти такое в мануале. Видел только что макрос можно для всяких ifdef передавать. Извини, не смог сходу разобраться в твоём билде по ссылке. Не умею пока в Мэйк файлы.
Параметр и макрос в тасме это одно и то же.
В коде пишем что-нибудь типа
а при вызове tasm добавляем (можно просто в батнике) -DDATA_SIZE=256, то естьКод:lxi h, DATA_SIZE
tasm -DDATA_SIZE=256 -b -t85 myprog.asm myprog.bin
О! За это огормное спасибо! Жалко что не было примера макросов в документации TASM.
- - - Добавлено - - -
команды dup и edup которые ты привел в своем коде из какого ассемблера?
- - - Добавлено - - -
Сравнил твой алгоритм с предыдущими. Твой чуть быстрее всех в тесте TKSerg.
Что-то картинка чмльно пожалась. Не разобрать, поэтому текстом. Добавил проценты от изначального варианта metamorpho. Наглядно видно сколько можно выжать при оптимизации. Крутые результаты, ребят! И спасибо за реализации.
jerri's original
137EH 4990 162%
jerri's precalced, unrolled
162EH 5678 184%
Serg's original
151CH 5404 175%
Serg's precalced, unrolled
15B0H 5552 180%
ivagor's unrolled
170EH 5902 191%
metamorpho's unrolled
0C0CH 3084 100%
Вложение 77511
Нашел небольшую ошибку в программе KTSerg
Два раза вызов процедуры для расчета адреса спрайта для последнего знака результата
Корректный результат будетКод:call adr_tab
call adr_tab ; вычисление адреса спрайта
jerri's original
137FH 4990 162%
jerri's precalced, unrolled
162FH 5678 184%
Serg's original
151EH 5404 175%
Serg's precalced, unrolled
15B8H 5552 180%
ivagor's unrolled
1707H 5895 191%
metamorpho's unrolled
0C0EH 3086 100%
- - - Добавлено - - -
Можно сказать что ничего не поменялось, но для чистоты эксперимента примвел %)
Они содержатся не в моём коде.
Судя по переписке
https://zx-pk.ru/threads/31954-pishu...=1#post1075237
Я сам не знал что это такое, чтобы заменить чем-то соответствующим для Вектора.
Мнемоника команд кода в котором они были, очень похожа на мнемонику для Z80.
Поисковик дал такую ссылки:
https://zx-pk.ru/threads/447-sjasmpl...l=1#post903843
https://zx-pk.ru/threads/447-sjasmpl...l=1#post904360
http://zxpress.ru/article.php?id=14690
Пытаяс понять как работает твоя реализация прерываний нашел один избыточный кусочек кода как мне кажется:
кажется что тут избыточно порталкивание PSW в стек и обратно. Как мне кажется его можно убрать, и заодним убрать смешение SP на 2 в команде DADКод:StInt:
xthl ; обмен hl <-> ((sp))
shld im_ret+1 ; сохраним адрес возврата из прерывания
pop h
shld im_hl+1 ; сохраним значение HL при выхове прерывания
push psw
lxi h,2 ;\ вычисляем указатель стека
dad sp ;/
shld im_sp+1 ; сохраним указатель стека
pop psw
push b ;восстановим данные испорченные стеком
lxi sp,im_stek ; временный указатель стека для прерываний
push PSW
push b
push d
Поправь меня пожалуйста если ошибаюсьКод:StInt:
xthl ; обмен hl <-> ((sp))
shld im_ret+1 ; сохраним адрес возврата из прерывания
pop h
shld im_hl+1 ; сохраним значение HL при выхове прерывания
lxi h,0 ;\ вычисляем указатель стека
dad sp ;/
shld im_sp+1 ; сохраним указатель стека
pop psw
push b ;восстановим данные испорченные стеком
lxi sp,im_stek ; временный указатель стека для прерываний
push b
push d
- - - Добавлено - - -
Действительно ошибся. Спасибо за ссылки.
Если в основной программе флаг CY ни где и ни как не используется, то видимо, скорее всего, его защиту в прерывании можно убрать.
О, точно. Не подумал об этом. Спасибо!
- - - Добавлено - - -
Как думаете, рисовать спрайты лучше сверху вниз или наоборот? Где будет меньше теаринг? При условии что мы не укладываемся в прирывание.
Спасибо за оптимизацию! Твой вариант самый быстрый.
Я его совсем незначительно ускорил (только в инициализации). примерно на 1,2% и сделал его чуточку понятнее для хранения данных (на мой вкус), хотя и далеко от идеала.
твой вариант
Код:;----------------------------------------------------------------
; draw a sprite (24x24 pixels)
; author ivagor
; method: zig-zag, unrolled
; in:
; BC sprite data
; DE screen address (x,y)
.macro DRAW_EVEN_LINE_IVAGOR()
POP B
MOV M,C
DCR H
MOV M,B
DCR H
POP B
MOV M,C
MOV H,E
MOV M,B
INR H
POP B
MOV M,C
INR H
MOV M,B
MOV h,a
POP B
MOV M,C
INR H
MOV M,B
INR H
POP B
MOV M,C
DCR L
.endmacro
.macro DRAW_ODD_LINE_IVAGOR()
MOV M,B
DCR H
POP B
MOV M,C
DCR H
MOV M,B
MOV H,E
POP B
MOV M,C
INR H
MOV M,B
INR H
POP B
MOV M,C
MOV H,D
MOV M,B
INR H
POP B
MOV M,C
INR H
MOV M,B
DCR L
.endmacro
.function DS_ivagor
DrawSprite_ivagor:
; store SP
LXI H,0 ; (12)
DAD SP ; (12)
SHLD @restoreSP+1 ; (20)
; HL = BC
MOV H, B ; (8)
MOV L, C ; (8)
; BC = (HL), HL +=2
MOV C, M ; (8)
INX H ; (8)
MOV B, M ; (8)
INX H ; (8)
; SP = HL
SPHL ; (8)
; HL = DE
XCHG ; (4)
; D = screen X
MOV D, H ; (8)
; E = second screen X
MVI A, $20 ; (8)
ADD D ; (4)
MOV E, A ; (8)
; A = third screen X
MVI A, $20 ; (8)
ADD E ; (4)
; X += 2
INR H ; (8)
INR H ; (8)
; (160)
; screen format
; DRAW_EVEN_LINE_IVAGOR
; 1st screen buff : 3 <- 2 <- (1)
; 2nd screen buff : (4) -> 5 -> 6
; 3rd screen buff : (7) -> 8 -> 9
; y--
; DRAW_ODD_LINE_IVAGOR
; 3nd screen buff : 12 <- 11 <- 10
; 2nd screen buff : (13) -> 14 -> 15
; 1st screen buff : (16) -> 17 -> 18
; y--
; repeat
; HL = screen address (X + 2, Y)
; SP = sprite data + 2
; D - 1st screen buff X
; E - 2nd screen buff X
; A - 3rd screen buff X
; first line
MOV M,C
DCR H
MOV M,B
DCR H
POP B
MOV M,C
MOV H,E
MOV M,B
INR H
POP B
MOV M,C
INR H
MOV M,B
MOV h,a
POP B
MOV M,C
INR H
MOV M,B
INR H
POP B
MOV M,C
DCR L
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
DRAW_ODD_LINE_IVAGOR()
DRAW_EVEN_LINE_IVAGOR()
; 24th line
MOV M,B
DCR H
POP B
MOV M,C
DCR H
MOV M,B
MOV H,E
POP B
MOV M,C
INR H
MOV M,B
INR H
POP B
MOV M,C
MOV H,D
MOV M,B
INR H
POP B
MOV M,C
INR H
MOV M,B
@restoreSP: LXI SP, TEMP_ADDR ; restore SP (12)
RET
.endfunction
Код:;----------------------------------------------------------------
; draw a sprite (24x24 pixels)
; author: parallelno
; method: zig-zag
; in:
; BC sprite data
; DE screen address (x,y)
.macro DRAW_EVEN_LINE_PARALLELNO2(_moveOneLineDown = true)
POP B ; 1st screen space
MOV M,C
INR H
MOV M,B
INR H
POP B
MOV M,C
MOV H,E ; 2nd screen space
MOV M,B
DCR H
POP B
MOV M,C
DCR H
MOV M,B
MOV H,A ; 3rd screen space
POP B
MOV M,C
DCR H
MOV M,B
DCR H
POP B
MOV M,C
.if _moveOneLineDown == true
DCR L
.endif
.endmacro
.macro DRAW_ODD_LINE_PARALLELNO2(_moveOneLineDown = true)
MOV M,B ; 3rd screen space
INR H
POP B
MOV M,C
INR H
MOV M,B
MOV H,E ; 2nd screen space
POP B
MOV M,C
DCR H
MOV M,B
DCR H
POP B
MOV M,C
MOV H,D ; 1st screen space
MOV M,B
DCR H
POP B
MOV M,C
DCR H
MOV M,B
.if _moveOneLineDown == true
DCR L
.endif
.endmacro
.function DS_parallelno2
DrawSprite_parallelno2:
; store SP
LXI H, 0 ; (12)
DAD SP ; (12)
SHLD @restoreSP + 1 ; (20)
; SP = BC
MOV H, B ; (8)
MOV L, C ; (8)
SPHL ; (8)
; D, E, A are initial X for
; the 1st, the 2nd, the 3rd screen buffs
XCHG ; (4)
MVI A, 2 ; (8)
ADD H ; (4)
MOV D, A ; (8)
ADI $20 ; (8)
MOV E, A ; (8)
ADI $20 ; (8)
; (108) total
; screen format
; DRAW_EVEN_LINE_PARALLELNO2()
; 1st screen buff : 1 -> 2 -> 3
; 2nd screen buff : 4 <- 5 <- (6)
; 3rd screen buff : 7 <- 8 <- (9)
; y--
; DRAW_ODD_LINE_PARALLELNO2()
; 3nd screen buff : 12 -> 11 -> 10
; 2nd screen buff : 13 <- 14 <- (15)
; 1st screen buff : 18 <- 17 <- (16)
; y--
; repeat
; HL - 1st screen buff XY
; SP - sprite data
; D - 1st screen buff X + 2
; E - 2nd screen buff X + 2
; A - 3rd screen buff X + 2
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2()
DRAW_EVEN_LINE_PARALLELNO2()
DRAW_ODD_LINE_PARALLELNO2( false)
@restoreSP: LXI SP, TEMP_ADDR ; restore SP (12)
RET
.endfunction
VV и v06x точно, emu80v2 думаю тоже. b2m, когда я проверял последний раз, вел себя слегка девиантно, но не так существенно, чтобы повлиять на тестирование разрывов.
ivagor, в моем варианте прерывания тоже разрешены.
А как восстанавливать испорченный фрагмент спрайта? Есть разные варианты, но я не увидел или не понял, какой именно здесь.
- - - Добавлено - - -
Если конкретнее, то проблема возникнет, если прерывание попадет в промежуток от SPHL до DRAW_EVEN_LINE_PARALLELNO2(). Вероятность этого не такая уж большая, чтобы проблема сразу проявилась, но при долгой работе это произойдет.
Если мы ещё ничего не считали со стека, то sp указывает на начало спрайта. Если прерывание произойдет, то оно испортит те два байта перед данными спрайта, а это не страшно.
А если прерывание произойдёт чуть позже, то адрес возврата затрёт спрайт. Использование регистров BC позволяет всегда хранить эти два байта на регистрах и восстановить их в обработчике прерывания.
А перед самым началом спрайта делается двухбайтовая дырка, из которой мы никогда ничего не читаем. Затрёт -- так затрёт.
Можно уж было дать и развёрнутое объяснение. Вас же и другие люди читают.
Sandro, Извини пожалуйста. спасибо что дал развёрнутое объяснение. Но хочу уточнить что притензия не принимается, так как я отвечал не всем, а только
05ivagor
В этой теме кажется кто-то написал о том что нужно держать 2 safety байта до данных. И KTSerg в этой теме выложил свой вариант исходника где так же это было. Поэтому я посчитал что вроде бы все уже этой используют. Сорян.Цитата:
Да, jerri предложил этот вариант в теме robotz (PPC). Точнее он предложил оставлять между спрайтами (минимум) по 2 байта. Просто переход от варианта с "любым" размещением спрайтов к "разреженному" произошел без комментария.
Базырь в новом v06x позволил увидеть механизм возникновения артефакта. В игре, как я понимаю, есть ограничение области рисования спрайта по высоте, если на него наезжает шторка. Если при движении главгероя по вертикали шторка наехала на спрайт врага, то под шторкой останется нестертый фрагмент. Пока его не видно, но когда главгерой сместится по вертикали обратно и врага в это время не будет рядом со шторкой, то из под нее проявится нестертый фрагмент. По моему разумению возможный вариант борьбы - разрешить рисование спрайта под шторкой, чтобы он продолжал затирать.