Неделю не занимался игрой, но время пришло...
Я все пытаюсь отгородить себя как-то от написания ролевой системы, потому что до сих пор не понимаю, что с ней делать.
Поэтому я решил оптимизировать уже написанный код. И первыми в очереди оказались функции выбора оружия.
До этого я действовал максимально тупо: проверял, какая из кнопок клавиатуры (от 1 до 8) нажата, и под каждую кнопку была отдельная функция:
И так далее, и так далее. И это действительно было очень тупо.
Но сейчас я немного оптимизировал код:
И это вся функция.
Дело в том, что кнопки от 1 до 8 имеют кодировку от 49 до 57. И остается только вычесть из нажатой кнопки 49. Получится цифра от 0 до 7.
Потом надо проверить, выходит ли за границы 7 эта цифра (иначе, нажата другая кнопка).
Потом проверяем, доступно ли оружие и не хотим ли мы выбрать то же оружие, что держим в руках.
Если все это проходит проверку, то убираем селектор с экрана, переносим данные нового оружия из одного места в памяти в другое и рисуем селектор в новом месте.
И вроде выглядит все равно криво (и я уверен, что это можно оптимизировать), но памяти это сэкономило немало.
Я все пытаюсь отгородить себя как-то от написания ролевой системы, потому что до сих пор не понимаю, что с ней делать.
Поэтому я решил оптимизировать уже написанный код. И первыми в очереди оказались функции выбора оружия.
До этого я действовал максимально тупо: проверял, какая из кнопок клавиатуры (от 1 до 8) нажата, и под каждую кнопку была отдельная функция:
; ++++++++++ CHECK FOR WEAPON CHANGES KEY PRESSES ++++++++++
check_change_weapons_keys
lda key_pressed
bne @check_wrench
jmp @end
; проверка кнопки "1"
@check_wrench
cmp #49
bne @check_pistol
; если ключ доступен
lda weapons_avaliable
beq @check_pistol
lda curr_weapon_number
beq @check_pistol ; если оружие != ключ
ldy #$ce ; убрать текущее оружие
jsr choose_weapon_draw
lda #0
sta curr_weapon_number
jsr select_weapon_data ; выбрать ключ
ldy #$cd
jsr choose_weapon_draw ; нарисовать селектор ключа
jmp @end
@check_pistol
cmp #50
bne @check_nailer
; если пистолет доступен
lda weapons_avaliable+1
beq @check_nailer
lda curr_weapon_number
cmp #1
beq @check_nailer ; если оружие != пистолет
ldy #$ce
jsr choose_weapon_draw
lda #1
sta curr_weapon_number
jsr select_weapon_data
ldy #$cd
jsr choose_weapon_draw
jmp @end
И так далее, и так далее. И это действительно было очень тупо.
Но сейчас я немного оптимизировал код:
check_change_weapons_keys_new
lda key_pressed
sec
sbc #49 ; кнопка "1" = 49 в десятичной
; если ни одна из кнопок "1" - "7" не нажата
cmp #7
bcs @end
tax
stx $05 ; временная переменная для регистра X
lda weapons_avaliable,x ; если оружие доступно
beq @end
lda curr_weapon_number ; если новое оружие != текущее оружие
cmp $05
beq @end
ldy #$ce ; убрать текущее оружие
jsr choose_weapon_draw
ldx $05
stx curr_weapon_number ; переместить данные нового оружия в память
jsr select_weapon_data
ldy #$cd ; нарисовать селектор нового оружия
ldx $05
jsr choose_weapon_draw
@end
rts
И это вся функция.
Дело в том, что кнопки от 1 до 8 имеют кодировку от 49 до 57. И остается только вычесть из нажатой кнопки 49. Получится цифра от 0 до 7.
Потом надо проверить, выходит ли за границы 7 эта цифра (иначе, нажата другая кнопка).
Потом проверяем, доступно ли оружие и не хотим ли мы выбрать то же оружие, что держим в руках.
Если все это проходит проверку, то убираем селектор с экрана, переносим данные нового оружия из одного места в памяти в другое и рисуем селектор в новом месте.
И вроде выглядит все равно криво (и я уверен, что это можно оптимизировать), но памяти это сэкономило немало.
🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
И снова не ролевая система=)
Написал функции для аптечки и брони. Ничего сложного: если предмет есть, то выводится сообщение об его использовании и вычитается 1. Ну и в инвентаре количество меняется.
Если нет, то выводится сообщение об его отсутствии.
Правда пока что аптечки и куски брони ничего не лечат и не чинят. Все это в будущем, когда бои будут готовы.
Пришлось помучиться с выбором игровых кнопок. Раньше кнопка выбиралась пробелом. Но почему-то оказалось, что всю клавиатуру стандартные функции считывают как just pressed (одно нажатие), а именно пробел - как просто pressed (непрерывное нажатие).
Из-за этого аптечки съедались моментально, и я долго не мог понять, в чем дело. Когда перекинул выбор игровой кнопки на Enter, все заработало.
Написал функции для аптечки и брони. Ничего сложного: если предмет есть, то выводится сообщение об его использовании и вычитается 1. Ну и в инвентаре количество меняется.
Если нет, то выводится сообщение об его отсутствии.
Правда пока что аптечки и куски брони ничего не лечат и не чинят. Все это в будущем, когда бои будут готовы.
Пришлось помучиться с выбором игровых кнопок. Раньше кнопка выбиралась пробелом. Но почему-то оказалось, что всю клавиатуру стандартные функции считывают как just pressed (одно нажатие), а именно пробел - как просто pressed (непрерывное нажатие).
Из-за этого аптечки съедались моментально, и я долго не мог понять, в чем дело. Когда перекинул выбор игровой кнопки на Enter, все заработало.
🔥5
А что же с игрой?
А пока ничего😔
Последнее время не идёт особо, видимо надо передохнуть немного. Возвращаюсь к коду раз в неделю, делаю какую-то мелочь и забиваю ещё на 7 дней.
Останавливает то, что надо ролевую систему придумывать, и я не знаю, с какого конца к ней подступиться.
Но без дела пытаюсь не сидеть. Начал внезапно для себя изучать новый язык программирования - Gо. Хотел что-то похожее на С++, но не С++ 😅
И думаю все таки написать нормальный редактор графики для коммодора на нем. Все таки питоновский вариант "на коленке" даже выкладывать куда-то стыдно, да и тормозит он.
А пока ничего😔
Последнее время не идёт особо, видимо надо передохнуть немного. Возвращаюсь к коду раз в неделю, делаю какую-то мелочь и забиваю ещё на 7 дней.
Останавливает то, что надо ролевую систему придумывать, и я не знаю, с какого конца к ней подступиться.
Но без дела пытаюсь не сидеть. Начал внезапно для себя изучать новый язык программирования - Gо. Хотел что-то похожее на С++, но не С++ 😅
И думаю все таки написать нормальный редактор графики для коммодора на нем. Все таки питоновский вариант "на коленке" даже выкладывать куда-то стыдно, да и тормозит он.
👍1😐1🤗1
This media is not supported in your browser
VIEW IN TELEGRAM
Пусть игра и не идет, зато Go зашел. Действительно прикольный язык. Не очень сложный, код получается очень чистый (чего не скажешь о каком-нибудь Python). Короче я искал что-то похожее на C++, я его нашел=)
Но есть и особенности:
1. Нельзя объявить переменную, а потом ее не использовать. Компилятор ругается. А я очень люблю объявлять переменные на будущее при разработке. Привыкну, думаю.
2. Нет классов, а все ООП на структурах построено. И... это нереально удобно. Когда я пытался учить C#, меня оттолкнуло именно то, что все в нем - объект, а язык построен полностью вокруг ООП. В Go это все реализовано непринужденно.
3. Указатели... И тут я хочу сказать, что ассемблер и Commodore очень помогли в понимании того, что такое указатели, и зачем они нужны. Я так понял, что в Go нельзя делать с указателями любую дичь на свете (типа арифметики с адресами и указателей на функции). Здесь они используются в основном в структурах. И это тоже очень удобно.
Я начал переносить на Go редактор графики для Commodore 64, который писал на Pyhton недавно, и уже могу похвастаться. В реализации на Python редактор жутко тормозил (но и написан он был на коленке). В текущей реализации на Go он работает в 60 FPS.
Для графики я использую фреймворк Ebiten Engine (не смейтесь над названием). Это что-то вроде PyGame для Python, но с меньшим набором возможностей (например, мне пришлось с нуля писать систему коллизий с мышкой для экранных кнопок).
Но я постоянно помню про игру. Я не могу про нее просто так забыть, с учетом того, сколько времени я на это потратил. Так что скоро будет обновление...
Но есть и особенности:
1. Нельзя объявить переменную, а потом ее не использовать. Компилятор ругается. А я очень люблю объявлять переменные на будущее при разработке. Привыкну, думаю.
2. Нет классов, а все ООП на структурах построено. И... это нереально удобно. Когда я пытался учить C#, меня оттолкнуло именно то, что все в нем - объект, а язык построен полностью вокруг ООП. В Go это все реализовано непринужденно.
// Объявляем транспортное средство
type Vehicle struct {
doors int
wheels int
}
// Объявляем машину, которая тоже транспортное средство
type Car struct {
Vehicle
engine string
}
// Транспортное средство умеет ездить. (v *Vehicle) значит, что это метод структуры Vehicle. При этом мы передаем эту структуру по ссылке (указателю)
func (v *Vehicle) drive() {
fmt.Println("I'm driving")
}
3. Указатели... И тут я хочу сказать, что ассемблер и Commodore очень помогли в понимании того, что такое указатели, и зачем они нужны. Я так понял, что в Go нельзя делать с указателями любую дичь на свете (типа арифметики с адресами и указателей на функции). Здесь они используются в основном в структурах. И это тоже очень удобно.
Я начал переносить на Go редактор графики для Commodore 64, который писал на Pyhton недавно, и уже могу похвастаться. В реализации на Python редактор жутко тормозил (но и написан он был на коленке). В текущей реализации на Go он работает в 60 FPS.
Для графики я использую фреймворк Ebiten Engine (не смейтесь над названием). Это что-то вроде PyGame для Python, но с меньшим набором возможностей (например, мне пришлось с нуля писать систему коллизий с мышкой для экранных кнопок).
Но я постоянно помню про игру. Я не могу про нее просто так забыть, с учетом того, сколько времени я на это потратил. Так что скоро будет обновление...
👍5
Весь день писал функцию для конвертации двоичных 16 битных чисел в десятичный формат (BCD, не так давно про него говорил).
Растянулось все так из-за моей невнимательности. Обожаю ассемблер=)
Если вкратце, то программа проверяет каждый бит числа и, если он равен 1, то прибавляет к финальному результату число, соответствующее позиции этого бита. Например:
1000 0000 0000 0000 - 32768;
0000 0000 1000 0000 - 128;
0000 0000 0000 0001 - 1.
Вся программа выглядит как-то так. Не очень презентабельно, но зато работает. Все на таблицах и самомодифицирующемся коде:
Ну и на картинке я взял число $54C3, или 21 699 в десятичной. Каждая цифра этого числа помещается в отдельный адрес памяти для того, чтобы потом было удобно переносить их на экран.
А все это нужно для ролевой системы. Как минимум, количество опыта игрока будет именно 16 битным числом.
Растянулось все так из-за моей невнимательности. Обожаю ассемблер=)
Если вкратце, то программа проверяет каждый бит числа и, если он равен 1, то прибавляет к финальному результату число, соответствующее позиции этого бита. Например:
1000 0000 0000 0000 - 32768;
0000 0000 1000 0000 - 128;
0000 0000 0000 0001 - 1.
Вся программа выглядит как-то так. Не очень презентабельно, но зато работает. Все на таблицах и самомодифицирующемся коде:
decimal_to_bcd_converter_16bit
lda #$00
ldy #4
@clear_loop
sta decimal_result_16bit,y
dey
bpl @clear_loop
ldx #15
@loop_1
clc
rol binary_input
rol binary_input+1
bcs @add_digits
@next_loop_1
dex
bpl @loop_1
@end
rts
@add_digits
clc
ldy #4
lda dec_tbl_lo,x
sta @set_address+1
lda dec_tbl_hi,x
sta @set_address+2
@set_address
lda $ffff,y
adc decimal_result_16bit,y
cmp #$0a
bcc @next
sbc #$0a
@next
sta decimal_result_16bit,y
dey
bpl @set_address
jmp @next_loop_1
Ну и на картинке я взял число $54C3, или 21 699 в десятичной. Каждая цифра этого числа помещается в отдельный адрес памяти для того, чтобы потом было удобно переносить их на экран.
А все это нужно для ролевой системы. Как минимум, количество опыта игрока будет именно 16 битным числом.
🔥1
https://dtf.ru/2532867
Опробовал тут Daggerfall Unity. Не смог устоять и написал небольшую статейку по этому поводу
Опробовал тут Daggerfall Unity. Не смог устоять и написал небольшую статейку по этому поводу
DTF
Daggerfall Unity - от людей и для людей — Александр Логачев на DTF
Недавно я узнал, что в релиз вышла фанатская оболочка для TES: Daggerfall, которая переносит великую игру на движок Unity.
🔥4❤🔥1
И снова не ролевая система...
Хотя предпосылки к ней уже есть. Я нашел исходники ремастера Doom RPG на PC, и там много чего можно подглядеть. Но главное - почти все параметры игрока и врагов умещаются в 8 бит, что очень упрощает работу.
https://github.com/Erick194/DoomRPG-RE
А так - немного реструктурировал код. Теперь в нем проще ориентироваться и работает немного быстрее. Ну и дописал функции для аптечек и ремонтного набора. Теперь они восстанавливают здоровье и броню игрока до максимального значения (пришлось ввести еще две переменные).
Ну и продолжаю писать редактор графики на Go. Очень крутой язык, всем советую. Пока что не так много сделал, но уже можно порисовать одним цветом, удалить пиксель, и включить/выключить сетку и селектор знакоместа. Но хочу сказать, что код на Go уже получается более понятным и чистым, чем на Python, А еще оно не тормозит в отличие от Python (ну или это я более ответственно к делу подхожу😅)
Хотя предпосылки к ней уже есть. Я нашел исходники ремастера Doom RPG на PC, и там много чего можно подглядеть. Но главное - почти все параметры игрока и врагов умещаются в 8 бит, что очень упрощает работу.
https://github.com/Erick194/DoomRPG-RE
А так - немного реструктурировал код. Теперь в нем проще ориентироваться и работает немного быстрее. Ну и дописал функции для аптечек и ремонтного набора. Теперь они восстанавливают здоровье и броню игрока до максимального значения (пришлось ввести еще две переменные).
Ну и продолжаю писать редактор графики на Go. Очень крутой язык, всем советую. Пока что не так много сделал, но уже можно порисовать одним цветом, удалить пиксель, и включить/выключить сетку и селектор знакоместа. Но хочу сказать, что код на Go уже получается более понятным и чистым, чем на Python, А еще оно не тормозит в отличие от Python (ну или это я более ответственно к делу подхожу😅)
🔥3👍2❤🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Продолжаю писать редактор графики для Commodore на Go.
В отличие от Python (точнее PyGame) приходится прописывать новые структуры, например, экранные кнопки.
Ну и я стараюсь все делать красиво, поэтому работа идет несколько медленно. Но зато все работает в 60 FPS.
Уже можно выбрать 3 цвета для каждого знакоместа, переключить цвет фона. Немного переписал управление для удобства. В общем, работа потихоньку движется=)
В отличие от Python (точнее PyGame) приходится прописывать новые структуры, например, экранные кнопки.
Ну и я стараюсь все делать красиво, поэтому работа идет несколько медленно. Но зато все работает в 60 FPS.
Уже можно выбрать 3 цвета для каждого знакоместа, переключить цвет фона. Немного переписал управление для удобства. В общем, работа потихоньку движется=)
❤🔥6
This media is not supported in your browser
VIEW IN TELEGRAM
Начались подвижки в ролевой системе. Наконец-то...
В общем я немного полазил по исходному коду Doom RPG и не придумал ничего лучше, чем просто скопировать некоторые моменты.
Вышло как-то так:
Здоровье и броня:
P.S. Добавил еще поле NXP - количество опыта для получения следующего уровня.
P.P.S. Для теста кинул эту функцию на кнопку SAVE=)
В общем я немного полазил по исходному коду Doom RPG и не придумал ничего лучше, чем просто скопировать некоторые моменты.
Вышло как-то так:
Здоровье и броня:
така, защита, уклонение и точность:
8 бит.
30 при старте игры.
Увеличение каждый уровень: текущее значение + 3 + (random % 3).
Максимум - 100 (в оригинале было 99, но у меня есть 3 свободных знакоместа)
А
пыт:
8 бит.
При старте равны 16, 12, 14, 16. И так всегда.
Увеличивается как: текущее + 1 + (random % 2).
Максимум 100.
О
Ну и в итоге все это выводится на экран (как и меняется текст всех показателей во вкладках меню).
16 бит.
Количество опыта для нового уровня в оригинале высчитывается как: (номер уровня * 20) + 60.
Не понял, зачем так сложно, если можно просто прибавлять 20.
P.S. Добавил еще поле NXP - количество опыта для получения следующего уровня.
P.P.S. Для теста кинул эту функцию на кнопку SAVE=)
🔥4❤🔥2
Начал разбираться в устройстве 2600, и это конечно очень забавная консоль.
Во-первых, процессор 6507, может адресовать всего 8Кб памяти.
Во-вторых, у нас есть всего 128 байт (sic!) оперативки. Да уж, память и правда была в те времена дорогая.
В-третьих, размер картриджа всего 4Кб.
Если посмотреть на адреса, то это выглядит как-то так:
TIA - это местный видеочип, а RIOT - оперативка, ввод/вывод и таймер.
Но есть и плюс - PAL версия (как у меня) поддерживает аж 104 уникальных цвета. В Commodore 64, для сравнения, палитра состоит всего из 16 цветов. Хотя кажется, что все это будет с кучей ограничений.
Буду разбираться дальше=)
Во-первых, процессор 6507, может адресовать всего 8Кб памяти.
Во-вторых, у нас есть всего 128 байт (sic!) оперативки. Да уж, память и правда была в те времена дорогая.
В-третьих, размер картриджа всего 4Кб.
Если посмотреть на адреса, то это выглядит как-то так:
0000-002C TIA (Write)
0030-003D TIA (Read)
0080-00FF RIOT RAM
0280-0297 RIOT I/O, TIMER
F000-FFFF ROM
TIA - это местный видеочип, а RIOT - оперативка, ввод/вывод и таймер.
Но есть и плюс - PAL версия (как у меня) поддерживает аж 104 уникальных цвета. В Commodore 64, для сравнения, палитра состоит всего из 16 цветов. Хотя кажется, что все это будет с кучей ограничений.
Буду разбираться дальше=)
👍5❤🔥1
Это жесть, господа=)
Полдня потратил на то, чтобы добавить на экран спрайт. А все потому что это не Commodore, где ты просто кидаешь в нужные регистры позицию, изображение и цвета спрайта, а видеочип налету все подхватывает.
Здесь у спрайтов вообще нет такого понятия, как позиция. Все приходится вычитывать исходя из линии растра.
Более того, каждый кадр процессор должен четко следовать за лучом растра (если на определенной линии ему ничего делать не надо, то есть возможность притормозить работу процессора до следующей линии). На каждую линию нам дается всего 76 тактов, за которые надо успевать что-либо сделать с логикой или графикой.
Короче, я сам еще не до конца понимаю, что тут происходит, но это довольно интересно.
Полдня потратил на то, чтобы добавить на экран спрайт. А все потому что это не Commodore, где ты просто кидаешь в нужные регистры позицию, изображение и цвета спрайта, а видеочип налету все подхватывает.
Здесь у спрайтов вообще нет такого понятия, как позиция. Все приходится вычитывать исходя из линии растра.
Более того, каждый кадр процессор должен четко следовать за лучом растра (если на определенной линии ему ничего делать не надо, то есть возможность притормозить работу процессора до следующей линии). На каждую линию нам дается всего 76 тактов, за которые надо успевать что-либо сделать с логикой или графикой.
Короче, я сам еще не до конца понимаю, что тут происходит, но это довольно интересно.
😱5❤🔥1
А вот, как выглядит код для определения позиции спрайта по Y. С позицией по X там еще веселее, и я пока не разобрался.
И данные спрайта. Нули в начале для очистки регистра, если спрайт рисовать не надо.
; цикл для каждой линии отрисовки на экране
ldx #0
graph_loop
; вычитаем позицию спрайта из текущей линии
; и сравниваем с высотой спрайта
txa
sec
sbc #50
cmp #13
bcc next
lda #0
next
;кидаем в регистр спрайта значение из таблицы со смещением
;(#0, если спрайт рисовать не надо)
tay
lda player_data,y
sta GRP0
;тоже самое с цветом
lda player_colors,y
sta COLUP0
; тормозим процессор до следующей линии отрисовки
stx WSYNC
; меняем цвет фона
stx COLUBK
inx
cpx #242
bne graph_loop
И данные спрайта. Нули в начале для очистки регистра, если спрайт рисовать не надо.
player_data
.byte #0
.byte %00111100
.byte %01111110
.byte %01011101
.byte %01111110
.byte %00111100
.byte %00011000
.byte %11111111
.byte %00011000
.byte %00011000
.byte %01100110
.byte %01100110
.byte %01100110
player_colors
.byte #0
.byte #$2c
.byte #$2c
.byte #$2c
.byte #$2c
.byte #$2c
.byte #$2c
.byte #$d2
.byte #$d2
.byte #$64
.byte #$64
.byte #$64
❤🔥1