"Unhinged" trackmo engine

Ну, пока в соседнем топике разбирается многопоточность, посмотрим на такую гораздо более простую вещь, как систему управления событиями в трекмо.

В этом топике я опубликую двиг, разработанный для «Unhinged», и использованный позже как обслуживающий в «Марио».

Зачем это? Дело в том, что пресловутое flow требует от дизайн-мейкера постоянно вводить как новые эффекты, так и их развитие в процессе своего течения.
Соответственно, код демо должен быть настраиваемым — предоставьте себе контролы, которые позволят вам менять внешний вид того же эффекта, который уже на экране. И применяйте их в течении демо именно в тот момент, когда они будут иметь максимальное воздействие на зрителя.

ДАО ГОВОРИТ :)
Главная цель движка трекмо — это Контроль выполнения демо.
Контроль должен быть реализован изменением состояния кода демо в процессе её выполнения (показа), путём изменения значений памяти в её подпрограммах в нужный нам момент, либо изменением вызываемой процедуры (что может быть переходом в следующую часть).

Пример использования:


Предоставленный в тексте код полностью отвязан от платформенных зависимостей.

В основу положим следующий принцип.

Основной цикл демо выглядит крайне просто:

		ei
loop		call wait_frame
main_proc	call 0
		jp loop

wait_frame здесь — это аналог halt, это ожидание прихода фреймового прерывания — нового кадра 50 фпс.
main_proc — адрес, указывающий на вызов в основном цикле.

Основной цикл предназначен для вызовов инициализации эффектов и вызовов «проигрывателей» эффектов демо и представляет собою всего лишь одинокий call, у которого будет меняться адрес.

В прерывании вызывается обработчик состояния трекмо, который обрабатывает свой поток управляющих команд:
_init — команда, которая должна вызывать инициализацию эффекта, который будет выполняться (особенность: команда выполняется ровно один фрейм, за который нужно всё успеть, и ровно один раз!);
_call — команда, указывающая вызов обработки текущего эффекта (просто указывает, какой адрес поставить в вызов в основном цикле по адресу main_proc+1);
_wait — команда ожидания нужного количества фреймов, при её выполнении другие команды не обрабатываются;
_poke — команда для патча памяти, призванная как раз изменять переключатели в демо, которые изменяют вид на экране и прочее. После её выполнения переходим на следующую команду, не ожидая фрейма.

Это — основной набор команд для движка, с помощью которого уже можно управлять выполнением демо.
Каждая команда являет собою ни что иное, как номер с возможными последующими параметрами

Для облегчения их описания я использовал предложенный на хайпе многоуважаемым introspec способ — макросы:

		MACRO	_wait	time
		db	0
		dw	time
		ENDM
		MACRO	_poke	addr, value
		db	1
		dw	addr
		db	value
		ENDM
		MACRO	_call	addr
		db	2
		dw	addr
		ENDM
		MACRO	_init	addr
		db	3
		dw	addr
		ENDM



В «Unhinged» я использовал расширенный набор команд, с помощью которых мне было гораздо проще нею управлять и её настраивать.

Вот пример их использования — в данном случае это самое начало демо:
  • инициализируем эффект первоначальной маски
  • устанавливаем отображение на экран маски под номером 0
  • устанавливаем отступ
  • включаем / отключаем нужные для начала эффекты в плеере эффектов (вырубаем трясучку и глитчи текста, включаем уровень глитча маски 1)
  • устанавливаем плеер эффектов основного цикла — mask_unsync
  • ждём 2 фрейма
  • устанавливаем новую позицию маски на экране
  • ждём 2 фрейма
  • ...
  • маска в центре
  • ждём проигрывания 4х паттернов заданного размера фреймов

music_pattern	equ #60
off 		equ 0
on		equ 1

proc_db
		_init mask_bw_inits
		_mask 0
		_mask_pos center-#40
		_poke mask_bw_fader+1, on
		_poke words_tiles_vert_glitch+1,off
		_poke words_t0_glitch_switch+1,off
		_poke words_t1_glitch_switch+1,off
proc_loop
		_poke glitch_level+1, 1
		_call mask_unsync
                _wait 2
		_mask_pos center-#30
		_wait 2*2
...
		_mask_pos center
		_wait music_pattern*4

Демо началось.

Давайте посмотрим на конвеер, который будет обрабатывать все эти команды.
Здесь:
frames — это счётчик фреймов, пройдённых от старта демо,
proc_db — список команд выполнения, завершается признаком #ff
en_pop — предназначен для снятия последующего адреса в рег. DE.
frames_wait — фрейм, после которого нужно начать обрабатывать следующую команду.

int		push af
		push hl
		push de
		push bc
frames		ld hl,0
		inc hl
		ld (frames+1),hl
frames_wait	ld de,1
		or a
		sbc hl,de
		jp c,en_ex		

en_proc		ld hl,proc_db
		ld a,(hl)
		cp #ff
		jr nz,en_proc0
		ld hl,0
		ld (frames+1),hl
		inc l
		ld (frames_wait+1),hl
		ld hl,proc_loop
		ld (en_proc+1),hl
		jr en_proc

en_proc0	or a		; _wait
		jr nz,en_proc1
		call en_pop
		ex de,hl
		ld (frames_wait+1),hl
		ex de,hl
		jr en_proc_ex

en_proc1	dec a		; _poke
		jr nz,en_proc2
		call en_pop
		ld a,(hl)
		ld (de),a
en_proc_cycle	inc hl
		ld (en_proc+1),hl
		jr en_proc

en_proc2	dec a		; _call
		jr nz,en_proc3
		call en_pop
		ex de,hl
		ld (main_proc+1),hl
		ex de,hl
		jr en_proc_ex

en_proc3	dec a		; _init
		jr nz,en_proc4
		call en_pop	
		ld (en_proc+1),hl
		ex de,hl
		ld (main_proc+1),hl
		jr en_ex

en_proc4	inc hl
en_proc_ex	ld (en_proc+1),hl

en_ex        	pop bc
		pop de
		pop hl
		pop af
		ei
		ret


en_pop		inc hl
		ld e,(hl)
		inc hl
		ld d,(hl)
		inc hl
en_pop_ex	ret


Система выглядит довольно просто и понятно, как мне кажется.
Гораздо важнее — именно Ваша гибкость при её применении, и Ваша фантазия.

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

_wait music_pattern*12
...
_wait music_pattern*16


Предоставленного в статье материала должно хватить для начала работы, но я так-же публикую все исходы демо:
Скачать сорцы Unhinged

2 комментария

avatar
full soundtrack, в деме версия покороче.
  • VBI
  • +2
avatar
мда… чувствую себя старым пердуном — настолько отстал )
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.