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

Есть возможность сохранять данные на дискету. То есть я могу теоретически записать основные параметры и считывать их при загрузке игры.
Как это будет работать на практике, пока что непонятно.

Второй вариант - использовать пароли прямо как в старых играх на денди, да:)
1
Ну что ж, я починил артефакт между графической и текстовой зонами.
Раньше в прерывании я считывал значения регистров и командами AND и ORA включал или выключал нужные биты.

lda $d011
ora #%00100000
sta $d011
lda $d016
ora #%00010000
sta $d016
lda $d018
ora #%00001000
sta $d018

Теперь я просто беру нужное значение и сразу кладу его в регистр:
        lda     #$3b
sta $d011
lda #$d8
sta $d016
lda #$1d
sta $d018

Занимает куда меньше циклов, и видимо из-за этого процессор успевает отработать прерывание до выхода за пределы линии. Докинул недостающие циклы NOP-ами, и все заработало
2👍2
Я тут подумал, что можно использовать вкладки для текстовой зоны!
Это позволит запихнуть больше информации на экран.

Нарисовал то, что я примерно хочу видеть в итоге:
1. Слева будет компас, который показывает направление движения (вполне себе замена для мини-карты). Правда, мне не очень нравится, как он выглядит, буду перерисовывать.
2. Справа - поле Player с количеством здоровья, брони и ключами, которые есть у игрока.
3. Посередине будут меняться 4 вкладки, при этом вкладка Fight будет появляться, если игрок вступил в бой.

Конечно, для этих вкладок надо будет выделять память:
64 байта для всех позиций компаса (4*4*4)
520 байт для всех четырех вкладок (26*5*4)
Многовато, но зато экран будет информативным
🔥32
Ну, теперь это уже стало больше похоже на игру.
Правда зачем нам ролевая система и игровые механики, если теперь буковки рисуются=)
2
This media is not supported in your browser
VIEW IN TELEGRAM
Ну и видео.
Стрелка правильно показывает направление (что можно использовать в подсказках), а под конец можно увидеть, как появляется ключ, когда я беру его из шкафа.
Там же можно увидеть, что вывод текста пока что не работает, как собственно и переключение вкладок. Но уже что-то
2👍2🤯1
Media is too big
VIEW IN TELEGRAM
Видеоотчет за последние несколько недель:)
2
И как-то так теперь выглядит карта в Tiled. То есть можно прям в программе забить нужные позиции триггеров и даже назвать из как полагается.

А Tiled хорош тем, что сохраняет все карты в формат JSON или XML. Мне JSON больше по душе, его легче читать.
И довольно простым питоновским скриптом все это дело можно перенести в формат ассемблера.
2👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Сегодня сделал не так много:

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

Во-вторых - добавил все текстовые меню и переключения между ними.

И возникла одна идея. В левой пустой части экрана сделать индикаторы изменений в текстовых меню. Допустим, игрок нашел триггер, который выводит текстовое сообщение. Само сообщение отправляется в буфер, а в левой части экрана появляется конверт. Мол, иди смотри, что тебе там написали.
🔥1
А еще я долго размышлял, как лучше сделать переключения оружия.
Все оружие будет в левой части экрана в квадратиках.
Сперва я думал сделать это спрайтами, но у меня уже занято 4 спрайта. Пришлось бы их размножать, вовремя переключать цвета и т.д.
Потом я подумал, что можно было бы рисовывать оружие попиксельно. Но одна зона для каждого оружия занимает 72 байта, что в сумме дает 576 байт (если не учитывать, что должно быть несколько состояний: оружие доступно/оружие выбрано/оружие недоступно).

Поэтому самый оптимальным решением я вижу банальную смену цветов в знакоместах.
Например:
серый/серый - оружие недоступно;
игрок подбирает оружие - меняем на белый/белый - оружие доступно;
игрок выбирает оружие - меняем на синий/красный - оружие выбрано.

Это позволит моментально выбирать нужное оружие и переключать его отображение в HUD без изменения пикселей.
🔥3
Сегодня я написал генератор случайных чисел.
Нууу.. как написал. Скорее спер отсюда:

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