Как создавалась Plasma is possible!
Идея создания небольшого интро 256б возникла случайно, когда мне на
глаза попалась работа Pisaas
(1k intro). Принцип простой, поэтому проще пояснить на исходном тексте.
Я постараюсь пояснить на отдельных участках кода:
device zxspectrum128
ORG #8100
begin
dec b; этот трюк раскусит каждый: при вызове RANDOMIZE USR NNNN выполняется код С BC=NNNN. в моем случае получается ld bc,#8000
push bc
ld h,c,l,c;ld hl,0; сейчас я начну подготовку - генерация синуса и спрайта.
ld de,hl;ld de,0
sinlp1: add hl,de;формирование первой части синуса, создается как аппроксимация парабол.
ld a,h
ld (bc),a
inc e
jr nc,noincd
inc d
noincd:
inc c
ld a,c:cp #41
jr nz,sinlp1
;--------------------1st;часть вторая периода синуса - отражение первой четвертинки
ld e,#40
ld d,b
sinlp2:
ld a,(de)
ld l,a
ld a,$10
sub l
ld (bc),a
inc c
dec e
jr nz,sinlp2
;зеркальное копирование таблицы синуса
; ld c,a;bc=$8081,de=$8000
ld e,d;$8080
sinlp3:
ld a,(de)
ld (bc),a
dec e
inc c
jr nz,sinlp3
;теперь нужно построить спрайт, который будет использоваться при эффекте:

;-----------draw plasma----------
pop hl;ld hl,#8000, потому что значение $8000 было сохранено, экономия 1 байта.
ld de,$c000
ld c,h
drw1:
ld a,(hl)
and 7
push de,bc
or d:ld d,a
ld b,4
drw2:
ld a,(de):or c:ld (de),a
inc d:res 3,d:djnz drw2
pop bc,de
or a:rrc c:jr nc,nonextX
inc e
nonextX:
ld a,l:add a,4:ld l,a;почему шаг равен 4? используется 8 байта спрайта, 8*8=64, 256/4=64, так получится "бесшовный" спрайт, т.е. частички можно собрать рядом.
ld a,e:cp 9
jr nz,drw1
;здесь, как можно догадаться, спрайт разбросан по памяти $C000-$C700.
plasm:
ei:halt:di
ld de,$4020
push bc
ld (storesp+1),sp
;как работает эффект: на каждой линии высота линии спрайта определяется как ( s(a)+s(b) ) and 7
;здесь s() - массив значения синуса, a и b - переменные
rowlp:
ld h,$80; HL указывает на таблицу синусов
ld l,c;B и C - это переменные a и b
ld a,(hl)
ld l,b
add a,(hl)
and 7
or $C0
ld h,a
ld l,0
ld sp,hl;готов адрес линии спрайта
inc c; переменные изменятся для следующей линии.
dec b,b
exx
pop af,bc,de,hl;эти регистры хранят 8 байт линии спрайта
exx
ex de,hl;стэк переадресуется на экран
ld sp,hl
exx
push hl,de,bc,af
push hl,de,bc,af
push hl,de,bc,af
push hl,de,bc,af; заполнена вся линия
exx
ex de,hl;переход на следующую линию на экране
dec de
INC D:LD A,D
AND 7:jr nz,$+12
LD A,E:ADD A,#20:LD E,A:jr c,$+6
LD A,D:SUB 8:LD D,A
ld A,D
inc de
cp $58:jp nz,rowlp;условие проверки цикла
storesp:ld sp,0
ld hl,$C000;теперь нужно сдвинуть линии спрайта
ld b,8
test:
push hl
or a
rr(hl):inc l
rr(hl):inc l
rr(hl):inc l
rr(hl):inc l
rr(hl):inc l
rr(hl):inc l
rr(hl):inc l
rr(hl)
pop hl; это заумный код для зацикленного спрайта
jr nc,nopix
set 7,(hl)
nopix:
inc h:djnz test
;-------------------------------AY------------
; заодно отправлю дамп регистров, который создан с помощью утилиты Vitamin'a
LD HL ,aydump
LD D ,$0D
aylp: LD BC ,$FFFD
OUT (C) , D
LD A ,(HL)
LD B ,$BF
OUT (C) , A
INC HL
DEC D
JR NZ ,aylp
;---------------------------------------------
pop bc;восстановлено начальное значение переменных, теперь они изменятся, плазма будет двигаться
ld a,b:add a,0-4:ld b,a;inc b,b,b,b
dec c,c,c
jp plasm
aydump:
db $0E,00,$42,$10,$10,$10,$38,00,$08,$4A,$08,$49,$20
end
display /d,end-begin
savesna "!void.sna",begin
; savebin "plasma.bin",begin,end-begin
Ну вот, на этом и всё, для того, чтобы ускорить вывод на экран, нужно развернуть цикл и явно задать адреса экрана.
Но в 256б это не влезло. Вышло итак неплохо.