(бухай): программируй
148 subscribers
465 photos
96 videos
3 files
65 links
Мысли, дегустация и код
Download Telegram
Сегодня я написал генератор случайных чисел.
Нууу.. как написал. Скорее спер отсюда:

https://codebase64.org/doku.php?id=base:ax_tinyrand8

Единственное, что я поменял - это процесс генерации зерна. Вместо того, чтобы брать значение из регистра A (аккумулятор) для последующей генерации, я взял значения таймера.
Нижний байт таймера лежит в регистре $dc04, а верхний - в регистре $dc05. Банальным XOR этих двух чисел получаем нужное зерно.

А дальше сделал все по инструкции и проверил на 27 тысячах итераций. Паттернов как будто особо не видно, да и вероятностное распределение по полученным числам тоже в пределах нормы.

Есть и второй вариант, и он довольно специфический.
Дело в том, что в Commodore есть звуковой чип, и один из каналов этого чипа умеет генерировать шумы. А шумы - это ничто иное, как псевдослучайные числа. Но такой подход я использовать не хочу, все таки звуковой канал есть звуковой канал.
🔥4
Продолжаю описывать всякие полезные для будущей ролевой системы функции.

И сейчас написал функцию для конвертации бинарных значений в так называемое Binary Coded Decimal (BCD).
BCD - это довольно полезная штука, например, для вывода на экран числовых значений.

В стандартном виде числа хранятся в одном байте памяти в диапазоне $00 — $FF в шестнадцатеричной системе, то есть от 0 до 255 в десятичной. А BCD позволяет представить десятичные числа в шестнадцатеричном формате.

Для этого один байт надо разбить на две части по 4 бита: 0000 0000.
4 бита могут хранить значения от 0 до 15 (то есть от $00 до $0F). Но в десятичной системе нет цифр A,B,C,D,E,F, поэтому нужно ограничиться значениями от 0 до 9 на каждые 4 бита.

Например, при использовании BCD значение $87 будет непосредственно равно 87, а не 135, как в шестнадцатеричной системе.

И как удобно, что процессор 6502 поддерживает такой формат чисел на аппаратном уровне.
Для того, чтобы процессор считал в десятичном формате надо поставить флаг D (decimal) в регистре статусов. например, чтобы сложить два числа, надо сделать так:
sed ; выставляем флаг
clc
lda #$49
adc #$20
cld ; убираем флаг

На выходе в регистре A будет значение $69
👍3🔥1
И возникает закономерный вопрос: А почему бы не хранить в таком виде все значения?

Во-первых, в одном байте в таком случае можно хранить всего до 100 значений: от $00 до $99.
Во-вторых, процессор 6502 в таком режиме может только вычитать и складывать числа. Все другие операции будут производиться в обычном двоичном формате.
Например, для увеличения адреса на 1, я уже не могу сделать так:
inc $nnnn

Вместо этого придется делать что-то такое:
sed
clc
lda $nnnn
adc #$01
sta $nnnn
cld

Это не очень удобно.

Зато очень удобно выводить числа на экран. Числа в экранной памяти кодируются значениями от $30 до $39. Просто прибавляем BCD значение (левую и правую части байта) к $30 и выводим на экран нужную цифру.

Поэтому я и решил написать функцию, которая конвертирует бинарные числа в BCD.
Получилось что-то такое:
binary_to_bcd_converter
pha
lda #0
sta decimal_result
sta decimal_result+1

sed
ldx #8
@dec_loop
pla
dex
bmi @end
asl
pha
bcc @dec_loop

clc
lda decimal_result+1
adc decimal_tb_lo,x
sta decimal_result+1
lda decimal_result
adc decimal_tb_hi,x
sta decimal_result

jmp @dec_loop
@end
cld
rts

decimal_result
byte $00,$00
decimal_tb_lo
byte $01,$02,$04,$08,$16,$32,$64,$28
decimal_tb_hi
byte $00,$00,$00,$00,$00,$00,$00,$01


В аккумуляторе хранится двоичное число, например $1000 1001 (136 в десятичной)
Сдвигаем все биты влево в цикле. И каждый бит при этом попадает в carry (флаг переноса).
Если carry равен 1, то надо просто прибавить к результату соответствующий разряд:
0 бит — 1
1 бит — 2
2 бит — 4
3 бит — 8
4 бит — 16
5 бит — 32
6 бит — 64
7 бит — 128

В итоге, полученное число окажется в адресах результата:
decimal_result — $01
decimal_result+1 — $36

И эти значения можно уже без проблем вывести на экран
1🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Как-то в последнее время разработка туго идет. Но я сделал случайные встречи с врагами с вероятностью в 10% при каждом движении (при этом, если игрок упирается в стену, то случайная встреча не просчитывается). Враг при этом тоже выбирается случайным образом из четырех доступных на одном уровне.
При столкновении появляется текстовое окно с параметрами противника и его именем.

Ну, в данный момент у меня нарисован только один спрайт, поэтому единственный враг - это компьютер😄 Но главное, что работает=)
🔥4
Ну и самое главное - у меня осталось еще куча памяти.
Вся игра вместе с кодом и данными занимает 18 385 байт.
Если посчитать доступное место без памяти под Kernal ROM (местный BIOS), то выходит 3529 байт с $1286 по $204f и 27647 байт с $6400 по $cfff.
А это в сумме целых 31176 байт!
Начал рисовать персонажей)
Но сразу же возникла проблема. Из-за того, что все персонажи у меня помещаются в 4 спрайта, то два цвета на каждый спрайт должны быть одинаковыми.
Но можно указать и третий цвет - уникальный для каждого спрайта.

Вот и получается, что я могу:
— сделать высокого персонажа и указать всего 3 цвета (коричневый и телесный - общие, синий - уникальный для каждого спрайта). И у меня не получится, например, сделать штаны другого цвета.
— нарисовать персонажа-карлика (чтобы вся одежда поместилась в два квадрата) и добавить еще один цвет😂

В общем, надо потренироваться рисовать все так, чтобы можно было использовать хотя бы 4 цвета из 6 возможных=)
Что ж...
Я думал, это будет более устрашающе😅

Но, к сожалению, при текущем подходе можно сделать только так.

Конечно, можно увеличить количество спрайтов, например, до 6.
Сейчас планируется 8 изображений оружия, 6 изображений патронов, аптечка и броня. А это уже 4 Кб.
Прибавляем сюда спрайты на уровне - 8 изображений - 2 Кб.

Очень уж затратны эти спрайты в плане памяти.
🔥3👏1
Так, ну я решил проблему со спрайтами врагов.
Вспомнил, что спрайты в Commodore можно увеличивать в два раза на аппаратном уровне. То есть сами пиксели остаются теми же, но изображение становится больше.

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

Теперь остается надеяться, что мне больше не понадобятся аппаратные спрайты для чего-либо еще, а то придется писать функции для их мультиплексинга (размножения)...
🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
Я так и не нашел софт, который позволял бы правильно выставить цвета для каждого знакоместа при рисовании в режиме Multicolor Bitmap.
Поэтому приходится все делать самому.

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

Ну и конечно нужно будет написать скрипт для сохранения изображения в формат ассемблера
🔥2❤‍🔥1
В общем, основные функции редактора уже готовы.
Можно выбрать для каждого знакоместа три цвета (при этом можно копировать цвета из одного знакоместа в другой). Каждый цвет выставляется левой, правой и средней кнопками мыши.

Ну и написал функции для сохранения изображения в JSON, загрузки из JSON и импорта в формат ассемблера.
И вроде все работает.

Не скажу, что рисовать по одному пикселю очень удобно, но зато не приходится вручную выставлять цвета для 2000 байт и пиксели для 8000 байт=)
Возможно потом напишу функции для отрисовки линями, квадратами и для заливки
🔥3❤‍🔥1
Вот это очень хорошо)
Были идеи что-то такое сделать, но я так и не постиг процессорную магию
❤‍🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Начал добавлять в игру оружие.
Пока готовы только три штуки: газовый ключ, пистолет и нейлер.
Если оружие недоступно, то отрисовывется его силуэт. А если игрок подобрал оружие, то иконка становится цветной.
Выбирать оружие можно только в бою, и при этом окантовка иконки меняет цвет (а в память загружаются параметры нового оружия).

Ну и из мелочей:
Полностью дописал скрипт для конвертации карты из Tiled. Теперь он сохраняет не только триггеры и саму карту, но и спрайты

Разработка стала немного нестабильной.
Из-за того, что все сейчас связано друг с другом: оружие, битвы, враги и т.д., то приходится одновременно писать все везде и сразу=)
🔥4❤‍🔥1
Кошка решила проверить, как дела с игрой :)
❤‍🔥6👎1
Решил добавить вот такие кнопки в левой части экрана. Вот они, сверху вниз:
— Первые четыре: атака, защита, бегство и ничегонеделание (по поводу последней еще думаю);
— Следующие две: аптечка и броня (принять внутривенно);
— Две последние: сохранить и загрузить игру.

Но я хочу об одной интересной штуке рассказать. Для этих кнопок я использовал переменную их состояния. Сперва я хотел сделать 5 кнопок, но это оказалось не очень удобно.
Сейчас код выглядит вот так:
@check_key_down
cmp #83
bne @check_key_up
clc
lda fight_choose_action
adc #32
sta fight_choose_action
jmp @end
@check_key_up
cmp #87
bne @check_key_use
sec
lda fight_choose_action
sbc #32
sta fight_choose_action
jmp @end

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

Такую штуку я использовал для поворота игрока, только там я прибавлял и вычитал 64 (256/64 = 4 стороны света).

Более того, это используется повсеместно. Например в Doom угол поворота игрока зашит в переменную размером 1 байт (так называемый byte angle), где привычные нам 360 градусов представлены в виде однобайтовой переменной (от 0 до 255).
🔥4❤‍🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Полдня переписывал функции выбора оружия (и отрисовки селектора). Раньше это была куча функций для каждого оружия, сейчас написал универсальные (правда пришлось добавить несколько таблиц с указателями и использовать много самомодифицирующегося кода).

Еще написал функции для переключения кнопок в левой части (переключаются последовательно с помощью Q и E). Кнопка выбирается пробелом (но дальнейший функционал еще конечно не описан).

Но осталась одна большая проблема.
Надо как-то иначе считывать клавиатуру. Сейчас за это отвечают системные функции SCNKEY и GETIN. Но, если быстро нажимать на кнопки, то они как-будто бы помещаются в очередь. В моем случае это критично, потому что процесс рендеринга занимает довольно много времени, и за это время в очередь можно поместить несколько действий, которые выполнятся по завершении отрисовки.
Это, конечно, портит впечатление. И на видео заметно, как в одном месте я сам запутался в управлении.
🔥4❤‍🔥1