Главная Отключить капчу Каталог NSFW Настройки

Общий раздел

Ответить в тред Ответить в тред
<<
Назад | Вниз | Каталог | Обновить | Автообновление | 178 189 6
Аноним  Вс 07 июл 2024 23:09:51 265645 1
Доска Настроения.jpeg 28Кб, 393x404
393x404
Ну, и как разрабатывать?

Я знаю немного язык программирования С.

Нужно курить мануалы как с драйвером монитора. Предполагаю, что на FreeBSD должен быть некий набор системных вызовов для работы с монитором. Есть конечно уже готовые api типо Xlib, но у нас нет права получать зависимости на пустом месте. Xorg довольно устарел. Игра должна быть независима от какого-то всратого Xorg.
Итак, поняв как работать с драйвером монитора, мы можем выводить визуальную информацию, закрашивать пиксели. Следовательно нам нужно создать алгоритмы 3D графики. Алгоритм брезенхема, Z-буфер и тд. и тп.
Теперь самое сложное. Как, собственно, разработать игру? Для этого нужно задаться вопросом, а что такое вообще игра?
Вот персонаж в игре - это некий конечный автомат, который получает события с клавиатуры, и под них меняет своё состояние. В это же время, события могут поступить не только с клавиатуры, но и сами собой, по каким-то внутренним причинам. В конечном итоге, событие может быть просто фактом истечения некотороего времени. И игра, это некоторая сложная система, которая все эти факторы как-то организует.
Как сделать самую простую 3d игру с самой простой архитектурой, чтобы потом просто немного расширить функционал? Создание игры получается сводится к срзданию своего xorg.
Аноним  Пн 08 июл 2024 09:29:38 266287 2
>>265645 (OP)
Если ты хочешь вкатиться в разработку (похоже что) движка, попробуй сначала сделать 2D игру.
Игра - это так называемый геймлуп, игровой цикл который гоняется по кругу в разных сценах. Даже так - каждая игровая сцена это свой небольшой геймлуп, который ожидает ввода пользователя. Также можно смотреть именно на дизайн игры с точки зрения цикла запустил->поиграл->подкачался->начал заново. Или иначе. Игра не привязана к наличию персонажа, кстати.
Конкретно по твоему вопросу - посмотри что такое так называемые ивенты и шины ивентов. Вкратце можно реализовать так - каждый промежуток времени прогоняется вся шина (динамический массив), и ты либо изменяешь состояние события, либо выполняешь его окончательно. Событие выполнено - супер! Удаляй его. При необходимости добавляй ивенты, которые

>могут поступить не только с клавиатуры, но и сами собой, по каким-то внутренним причинам

или да, по пользовательскому вводу.
Самая простая реализация событий в твоем случае. Но, имхо, самая большая проблема щас будет раскурить графоний. Строй абстракции на абстракциях, хуле.
Аноним  Пн 08 июл 2024 18:41:39 268068 3
photo_2024-06-1[...].mp4 147Кб, 496x496, 00:00:00
496x496
>>266287
>Если ты хочешь вкатиться в разработку (похоже что) движка
Я убеждён что движок и игра, это практически одно и то же. Конечно, можно назвать несколько примеров, когда на одном и том же движке делались разные игры, например Contract Wars на Unity. Но в любом случае, тот кто создал Contract Wars был вынужден изучить весь api движка. То есть движок - вещь неотделимая от игры. И если ты хочешь создать игру, то ты должен создать движок. Либо, если же ты профессионал, ты можешь использовать чужой движок, проанализировав код или документацию на него.
Клепание поделок без владения документацией и опыта работы - это весьма юеспдлжгл
>Конкретно по твоему вопросу - посмотри что такое так называемые ивенты и шины ивентов. Вкратце можно реализовать так - каждый промежуток времени прогоняется вся шина (динамический массив)
Это получается событийно-ориентированное программирование?
>Но, имхо, самая большая проблема щас будет раскурить графоний.
А я считаю, это лишнее. Почему никому не нравится ранний 3D, типо того же краш бандикута, doom, quake. Достаточно ведь примитивного затенения, текстур и сглаживания по гауссу. На этом визуал можно оставить.

>>265741
>Нынче модно смотреть гайды по пятому анрилу
Бесплодное занятие. Особенно смотреть. На видеороликах мало чему научиться можно. На них можно только посмотреть, и заинтересоваться.
Аноним  Пн 08 июл 2024 21:48:07 268610 4
>>268068
>Я убеждён что движок и игра, это практически одно и то же.
Почему? Как ты и говоришь, дорогой анон, можно создать на одном движке разные игры. А ещё можно на разных движках делать одну и ту же игру. Движки ж есть разные, одни заточены под жанр (Adventure Game Studio), другие под конкретную игру (пример Factorio), третьи под большинство игр разных студий (пример Unity).
Зазубривание кода и доскональное знание чужого движка нужно только для "больших" игр для "больших" студий. Типо хуйоверсов. Которым, похоже, было лень делать своё двигло. Остальные же говнокодят (ультракилл лол) и крутят лавешечку.
> Это получается событийно-ориентированное программирование?
Да. Думаю лучший выбор для начала.
Аноним  Пн 08 июл 2024 22:19:52 268670 5
>>268610
>Почему?
Ну, ты впринципе прав, но мне казалось движок делается под конкретный жанр. Можно ли на idtech2 сделать рпг? Кажестя будто бы idtech создан чисто для шутеров. Если вычленять элементы, убирать ненужное, оптимизировать модицикацию под рпг, то это ведь уже получиться другой движок, пускай местами взятый с idtech.
Тот же goldsrc много чего у doom перенял. Но доделал своё.
Если взять многожанровые движки, типо Unity, то ведь сам по себе Unity это стек технологий.На каждом этапе каждой технологии может возникнуть ошибка, и если ты новичок, увы, эта ошибка останется с тобой навсегда. Получается, что если ты не профессионал и не понмаешь что к чему, то для тебя этот Unity ничем полезен быть не может, и даже в каком-то смысле вреден.
Аноним  Сб 27 июл 2024 21:44:07 320119 6
@girlfeedgoals.jpeg 55Кб, 736x729
736x729
Ну допустим я хочу сделать игру. (Забудем ту фигню что я написал в предыдущих постах).
Начнём с самого простого: как мне нарисовать что-то на мониторе?.
Вопрос в лоб.

Если мы уже умеем что-то рисовать на мониторе, то далее уже ясно что делать: создавать алгоритм брезенхема, оптимизировать его, создавать Z буфер, создавать модель трёхмерного пространства которую потом проецировать на двухмерный канвас экрана. В общем, там уже много чего можно придумать.

Но как чьёрт возьми мне что-то вывести на экран? Ясно, что есть OpenGL. Я не хочу OpenGL. Также есть Xlib, Xcb. Я не хочу пользоваться xorg тем более. Просто принципально не хочу наворачивать готовые нестандартные решения. Они может быть и лучше, но это не правильно, так нельзя. Нельзя просто сказать "вот эта сторонняя непонятная щтючка всё сделает за меня". Это невежество.

У меня есть операционная система. ПОПРОШУ ЗАМЕТИТЬ: она умеет выводить буквы на экран даже без Xorg, без OpenGL, в общем-то даже без встроенной видеокарты. То есть ей даже видеокарта не нужна. ОС умеет работать с монитором, она умеет закрашивать пиксели на мониторе. У неё должен быть какой-то стандартный интерфейс для работы с монитором, какие-то системные вызовы для работы с драйвером файла "/dev/монитор".

Несколько погуглив я нашёл только linux framebuffer. Во-первых, такого на BSD я не нашёл. Во-вторых, на википедии не написано понятным языком что это такое. Написано что просто какой-то "интерфейс". Это очень посредственный ответ на вопрос, который не добавляет смысла ни на йоту.

Прочёл 60 страниц мануала на FreeBSD - такая нудятина. Ноль полезной информации. Всё какие-то глупости бесполезные пишут типо "ооо установить бсд вы можете и на иксбокс... [спустя страницу] установка бсд на иксбокс сложна и весьма бесполезна, поэтмоу обсуждать мы её не будем". Ок. Нахуй мне эта информация?! И вот 60 страниц такой абсолютной нудятины, рассуждений про какие-то системные требования, история юникс. Зачем?? Почему нельзя конструктивно подходить, и писать по делу. Лушче бы они в истории юник рассказали чем UFS от старой S51K отличается. Но нет, там зачем-то упомянуты эти две системы, но мне это ни о чём не говорит, для меня это тупо названия, которые ничего не значат. Пафоса много, а толку ноль. Ввод-вывод перенаправлять я по-итогу по википедии научился, а не по мануалам. Стандартные команды Unix, тоже по википедии прочитал. А в книге по бсд одна вода, про то как охуенно ей пользоваться. Пиздец. Охуенно было бы, если бы меньше рассказывали про то как ей охуенно пользоваться и по-больше бы пользовались.

И по-больше бы рассказывали о самой системе, а не пичкали её тысячью сторонних программ. Я вот действительно не понимаю: Я установил FreeBSD. Я хочу поставить себе Discord. Я интересуюсь, есть ли клиент дискорда на фряхе? И попадаю на ветку форума, где пользователя настоятельно просят установить себе дополнительное ядро линкус, и с него запустить Discord. Или электрон. Или браузер. ЗБС. А нахуй тогда вообще этот BSD нужен, если вы на 80% захламляете его какими-то сторонними сервисами? В чём у вас Unix-wayность и свобода, если вы просто зависимы от Xorg. Просто большая часть софта не способна работать без Xorg. Я действительно не понимаю. Давайте не будем пиздеть, давайте будем поступать честно: установил Unix - выжимаешь максимум из системы, а не устанавливаешь подярдо пинуса и не сидишь с линупс, всем показывая что у тебя фрибзде. Шизофрения. Пользоваться нужно операционной системой, а не тремя виртуалками внутри ещё одной виртуалки под электроном.

Если кто знает годных книг по устройству и API юниксов, то был бы признателен.
Аноним  Сб 27 июл 2024 22:16:19 320190 7
И не надо посылать меня на три буквы. Потому что я прав.
Я понимаю, если бы я работал под Windows, то действительно, ядро windows не предназначено чтобы туда лез непрофессионал. Но уж извините, если я поставил себе свободную операционную систему, рассчитаную, в том числе, и на обучающихся, то я имею полное право знать как работают драйверы монитора на FreeBSD. Ну это просто факт. Для этого ведь она и создана, чтобы студенты изучали именно её, а не обмазывались виртуалками чтобы запустить тот же софт что и под виндой.
Аноним  Вс 28 июл 2024 22:11:15 322661 8
image.png 44Кб, 305x482
305x482
image.png 8Кб, 490x536
490x536
Весь день убил на поиск драйвера монитора FreeBSD и так ничего и не нашёл. Я так и не понял какое устройство из /dev отвечает за монитор. Более того, я почему-то даже нигда не нашёл внятного описания для каждого из устройств. Каждое гуглил - монитора так и не нашёл.
Конечно, тут есть /dev/dri - это как раз иксорговский модуль ядра для работы с драйверами графических устройств. Но это не то. Мне надо прям чтоб моя графика работала на голой системе.
Ну и ладно. Решил немного сдаться, хоть что-нибудь поделать, скачал SDL. Он хотя бы пустое окошко выдаёт. Хоть чёто поделаю.
Может стоит забить просто и танненбаума почитать, вроде там вообще всё подробно про операционные системы рассказано.
Аноним  Вс 28 июл 2024 22:41:05 322710 9
Помниться, кстати, я как-то пробовал запустить SDL на голой системе... и он мне выдал рендер в ASCII буквоках. Меня это одновременно и порадовало и расстроило. Порадовало тем, что этот SDL хотя бы работает без xorg (хотя в описании написано что для него необходим xlib). То есть это что-то рабочее и стабильное. Расстроило тем, что он выводит всё в псевдографику, даже не работает с драйвером монитора. Псевдографику и на ncurses лучше делать. То есть без иксов он весьма бесполезен.
Аноним  Пн 29 июл 2024 11:07:14 323155 10
image.png 28Кб, 663x192
663x192
Кстати, авторам на заметку
>вам не нужно полностью понимать как это работает. Просто используйте этот код
НИ ЗА ЧТО не пишите вот такое! У меня сразу ухудшается к вам отношение. Вы что, считаете что я какой-то подневольный раб, что не имею права знать как этот код работает? Это буквально звучит как "Посиди сычуша, покопируй код, пока умные дяди его разрабатывают.". Неуважение! Откуда такое завистливое скотское отношение к обучающимся, мол "а вот это тебе знать не нужно". Всё нужно знать! Потому что я ЛИЧНОСТЬ и я делаю как я хочу, а не как уёбищный автор статьи этого хочет.
Аноним  Пн 29 июл 2024 12:40:33 323253 11
image.png 104Кб, 735x771
735x771
image.png 79Кб, 359x500
359x500
Охуительный курс ргб, пацаны. А вы знали что rgb это красный зелёный и голубой? а? а? знали?
Пиздец. Эту хуйню ещё во втором классе знают. Просто, блядь, автор издевается. Он считает меня за какого-то умственно неполноценного деграданта.
Что дальше? Дальше он познакомит нас "немного с математикой" и начнёт рассказывать про 1+1 = 2. Ну бля... ну не пишите вот так..... это же троллинг какой-то, а не уроки.
Лучше бы он сказал из чего состоит структура типа SDL_Surface. Лучше бы он рассказал что он своим кодом сделал. Я вот вижу что он тупо вычислил цвет для разной глубины 8, 16, 24 и 32. А зачем? Это же процедура. Она должна как-то рисовать пиксель. Что она делает то, как она его рисует. Опишите процесс, блядь. Это было бы намного полезнее этих ваших дебильтных "так диточки, а вы знали что RGB это типо типлет на экране? знали да? злани". Буквально подача на уровне тупорылой школьной училки. Какая мне разница чё у меня за триплет, мудак. Может у меня вообще кинескоп, или терминал. Хули ты доебался до RGB. Пиши про SDL, блядь. Я урок по SDL читаю, или про что?
Урод.
Аноним  Пн 29 июл 2024 12:53:05 323270 12
Я имелл виду, что после switch case там идёт завершение процедуры. SDL_MapRGB который вначале, похоже что подгоняет 24-битный rgb под тот формат, что в структуре screen указан по-умолчанию.
bufp - буфер пикселя мб. Указатель на байт.
>bufp = (Uint8 *)screen->pixels + y*screen->pitch + x
>*bufp = color
Вот это последняя строчка в каждом кейсе.
То есть типо мы узнаём какой-то адрес, может быть shared памяти, и туда заносим нужный цвет. Пока что предположение только такое.
Аноним  Пн 29 июл 2024 13:34:57 323344 13
image.png 66Кб, 657x543
657x543
>Заметьте, что это нужно только при работе с пикселями, но никак не со спрайтами
Какими впизду "спрайтами", я не пью газировку.
Это шутка. Просто, я вот не понимаю зачем авторы статей это пишут. Ранее нигде не было упомянуто что такое "спрайт". И тут посередине текста какашечка про то, что что-то не работает со спрайтами. Зачем это писать? Чтобы что? В этом предложении ровно 0 информации для меня. Вот когда будешь писать про спрайты, тогда и напиши. Нах это в первый урок пихать я не понимаю.
>проверяет надо ли блокировать экран
Какой экран? Что блокируют? Лучше бы ты сказал что всё это значит. Да и функция SDL_LockSurface(SDL_Surface *screen) принимает тип SDL_Surface, а не экран. SDL_Surface то это поверхность, это может быть и окно. Он тогда заблокирует получается окно, а не экран, судя по названию. Это же LockSurface, а не LockMonitor.
Правильное построение урока, должно выглядеть так: вначале должны быть описаны объекты, которыми работает библиотека, а потом уже что-то ковырять.
Вот когда я читал документацию на Xorg, там было чётко написано, как устроен x-server, что такое "событие", что такое "окно", что такое "монтиор", чем они отличаются. Тут же просто автор ведёт рассуждение просто как училка информатики: общие фразочки какие-то вставлены тупо для количества буков, но сути никакой это не добавляет, да и код он считает что нужно тупо копировать. От этого больше всего горит жопа, когда автор говорит: "скопируйте код", чувствуется наёб. Типо, я для того и пришёл, чтобы обучаться коду, а не пространным рассуждениям.
При том, когда подробно рассуждают это хорошо. Например, я слышал что у танненбаума, глава про сети начинается с рассуждений про физические являения передачи сигналов. Ну, это как бы не по теме, но всё равно хорошо, всё равно хорошо что в поднобностях всё описывается, лишним не будет так сказать. А тут просто никаких подробностей, просто "шмяк.. короче ёпта рендер"
Аноним  Пн 29 июл 2024 14:42:48 323554 14
image.png 24Кб, 649x112
649x112
image.png 1370Кб, 1200x865
1200x865
>Если скомпилировать этот код, то получим черное окно, которое появится и быстро исчезнет.
>Попробуйте добавить флаг SDL_FULLSCREEN и посмотреть что произойдет.
>А теперь давайте рисовать.
Кто нибудь мне объяснит как эти три предложения взаимосвязаны? Чиво, блядь.
>"Если мы скомпилируем код, то получим черное окно"
да ну нахуй, а я не додумался откомпилирвать пример с окном ранее.
>"Попробуйте добавить флаг SDL_FULLSCREEN и посмотреть что произойдет"
Будет фулскрин. И... чО?????? Окно что ли пропадать перестанет? Нет. Также пропадает. Флаг, сука, называется Fullscreen, выше идёт описание что этот флаг для фулскрина, и автор посчитал НЕОБХОДИМЫМ сообщить нам, что нужно поставить этот флаг и проверить что будет. Зачем?? Чтобы что?? Что ты этим добъёшься?? Какая учебная польза от этого?? Автор, будто бы училка, которая пытается впарить школьникам какой-нибудь фокус, типо она работает не зря.
>А теперь давайте рисовать.
Да, охуенно. Сделали хуйню какую-то, ни разу не разрбрались, а теперь будем рисовать. Что к чему? Вахуи.
Аноним  Пн 29 июл 2024 15:12:27 323586 15
image.png 85Кб, 646x847
646x847
Этот гайд меня разозлил. Теперь буду срать просто на всё подряд, потому что могу. Всё равно сюда никто не заходит.

Вопрос к додикам, которые постоянно говорят, что "ты изобретаешь свой движок, зачем ты это делаешь если есть готовый".
Вот, заходим на оффициальный сайт, и смотрим "что такое SDL". Там написано, что вот SDL это бибилиотека даёт доступ к аудио, видео, тредам, системному таймеру итд итп.
Собственно вопрос.. а что по вашему делает ядро операционной системы?! Не то же ли самое, а? Собственно, заходим на сайт FreeBSD, и смотрим. Видим абсолютно тоже: операционная система даёт доступ к процессам, потокам ввода-вывода, файловым системам, сокетам, и главное "даёт доступ к переферийному оборудованию". Что это значит? Это значит, что в твоём ядре ОС уже должна быть возможность работать со всеми поддерживаемыми устройствами. Монитор - поддерживаемое устройство? Безусловно, да. Мы же работаем на мониторе даже без специальных графических драйверов. Установите чистую фряху и экран-то работать будет! Терминал то буковки показывает. Тут, может кто-то подумать, что я ищу /dev/tty, но нет, это эмулятор терминала. А я ищу именно монитор.
Я бы понял, если бы у меня был настоящий терминал, то тогда, безусловно, возможно никакой графики выводить было бы просто невозможно. Но у меня ЭМУЛЯТОР терминала. То есть существует какой-то примитивный графический драйвер, со своей системой шрифтов (у которых кстати расширение .fnt вроде, а не truetype), на которой уже и основана программа tty. И это ТОЧНО можно перепрограмировать. Знаете почему? Потому что я установил svgalib, без всяких специальных драйверов, и моя тестовая программа даже запустлась. Запустилась, правда, некорректно: вместо чёткой картинки я получил какие-то смятые пиксели и шум. Но это уже сильно отличается от стандартных букв терминала, то есть монитором можно пользоваться напрямую. SVGAlib работает с драйвером монитора напрямую, в обход видеокарты.
Безусловно, SDL, OpenGL, Unity, это наверняка хорошие инструменты. Я не хочу говорить про них ничего плохого, я уверен их делали грамотные и обученные люди. Я уверен эти технологии позволяют пользоваться ресурсами компьютера более рационально, тот же SDL_Init воспринимает флаги для рендера как на харде, так и на софте (то есть наверное SDL можно заставить всё на чистом проце рендерить, без помощи видеокарты. Но мне абсолютно не важно что это за технология. Если можно обойтись без неё - нужно обходиться без неё. Если можно заменить что-то собственным велосипедом - это делать НУЖНО. Уже потом, когда будет потребность в чём-то, нужно использовать фреймворки итд и тп. А получать на пустом месте зависимости от SDL когда тебе дано ядро ОС - это невежество, это слабость. Так если бы уроки по SDL были бы нормальными, я бы ещё прогнулся под эту библиотеку, в надежде что я хотя бы какой-то полезный опыт приобрету. Но это обезьяне "скопируйте код" это скучная поебота, а не опыт. Не нужно копировать код. Мы, блядь, должны заниматься изучением кода, а не чистописанием, и копипастингом.
Аноним  Пн 29 июл 2024 15:39:20 323627 16
image.png 195Кб, 363x306
363x306
image.png 458Кб, 640x350
640x350
Я поначалу даже string.h не использовал. Делал функции для строк вручную. Только потом я заметил что string.h довольно более гибкая, удобная, а глваное, что идёт почти с любым компилятором С.
Также и с math.h. Поначалу, возведение в степень я делал вручную. Потом, мне пришла мысль, что возможно сущестувют более оптимальные алгоритмы возведения в степень, и я начал использовать pow().
ncurses я практически сразу принял без торга, потому что он довольно компактный и выглядит как что-то хорошее.
Тем не менее, со всеми принятыми допущениями зависимости минимальны: зависимость от стандартной библиотеки ничтожна, так как библиотека С практически намертва склеена с операционными системами. Формально наверное их можно как-то разделить, но по сути пользоваться ОС без библиотеки С - это какое-то фричество, ведь в мануале FreeBSD сделан целый раздел поствящённый стандартной библиотеке. Так, что использовать стандартную библиотеку вполне допустимо.
Почему тогда ncurses? это же не часть стандартной библиотеки? Ну, ncruses стабильная, компактная, и удобная. Вот в общем-то и всё. Я могу работать и без Ncurses, просто перепрограммировав драйвер терминала. Таким образом, использовать ncurses, это мой свободный, осознанный выбор.
Использовать же SDL, это выбор вынужденный. Я не могу вывести графику без него. Это меня и напрягает в первую очередь. Это не выбор, это уход от разработки. Вот задумайся, сегодня ты попустился и сказал себе: "ну ладно, я не буду пытаться изобретать велосипед, я буду делать в Unity", а что мешает завтра же тебе сказать: "ну ладно, а я не буду делать свои 3d-модели, я возьму бесплатные из ассетов, я не буду делать свои текстурки, я возьму бесплатные, я не буду делать свои звуки, я возму с сайта, я не буду делать код, я скопирую его у того человека". Приехали. А что, ты нахуй будешь делать сам??? Делай тогда игры в "конструкторе 3d игр", вперёд, пиздуй. (если кто не вкурсе, это в детстве была такая дебильная программа, где тупо по-пунктам можно выбрать модельки и звуки, и на выходе получить какую-то однотипную фигню). Давай. Пиздуй делать игры в редакторе космических приключений Spore. Вот это игропром.. уровня кал говна.
Помнится, я в детстве как раз из-за этого бросил пытаться делать игры, потому что ютуб просто заполнен роликами про "давайте сделаем бродилку в юнити.. повторяйте за мной".И был абсолютно прав. Это бесполезное говнище. А изобретение велосипедов - единственный путь, стать хорошим механником.
Аноним  Пн 29 июл 2024 16:10:13 323698 17
>>323253
Я вот только сейчас задумался, а зачем он каждый кейс в {} заводит?
case: это же метка, всё равно что goto label:. Там не нужны скобки, он же тупо начинает с этой части кода.
Аноним  Пн 29 июл 2024 17:14:00 323781 18
image.png 7Кб, 539x342
539x342
>>323698
Ого. Оказывается эти скобки не просто так. Почему-то без скобок, компилятор считает что bufp объявлены одновременно, и начинает ругаться (что в общем-то верно, но очевидно что код из case 2 никогда не попадёт в case 3).
И скобки эту ошибку фиксят. Хоть что-то новое узнал.
Аноним  Пн 29 июл 2024 17:31:11 323805 19
image.png 2Кб, 640x496
640x496
Ну и уродство. Эта программа заставляет куллер на моём ноутбуке шуметь.
Возможно это из-за активного ожидания. Идея создавать бесконечные циклы для отрисовки графики изначатьно звучит так себе. Если нужно показать картинку, можно было бы сделать проще:
//код по отрисовке
char ⚹buf = malloc(1024);
fread(buf,1024,1,stdin);
free(buf);
fread тут работает в блокирующем режиме, и он просто заблокирует всю программу с отрисованым канвасом, до тех пор, пока ему не придёт eof, или будет введено 1024 байт в буфер. Зачем вводит "эвенты", если даже толком не рассказано что такое эвенты и как они устроены. Да даже про сёрфейсы не особо подробно рассказали, а уже эвенты.
Аноним  Пн 29 июл 2024 17:42:16 323819 20
У меня появилась забавная идея.
Мы же можем рисовать по-пикселям?
А что, если сделать программу, которая на вход получает картинку, а на выходе выдаёт текстовый файл, с кодом на С, который бы содержал функцию, которая отрисовывает эту картинку при помощи drawpixel! Для экономии можно было бы сделать что-то типо RLE сжатия, чтобы пиксели одинакового цвета рисовались сразу строчкой.
И тогда, можно было бы сделать игру без ресурсов, в том плане, что все картинки в ней выполнялись бы програмно.

Это шутка. Конечно же так делать не буду.
Аноним  Пн 29 июл 2024 21:55:39 324250 21
image.png 2Кб, 634x477
634x477
Сделал отрисовку линий. Вроде работает.
Аноним  Пн 29 июл 2024 22:10:54 324286 22
image.png 530Кб, 640x631
640x631
Вообще, я так подумал, maby im a cringe.
Типо, что мне этот монитор сдался вообще?
Игра на 90% состоит из вещей, никак с переферией не связанных. В игры же играют, а не смотрят.
Нужно сделать саму игру, т.е. некий конечный автомат, который реагирует на события. Я могу выводить все результаты тупо в консоль, даже без ncurses. Даже то что касается графической части, можно выводить в консоль в виде результатов типа: "линия построена по коодринатам:...". Так даже легче отлаживать программу.
Аноним  Вт 30 июл 2024 00:03:05 324680 23
17167507682252.jpg 305Кб, 736x837
736x837
fd14ccdb48ed350[...].jpg 105Кб, 736x911
736x911
hIYQB8I1S2DK-L0[...].png 4Кб, 320x480
320x480
scale_1200.jpg 164Кб, 1200x687
1200x687
Да. Я просто-напросто занимаюсь не тем чем нужно. От этого и бомблю почём зря. Надо заняться разработкой игры, а не чего-то другого.

Собственно, надо подумать над вопросом, в чём заключается игровой процесс программы которую я хочу создать.
Допустим, пускай это будет очередной рогалик (первое что пришло в голову)
Из чего же может состоять будущая игра?
1)Меню. Реализация мыслиться простой. Может это некий конечный автомат, который просто ждёт наступления событий (щелчка мыши по нужной координате например), и после что-то делает, например меняет свое состояние, переходит в другое подменю.
2) Сама игра. Если так подумать, то ведь управление персонажем это тоже как конечный автомат: нажал - он идёт, отпустил - стоит. Однако, кроме событий с клавиатуры (или другого ввода), в игре ведь существует и внутренние события. Например, игрок наступил на жабу - чисто внутренне событие, которое может выражаться как решение системы линейных управлений в трезмерном пространстве. Нет. Решать СЛАУ - звучит максимально глупо, тактов процессора не хватит, чтобы бесконечно решать задачи на столкновение трёхмерных объектов. Очевидно, можно же упростить задачу, добавив дэмэджбоксы", (хотя наверное выгоднее были бы джмэдж-сферы, мне почему-то кажется что из вычислять проще, ведь тогда достаточно просто вычесть разницу в координатах между двумя точками в трёхмерном пространстве, и посчитать не является ли эта разница слишком маленькой. т. е. не находятся ли эти объекты близко).
Такими же внутренними событиями, являются: столкновение камеры с поверхностью. столкновение оружия противника с персонажем, нахождение персонажа на поверхности. То есть игра уже образует собой некоторую среду, в которой могут возникать внутренние события. В отличие от меню, игра сама в себя играет.
Допустим, мы сделаем игру по тому же принципу что и меню: бесконечный цикл, который блокируется на одной итерации в ожидании событий. Так как игра сама в себя играет, то параллельно должен выполняться другой процесс, который мог бы вызвать это самое событие. Например это может быть совершенно такой же конечный автомат, но только он каждый цикл смотрит, изменились ли координаты всех объектов в игре, и если изменились, то вычисляет разницу. Если разница нулевая, то генерирует событие "столкновение". Получается что у нас есть отдельный модуль который занимается вычислением физики точек в пространстве.
... Создать игру это почти как создать свой xorg server получается. Хотя и вправду, а чем xorg не игра? Принципиально тыканье кнопок xcalc ничем не отличается от игры в сапёра... (внезапная мысль)

По-аналогии, можно создать и несколько других процессов, которые тоже генерировали события исходя из набора правил.
Всё это можно объединить в большую диаграмму, разбив по группам.

Что касается графики, так у нас есть условно "камера" - это наше двухмерное полотно, canvas или surface, как угодно. Мы можем рисовать линии на этом холсте. Таким образом, мы можем координаты трёхмерного объекта спроецировать на полотно. Нужно разработать алгоритм отрисовки линий так, чтобы он рисовал только то, что помещается на экран.
Похоже что 3d модели придётся погружать в ОЗУ, иначе просто неудобно будет постоянно парить. obj файл. Раз уж массив точек лежит в ОЗУ, то почему бы не сделать функции для его поворота. Поворот объекта будет осуществляется полным перезаписыванием всех его координат на новые значения, домноженные на матрицу поворота (тут конечно неплохо было бы использовать кватернионы, а не матрицу эйлера). Сама же камера может тоже иметь координаты. В таком случае, перед тем как спроецировать трёхмерный объект она будет все его координаты изменять на новые с новым поворотом, после чего обнулять свои.

В общем, нафантазировался сегодня. Попробую что-то сделать. Уже лучше чем пустота в голове.
Аноним  Ср 31 июл 2024 21:24:09 328200 24
image.png 19Кб, 1016x554
1016x554
Да. Этот Poll не блокируется пока эвентов нет.
Аноним  Чт 01 авг 2024 18:32:41 330498 25
2024-08-01 20-29-21.mp4 9453Кб, 1280x720, 00:00:30
1280x720
Сделал алгоритм брезенхема который не позволяет вылезти за поля экрана.
Далее делаю парсер .obj файлов.
Аноним  Пт 02 авг 2024 12:57:26 331655 26
image.png 13Кб, 1222x728
1222x728
image.png 9Кб, 664x315
664x315
Точки можно хранить в двухмерном массиве, где строки - номера точек, а столбцы - координаты. типо vertex[1][x]
А вот с полигонами чуть по-сложнее, полигон ведь это не обязательно четыре точки, это может быть и три и пять и шесть, и вообще сколь угодно много.
Поэтому, полигон, это указатель на указатель на список.
То есть это массив из списков (список желательно сделать закольцованным, чтобы можно было все элементы последовательно прокрутить). Каждый индекс - номер полигона. Список в каждом индексе может иметь неограниченое количество элементов. Каждый элемент содержит в себе номер точки из этого полигона. Вот так, на мой взгляд логично. Впринипе, парсер сделан. Я позволил себе использовать переменные типа float, по той простой причине, что загружается модель в память всего один раз, так что тут наверное можно позволить float'ы. Зато флоаты позволять масштабировать объект при импорте. Без флоатов пришлось бы изобретать снова велосипед для маштабирования, чтобы например число 0.02, ипортировать не как 0, а как 2. А с флоатами просто домножил на 100 и всё.
Можно позже этот велосипед доизобретать, сли вдруг окажется что числа с плавающей точкой мешают.

Осталость сделать какие-нибудь прикладные функции для работы с типом "wavefront object". Функция импорта содержит в себе malloc'и, следовательно нужно сделать функцию для уничтожения всего этого объекта. Нужно также сделать фнукцию которая позволять умножать и скалировать объект, производить над ним математически операции. И тогда уже можно помещать его на экран, и выполнять всякие повороты над ним.
Аноним  Сб 03 авг 2024 00:05:03 333265 27
image.png 97Кб, 1909x1049
1909x1049
Наконец-то сделал проволочный рендер. Большую часть времени фиксил очевидные ошибки.

Ошибка 1: Забыл инициализировать список значением NULL, из-за чего на выходе получался рандомный мусор, заканчивающийся сегфолтом. Я не сразу догадался, что ошибка меняется в зависимости от времени когда ты запустил программу.

Ошибка 2: при переборе списка, поставил на вывод не временную переменную, а основную, от чего список выдавал всегда только последний элемент. Я не сразу понял, что ошибка всего в одной переменной, и начал искать ошибки в функции добавления элемента в список.
Заодно пока искал несуществующие ошибки, нашёл новые недочёты, которые пока не пофиксил.

Недочёт 1: Парсер полигонов работает неверно. А дело в том, что полигоны могут быть заданы в форматах 1/2/3/4 или 1/2/3 или вообще 1. Когда scanf, берёт строку он работает только с одним форматом. Про другие форматы я не знал. Другие форматы зависят от наличия групп сглаживания/нормалей/текстур/ещё чего-то. То есть для полноценной работы нужно дополнить парсер, чтобы он узнавал формат и уже под него сканировал строку.

Недочёт 2: Оказывается, номер точки у полигона может быть отрицательным. Отрицательный номер означает, что номер берётся с конца, то есть (макс_кв_точек - х). Этот недочёт пофиксил.

Пришла в голову идея, а что если функцию по отрисовке линий сделать как callback-функцию. Тогда функция DrawObj будет просто перебирать координаты точек объекта по-полигонам,а функция-отработчик уже будет что-нибудь с этими кординатами делать. Может не обязательно линию строить, может она будет закрашивать область по координатам, или текстурку мапить на неё.
Аноним  Сб 03 авг 2024 11:07:55 333849 28
Ошибка 3: Алгоритм брезенхема не рассичнат на отрицательные значения. Я почем-то наивно полагал что все координаты больше нуля. Но так-то могут быть и меньше. Поэтому нужно допилить защиту выхода за области экрана с учётом всего этого
Аноним  Сб 03 авг 2024 14:09:37 333972 29
image.png 86Кб, 1920x1080
1920x1080
image.png 81Кб, 1920x1080
1920x1080
Пофиксил.
Теперь оно может вылезать за рамки, и в отрицательную часть.

Если быть точным, фактически оно ни при каких условиях не может вылезти за пределы экрана, ведь тогда получится segfault, и программа завершится. Просто предварительно происходит позиционирование начальной точки: если она находится за пределами экрана, то она либо проецируется на оси экрана, либо линия вообще не рисуется (в случае когда очевидно что линия не будет отображена. Например, восходящая линия хотя бы с одной координатой больше ширины экрана уже не будет отрисована, потому что вторая точка по-любому находися также за пределами экрана и линия экран никак не задевает). С падающими линиями всё немного сложнее, ведь точки могут находится и за пределами, но сама линия частично пересекает экран. Но тут есть преимущество, в том, что проецировать нужно только первую точку. Вторая точка нам безразлична, просто потому что мы в самом алгоритме брезенхема можем сделать условие, что если текущая координата выходит за пределы ширины экрана - цикл следует завершить. Таким образом, вторая точка в проецировании не нуждается.

Дополнил парсер. Теперь он различает как формат a/b/c так и a. Форматы a//c и a/b, ещё не сделал, но это делается аналогично в пару строк кода.

Надо бы сделать функции для увеличения загруженной модели.
Аноним  Сб 03 авг 2024 14:26:00 333995 30
image.png 18Кб, 379x375
379x375
image.png 1225Кб, 1024x691
1024x691
Мне ещё нравиться что она отриcовывает линии без сглаживания. Чисто игра без мыльца получается. Как старая графика типо краш бандикут
Аноним  Сб 03 авг 2024 15:22:29 334103 31
image.png 323Кб, 1080x1080
1080x1080
Масштабирование объекта - задача простая. Просто умножить все координаты на коэффициент.
Параллельное перемещение объекта тодже в теории просто - добавить ко всем координатам какое-то число.
А вот с поворотом начинаются проблемы.
Матрица поворота эйлера - кал. Выглядят как плохая идея.
Кватернионы - непонятно.
Попробую покурить математику. Если пойму как эти кватернионы работают, реализую сразу их. Если нет - придётся с каловыми матрицами работать, которые ещё и кривизну выдаёт при повороте на 360.
Аноним  Сб 03 авг 2024 16:35:12 334297 32
image.png 14Кб, 461x458
461x458
При масштабировании возникла проблема: целочисленные значения искажаются(((
Насколько я знаю float довольно вредно влияют на процесс рендера. Придётся подгонять изображение под конкретные размеры.
Аноним  Сб 03 авг 2024 16:44:55 334306 33
2024-08-03 18-43-39.mp4 2628Кб, 1280x720, 00:00:08
1280x720
Аноним  Сб 03 авг 2024 17:08:57 334340 34
image.png 121Кб, 821x797
821x797
чтоооо?! функции для решения матриц можно запилить на ассемблере? тогда получиться намного быстрее и удобнее вращать объект.

Обойдусь пока что. Сделаю на флоатах для простоты. Потом попробую сделать на интах. Потом покурю кватернионы.
Аноним  Сб 03 авг 2024 18:20:55 334411 35
2024-08-03 20-15-59.mp4 5039Кб, 800x600, 00:00:16
800x600
Из-за хранения модели в целочисленном виде появляются искажения((
Аноним  Сб 03 авг 2024 18:35:44 334422 36
Ну и чё с этим делать? Неужели это конец?! Придётся использовать флоаты, а значит игра уже будет довольно тормознутой.

Без флоатов всё черевато искажениями.
Аноним  Сб 03 авг 2024 18:42:05 334426 37
2024-08-03 20-41-08.mp4 3200Кб, 800x600, 00:00:10
800x600
Аноним  Сб 03 авг 2024 21:01:25 334652 38
2024-08-03 22-55-00.mp4 7967Кб, 800x600, 00:00:26
800x600
Ну и пох. Сделал на флоатах. Теперь в кашицу конечно всё не превращается, но что это за артефакты? Почему какие-то точки остаются на месте? Это может значить что алгоритм брезенхема неправильно сделан. В общем, нужно искать ошибку.
Аноним  Сб 03 авг 2024 23:05:44 334755 39
2024-08-04 00-55-55.mp4 6115Кб, 800x600, 00:00:20
800x600
2024-08-04 01-01-35.mp4 1790Кб, 800x600, 00:00:05
800x600
2024-08-04 01-02-09.mp4 1678Кб, 800x600, 00:00:05
800x600
image.png 68Кб, 1012x252
1012x252
Похоже что ошибка возникает именно во время поворота.
Если отрисовать заранее повёрнутую модель, но всё нормально. Проблема возникает именно на поворотах. Значит, мне кажется, что алгорим брезенхема работает верно. Проблемы именно в вычислении поворота, матриц.
Я использовал формулы с википедии.
Чъёрт знает. Надо попробовать кватернионы + другие варианты матрицы поворота.
Аноним  Сб 03 авг 2024 23:12:51 334761 40
2024-08-03 23-39-58.mp4 6891Кб, 800x600, 00:00:22
800x600
2024-08-04 01-10-24.mp4 4273Кб, 800x600, 00:00:14
800x600
Я думал, что может искажения происходят от угла 90 градусов.
Ведь гладкий валькнут не даёт никаких сбоев.
Но и куб под 90 градусов тоже не даёт никаких сбоев.
Завтра разберусь.
Аноним  Вс 04 авг 2024 21:43:40 336269 41
2024-08-04 23-35-22.mp4 8125Кб, 1920x1080, 00:00:26
1920x1080
2024-08-04 23-38-22.mp4 3531Кб, 1920x1080, 00:00:11
1920x1080
Добавил возможность перемещения объекта.
Проблемные точки искажаются даже при перемещении объекта. Значит проблема не в матрице поворота.

Возможно модель импортируется некорректно: например может некоторые точки считываются неправильно.

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

Может быть сама отрисовка сделана неверно и с ошибками. Например, алгоритм брезенхема на некоторых углах может даёт сбой, неправильно что-нибудь проецирует.. Надо попробовать запустить алгоритм без защиты канваса.
Аноним  Вс 04 авг 2024 22:15:08 336293 42
image.png 1142Кб, 1024x683
1024x683
image.png 4Кб, 628x258
628x258
До меня долшло.
Один полигон может содержать точки 1/2/3/4, и другой полигон может содержать точки 4/5/6/7. Таким образом точка 4 повторяется дважды, а значит она дважды будет повёрнута. Вот и всё. Надо перебирать просто все точки. А я перебираю по полигонам.
Аноним  Вс 04 авг 2024 22:26:31 336311 43
2024-08-05 00-23-07.mp4 8054Кб, 1920x1080, 00:00:26
1920x1080
image.png 3Кб, 497x230
497x230
Да. Проблема была в этом.
Теперь всё работает. Ну и хорошо, я уж думал проблемы с брезенхемом.
Аноним  Пн 12 авг 2024 15:02:07 350728 44
image.png 140Кб, 1024x732
1024x732
Попробовал откомпилировать игру с флажком -static, для того, чтобы сделать ещё протативной. Результат плохой. Почему-то программа теперь запускается только в ncurses. И если бы оно хотя бы показывало что-то, но нет, просто загружается пустой ncurses, а при попытке переместить 3D обьект программа падает.
Это никуда не годиться. Видимо придётся отказаться от SDL, и делать всё чисто под XCB.
Под XCB получилось статически откомпилить программу. Минус, что SDL по-идее должен работать и под wayland и под xlib и даже под windows, а xcb работает только под x-server.
Также, говорят что xcb довольно тормознутый.
Или xlib лучше.

Надо переработать защиту от выхода за поля картики. Видно, что при увеличении изображения линии начинают "искажаться". В целом, подход тот же, только переделать функцию OutOfCanvas. Уже протестить всё.

К слову о тестах. И всё же сонсолечка надёжнее. Решил я протестить вообще все варианты линий от -5 до 5 координат. Надо сказать, что это весьма много вариантов (19 мб текстовый файл со всеми вариантами весит). И мой любимый текстовый редактор XNedit, на этом начал подвисать. А вот консольный nano справляется запросто.
И если так подумать, графическому интерфейсу уделяют слигком много, вместо того чтобы развивать надёжный текстовый. Зачем вообще нам визуальная информация?
1.Чтобы было понятнее
2.Для творчества
Всё. Больше впринципе незачем. Результат любой программы можно представить в виде текста. Просто, иногда бывает удобнее смотреть на пересекающиеся графики, а не на таблицу из их значений. Поэтому, графике надо уделять меньше внимания. Программы по возможности должны работать без графики. Например, зачем нам графический плеер? moc отлично воспроизводит музыку и из терминала.
Графика нужна только при просмотре видео, картинок, игр, книг.
Вот бы графический модуль был более утилитарный.
Аноним  Пн 12 авг 2024 18:18:46 351166 45
image.png 4Кб, 632x247
632x247
image.png 17Кб, 1058x732
1058x732
Вот. По сути, на моей модификации алгорима брезенхема, мы можем разбить все линии на возрастающие и убывающие (все до 45 градусов, так как когда координаты линии приходят в функцию bresenham, они уже перевёрнуты и отражены как надо).
Возрастающие линии (красные) ТОЧНО можно не отрисовывать если они выходят за росовую область. А убывающие - за бирюзовую.
Отсечём две эти области, а для всех остальных линий, сделаем функции для проецирования X и Y соответственно (функции сделал на флоатах. Долго тестировал, деление на целых числах так и не получилось реализовать, всегда получается какая-то безумная погрешность. Решил забить, пусть пока на флоатах поработает).
Причём, если точка начала линии лежит за диагональю экрана(жёлтая линия), то проецировать её следует на ось X, а если выше диагонали то на ось Y.
Осталось написать код.
Аноним  Пн 12 авг 2024 18:50:22 351227 46
image.png 20Кб, 1283x743
1283x743
А вот, опять проблема.
"вычислить условие нахождения на диоганали" - это означает вычислить проекцию начальной точки на диоганали и сравнить их x координату. Это опять использование чисел с плавающей запятой.
Думаю, поскольку в СИ существуют "ленивые вычисления" (то есть например у условия А || B выражение В не будет вычислино, если А истино), я думаю, можно вначале узнать, выше ли y0 нуля. Если он выше, то тут и так ясно, что точка выше диоганали. А если ниже, только тогда следует сделать проекцию
Аноним  Вт 13 авг 2024 14:46:17 352683 47
Отрубили электричество - всесь исходный код программы исчез к хуям.
ЧЗХ?! Не может же это быть проблемой FreeBSD. Наверняка это всратый редактор XNedit испортил мне всё.
В общем... всё заново. А я уж было только сделал защиту канваса.
Аноним  Вт 13 авг 2024 14:52:04 352693 48
пиздец... всё с самого начала. Благо хотя бы парсер .obj сохранился, не придётся делать этот ебучий импорт изображений. Тогда длать под xlib попробую. Нах этот SDL.
Аноним  Вт 13 авг 2024 21:54:04 353387 49
image.png 82Кб, 1465x994
1465x994
Зато, на Xlib можно обучаться на примере dwm. Берёшь код из dwm, анализируешь, применяешь так же. Поминималистичнее и приятнее будет
Аноним  Сб 17 авг 2024 01:34:55 360281 50
Было бы интересно полностью избавиться от чисел с плавающей точкой.
Тогда, нужно было бы создать свои функции для целых чисел. Например функцию поворота объекта.
Суть в том, чтобы результат был обратим: повернув объект, его можно было бы вернуть заново.
Как это сделать, пока не знаю. Очевидно, что такая функция не сможет повернуть объект на 1 градус: при таком повороте координаты практически не изменятся. Но вот на 90 градусов повернуть объект без потерь довольно просто: достаточно поменять местами его координаты.
То есть тут нужно придумать какую-то логическую замену тригонометрическим функциям, чтобы получать однозначный обратимый результат.
Звучит как что-то невозможное.
Ко всему прочему, функции с плавающими точками не ограничиваются поворотом. Также нужно реализовать перспективу на целых числах, заполнение поверхностей.
Аноним  Сб 17 авг 2024 01:56:37 360299 51
А что если функцию реализовать как просто множество значений!?
Грубо говоря, вычисляем огромную таблицу результатов поворота на действительных числах. Задаемся погрушностью и делаем функцию, которая тупо по заданным значениям выдаёт заранее заготовленный результат поворота.

А формат анимаций реализовать как последовательность необходимых действий над точками. То есть анимации могут хранится в объектном файле в виде функции. Например функция anim_fly() выглядела бы как
for(int i = 0; i < 200; i++)
moveobj(obj, 0,0,12);
Аноним  Сб 17 авг 2024 14:54:10 360674 52
2024-08-17 16-49-26.mp4 8299Кб, 1920x1080, 00:00:27
1920x1080
Начал делать шейдер. Вот первая весия. Пока-что очень сырая.
1. почему-то векторное произведение считает самой яркой ту часть, которая находится с обратной стороны. видимо необходимо придумать рефлексы.
2. векторное произведение переполняет буфер. яркость считается неверно, из-за чего выдаёт просто мозаику. Я так веременно пофиксил, просто поделив яркость на 1000. Но с этим явно что-то нужно делать
Аноним  Сб 17 авг 2024 14:56:25 360679 53
3.Отсутствует защита выхода за пределы экрана для алгоритма заливки треугольников. Из-за этого программа крашится.
Аноним  Сб 17 авг 2024 15:21:16 360694 54
>>360674
Ну и что я написал? Иногда такое состояние, когда чувствуешь себя ужасно глупым - сложно подумать о чём-то, сложно сформулировать правильно мысль. И ты лежишь и смотришь в стену.
Надо нормально сформулировать ошибки, а то потом перечитаю и не пойму что я вообще имел ввиду.
>переполняет буфер.
Не буфер переполняет, а переменну.
Яркость высчитывается неверно. Произведение: яркость*цвет переполняет переменную, от чего яркость распределяется мозаикой. При этом, если значение поделить на 100, то результат будет удовлетворительный, следовательно функция вычисления векторного и скаларного произведения векторов, вероятно работают верно. Только, что-то необдуманно скомбинированно.
Аноним  Вт 20 авг 2024 11:34:46 365387 55
image.png 30Кб, 811x621
811x621
image.png 2Кб, 645x158
645x158
Пофиксил.
Достаточно было просто нормализовать вектор - т.е. сделать его единичным. С другой стороны, я вот сейчас подумал, а ведь можно избежать этих вычислений с плавающей точкой, и придумать более хитрый способ нормализовать вектор.
Теперь всё шейдится так как нужно.
Выход за рамки сделал довольно примитивно: добавил функцию DrawPixelProt, которая не рисует пискель если он находится вне канваса. Плохая функция. Ведь на те полигоны, которые находятся за пределом камеры тратятся такты процессора - каждую такую точку программа извлекает, смотрит что её отрисовывать ненужно, и завершается. Вместо этого, лучше бы сделать алгоритм, который заранее рисует только те полигоны, что умещаются в камеру. Но это, наверное позже, так как у меня пока и камеры никакой нет, всё это отрисовывается в ортогональной проекции, а поворачивается не камера а сам объект. Нужно сделать перспективную проекцию, это во-первых, во-вторых нужно сделать и саму камеру, чтобы можно было объекты с разных сторон отображать, при этом чтобы сами объекты координаты не изменяли.
Плюс, нужно сделать YZ буфер, чтобы не отображать ненужные полигоны. Нужно реализовать сглаживаение по-гауссу. И когда вот эта "база" будет готова, нужно вначале сделать оптимизицию: 1 всё что находится вне экрана, не должно обрабатываться отрисовщиками. 2 все операции надо перевести на целые числа, 3. надо сделать программу более модульной и гибкой. Возможно реорганизовать некоторые функции. Например, можно было бы затенять полигоны алгоритмом брезенхема, или другим каким-нибудь алгоритмом (главное чтобы был отдельный алгоритм по затенению).
Аноним  Вт 20 авг 2024 11:58:17 365436 56
image.png 99Кб, 214x235
214x235
Похоже что работать напрямую с монитором - невозможно. Точнее, вероятно, никакого "драйвера монитора" в системе может и не быть. Монитор похоже никак не связан с компьютером (с шиной).
Мне как пользователю ноутбука, это не очевидно, так как у меня от монитора идёт какая-то шина внутри сразу на плату. А вот на стационарных пк это явно заметно: от монитора идёт только VGA кабель до видеокарты, и питание.
Конечно, монитор можно подключить и прямо к материнской плате, но сам факт того, что он может работать и без материнской платы заставляет задуматься. Раз монитор подключается только к видеокарте, то если так подумать... возможно никто и не предполагал использовать компьютер без видеокарты.
Ещё немного погуглив, я прочитал что
>VGA (разъём) — 15-контактный субминиатюрный аналоговый разъём
Обратите внимание на слово "аналоговый". Получается, я не могу никак напрямую из памяти обратится к vga. VGA просто не может быть подключен к шине, так как на шине сигналы цифровые, логические. Мне нужно иметь как минимум какой-нибудь АЦП (аналого-цифровой преобразователь) чтобы обратится к монитору. Если я подключу к Com порту ацх, и буду какие-то алгоритмы делать - то это и будет своего рода примитивная видеокарта. Поэтому, искать "драйвера монитора" похоже что бессмысленно.
Имеет смысл искать только "драйвера видеокарты".
И тут сразу же два минуса: похоже, что работа в текстовом режиме - это уже не один драйвер. И пользовательский интерфейс к этим драйверам есть только текстовый. Таким образом, чтобы сделать графику из сонсоли, нужно пилить свои драйвера. А второй минус, заключается в том, что походу то что рабоатет на одном драйвере, не работает на другом. Таким образом, игра, зависящая от конкретных драйверов - это кал. Нужно отделить игру от драйверов. Нужно создать отдельную папку api_setting, в котором составить обёртки для функций драйверов или бибилиотек. То есть, моя игра должна воспринимать функци типо DrawPixel. А с помощью какого драйвера этот DrawPixel реализован, должно находится в отдельном модуле. Таким образом, если захочется перевести игру с SDL на Xlib, или вовсе на виндоузовские функции, то достаточно будет добавить новый модуль в api_setting, например SDL_base.c, Xlib_base.c, Win32_base.c, SVGAlib_base.c итд, и откомпилировать игру, поменяв include в главном файле current_set.h. И сама игра должна содержать модули ТОЛЬКО из стандартной библиотеки. все сторонние модули системной библиотеки должны быть вынесены в файл current_set.h, и заполнены обёртками, чтобы можно было в случае чего портировать программу под любую другую ОС/api если вдруг старые устареют.
Аноним  Вт 20 авг 2024 13:03:51 365560 57
Почитал про Z-буфер, про Алгоритм художника и Back Culling.
По-сути, применять необходимо все три алгоритма. Для построения пересекающихся и самопересекающихся объектов нужен только Z буфер. Для различных непересекающихся объектов подойдёт алгоритм художника. Для одного единственного объекта можно использовать back culling, чтобы рендерилась только его видимая часть.
Аноним  Вт 20 авг 2024 16:16:03 366107 58
image.png 192Кб, 256x347
256x347
image.png 4059Кб, 1920x1080
1920x1080
Для интереса поковырял код Quake 2.

Откомпилировать так и не смог, потому что игра сделана под windows, dos, но ни как не под unix. Может быть в те времена фреймворки ещё не были обыденностью, поэтому Кармак решил писать всё железо-зависимое с нуля.

Но не суть. Главное, что я понял, что я делаю не движок, а игру. Разница между движком не в проделанной работе, а в иерархии и устройстве. Тот анон, который говорил что я хочу создать движок
>>266287
отказался немного не пра всё-таки.

Так в чём же разница?
На примере Quake видно, что сам Quake представляет собой некоторую программу для обработки игровых ресурсов. Игровые ресурсы - это скрипты, сценарии, текстурки, модели, уровни итд. То есть, ресурсы, это грубо говоря файлы игры.
А движок - это сам .exe файл. Если запустить движок без ресурсов, то движок вежливо сообщит об ошибке, что он не нашёл что запускать. А ресурсы без движка запустить попросту нельзя. Для того, чтобы запустить скрипты движка нужен интерпритатор внутри движка. Получается, что сама игра Движок+Ресурсы.
Мод на игру - это Движок+видоизменённые ресурсы
Вот примерно так.

К слову, игру можно создать и без движка, а точнее с монолитным движком. Пример такой игры - Painkiller. Вся игра написана на С, и чтобы её как-то модифицировать придётся перекомпилировать код.
Так, что игра может быть как с движокм, так и без, это не показатель её сложности. Можно сделать простую игру с движком: условно, движок будет считывать буквы из файла res.txt, и ожидать действия от пользователя. Если пользователь нажал ту же букву, что сейчас находится в переменной движка, то движок считывает следующую букву. Если же, буква различная, то движок ничего не делает.
Вот и вся игра. У этой игры есть и движок и ресурсы. При этом, ясно дело, что эта игра намного проще пэинкиллера.

При этом, иерархию движок/игра можно реализовать по-разному. В случае с Quake. движок просто ожидает основной мод на игру. Современные движки могут быть ещё более навороченными, и вообще представлять из себя среду программирования. Например unity, представляет из себя редактор, который все ресурсы компилирует в отдельную standalone программу. В таком случае движок вообще представляет собой обобщённый инструмент.

Я бы наверное не стал делать игру монолитной, как пэинкиллер. Вместе с этим, мне кажется глупым и неэффективным обобщать игру до сложных движков. Поэтому, я пока не знаю что делать. Буду писать документацию на несуществующую игру, чтобы
1 было проще структуировать мысли
2 в случае если получися что-то разработать, не пришлось бы маятся над документацией, так как она бы уже была готова по ходу разработки.
Итак ридми.тхт.мд

# OVERVIEW
Для обзора, продемонстрирую игру созданную на этом движке.
# INFRASTRUCTURE
Движок является серверной программой, которая получает на вход файлы
игры, производит настройку а затем работает в режиме конечного автомата,
ожидая наступления событий (событий клавиатуры, либо внутренних собы-
тий движка). Средства которыми обрабатываются события, нахоятся в
каталоге SYS, это может быть любой интерфейс, например xserver или SDL.
Игра - жто движок+ресурсы.
Ресурсы игры - это набор файлов, в которых содержаться все необходимые
настройки, указания серверу, текстуры, анимация, звуки, сценарии, и
прочие необходимые объекты, которые задают конкретику игры.
Далее, будет более детально описано устройство движка по каталогам
и файлам.
## cd ./SYS/
В данном каталоге собраны обёртки для всех нестанартных функций.
Основной движок имеет зависимость либо от стандартной библиотеки,
либо от обёрток функций из этой папки. Например, центральной функцией
графической части, является функция DrawPixel(), которая объявлена и
описана тут. В данном модуле функция реализована при помощи библиотеки
SDL. Но в случае портирования движка на другую платформу, можно пере-
писать функцию под другой фреймворк/библиотеку, сохранив только название.
В результате, чтобы портировать игру под другую платформу, достаточно
переписать только этот модуль, оставив модули движка без изменений.
## cd ./ENGINE/GRAPHIC/
Часть движка отвечающая за графику (включая трёхмерную).
./wavefront.c - Модуль для работы с объектами формата wavefornt obj.
Включает в себя функции на импорт файла вместе с инициализацией
всех необходимых структур данных, а также включает в себя функции
по удалению из памяти не нужных более 3d объектов.
./math.c - Модуль для работы с некоторой полезной математикой.
Операции над числами с плавающей точкой довольно сильно нагружают
систему, особенно когда приходится их выполнять над одной точкой
по несколько раз. Поэтому был разработан специальный модуль который
позволяет выполнять те же самые операции над целыми числами, с
определённой погрешностью. Также в этом модуле созданы полезные
функции и процедуры над математическими объектами такими как "точка",
вектор, матрица.
./graphic.c - Главный модуль, который использует функции из всех
предыдущих подмодулей, образуя интерфейс для работы с трёхмерным
пространством.
## cd ./ENGINE/main.c
Ядро движка. Компилируется в исполняемый файл, который является файлом
для запуска игры. Как уже говорилось ранее, движок ожидает ресурсов игры,
в случае отсутствия каталога "game", программа завершится с ошибкой.
## cd ./GAME/
Ресурсы игры. Тут размещены все файлы, определяющие конкретный игровой
уровень/действия внутри игры.
Аноним  Вт 20 авг 2024 23:10:30 367035 59
image.png 28Кб, 800x600
800x600
image.png 4Кб, 502x286
502x286
Сделал Z-буффер... ну и муть.
Это получается карта глубины для всего изображения. То есть каждый кадр НА МОДЕЛЬ проецируются точки. То есть каждый кадр, моя программа вычисляет несколько определителей матрицы, для того чтобы найти точку на плоскости. Почти как рейтрейсинг. Ужас.. Копьютер подпёрживает от количества.
Как по мне, алгоритм который просто не рендерит все полигоны, которые развёрнуты от наблюдателя - более оптимальный. Но вот, сразу же непонятно, что делать с "углублениями" и "канавками" на модели. Ведь задняя стенка канавки развёрнута на камеру, но при этом видимой быть не должны так как перекрыватся передней стороной.
Z-буферизация позволяет разрешить эти проблемы. Но вместе с этим.. это двольно затратно.
С другой стороны, backculling предварительно отрезает заднюю часть. Тогда можно сделать так, чтобы буферизировалась только передняя часть.
Аноним  Ср 21 авг 2024 11:14:00 367557 60
Я вот сейчас поняо, что в игре можно обойтись без шейдеров. Можно же просто запекать текстурки - делать так, чтобы собственные тени были заранее подкрашены в текстуре.
Это, правда не работает с движущимися объектами. Если что-то двигается, то у него тени будут смотреться доольно странно при движении.
Можно сделать типо систему флагов из макросов, чтобы каждой модели ставить способ её отрисовки: проволочный, сплошной, затенённый, затенённый со сглаживанием по гауссу.
Преимущество сплошного отображения, в том, что не нужно считать векторы, ни на сглаживание, ни на свет: всё уже заранее содержится в текстуре.
Аноним  Ср 21 авг 2024 11:34:02 367594 61
Какой бы выбрать формат для хранения триде анимаций?
Текстуры - в tga
Модельки - в obj
А анимации?
Аноним  Ср 21 авг 2024 12:19:29 367633 62
image.png 39Кб, 800x600
800x600
image.png 56Кб, 762x653
762x653
Перспектива. "он был настолько жирным что вытекал из треда"
Я так и не понял ничего про какое-то "четырёхмерное пространство". Я довольно глупый - всё что я не проходил в вузе даётся сложно.
Мне показалось, что примитивном случае, построение перспективы сводится к нахождению проекции прямой, которая проведена из точки свода до точки объекта.
В моём случае, точка свода находится в точке 0,0,0. Плоскость на которую проецируются лучи из точки свода, параллельна плоскости Z, и находится от неё на расстоянии 100, а сам объект находится на расстоянии 200.
Вроде походит на что-то правдоподобное. Нужно по-подробнее разобраться как это преобразование происходит. А потом всё это добро можно переводить на целые числа, и переписывать всё заново, так как идеи поднакопились за это время
Аноним  Ср 21 авг 2024 12:44:51 367660 63
image.png 35Кб, 800x600
800x600
image.png 108Кб, 1024x791
1024x791
image.png 982Кб, 1280x854
1280x854
Я кажется понял, почему на рисовании мы всегда делали две точки схода.
Точка схода, похоже что всегда одна. Похоже что вторая точка схода - это просто вычисление расстояния геометрическим методом. То есть вторая точка обеспечивает паралельность линий, и всё.
У художников точек схода может быть сколь угодно много, но при этом в трёхмерном пространстве точка всегда одна.

Вот, точку схода поставил на середину экрана. и воде бы искажений не наблюдаю.
Сразу же можно выявить несколько минусов: во первых, если объект попадает за плоскость проецирования, то он начинает искажатся. Надо сделать так, чтобы полигоны сзади камеры вообще не принимались в расчёт.
Также, есть верояность, что изображение на самом деле рисуется "вывернутым". С другой стороны, Z-буферу безразлично что-там как вывернуто, перспектива - это же всего лишь проекция. Закрашивать то он будет так как положено.
Аноним  Чт 22 авг 2024 23:59:11 371040 64
image.png 10Кб, 667x462
667x462
image.png 18Кб, 667x462
667x462
ну, чтож. Всё заново. Начну с математического модуля.
Сделал пока-что только рациональные числа и операции над ними.
А производительнее ли это вообще? Я посмотрел fixed-point арифметику, и похоже что там какая-то другая реализация.
Во всяком случае можно протестировать debugger'ом, и посмотреть на производительность
Аноним  Пт 23 авг 2024 14:28:53 371772 65
image.png 9Кб, 651x343
651x343
Да. Получилось только хуже. На моих "рациональных числах" большая часть времени в normalize() простаивает. Итого, на main функцию уходит 5% времени. А на float, на функцию main уходит 20% времени. То есть Float'ы более меньше времени занимают чем мои рациональные.

Но я попытаюсь ещё что-то сделать.
Во-первых, нужно представить числа не в формате i10^p, а в i2^p. Это позволит использовать битовые сдвиги.
И нужно отказаться от циклов, при нормализации.
Аноним  Пн 26 авг 2024 17:20:45 378915 66
image.png 18Кб, 667x462
667x462
Наконец-то протестил и завершил числа с фиксированной точкой. Теперь реализую операции над ними.

Также, входе прошлого рендера, я заметил что пихать тысячу аргументов в функции, может быть и экономно, но неудобно.
Поэтому я решил сделать тип "вектор" который содержит три точки. По-сути это радиус-вектор.

Теперь векторное произведение векторов может возвращать значение
Аноним  Вс 08 сен 2024 17:49:34 411966 67
image.png 130Кб, 499x365
499x365
image.png 11Кб, 667x462
667x462
image.png 12Кб, 667x462
667x462
image.png 18Кб, 995x703
995x703
Ну чё. Давайте думать, подсказывайте, чё вы мозги ебёте.
Продолжаем.
За сегодня, я переписал весь wavefront_obj под мои "целые" числа. А также немного почитал xlib manual при помощи гуголтранслейта https://tronche.com/gui/x/xlib/utilities/XCreateImage.html
И переделал главную программу под xlib.
Преимущества: наконец-то я хотя бы отдалённо понимаю что моя программа делает. В том смысле, что я понимаю, что вот у меня запущен Xserver и я к нему обращаюсь с запросами типо "выдай указатель на дисплей" или "подожди событие".
Вместе с этим, в моей игре пропал весь интерактив: я не знаю как сделать чтобы кнопку можно было "зажать" надолго, ведь есть только события keypress и keyrelease. Я прочитал что строить изображение путём XPlotPixel - преступление против эффективности, ведь эта функция постоянно отправляет запрос серверу. То есть нужно мучиться, думать, как бы "подготовить кадр" и отправить его серверу на вывод.
То есть минусов дохрена получилось. Зато теперь можно начинать думать и как-то "выстраивать" систему по отрисовке. То есть делать непосредственно игру, её основу.
Я решил пока не заморачиваться по поводу кросплатформенности, потому что я до сих пор ещё не понимаю как выглядит игра, и какой "набор функций" требуется от API системы. Посторяюсь конечно же всё это наследие xlib, максимально не распостранять на другие файлы. Пусть оно не выходит за рамки маина, пока что.
Ну он конечно и друной этот Xlib. Отключил "автоповторение" и оно так и не закрылось с закрытия программы. Получается, это мне нужно фиксировать когда на моей игре сфокусировались и только тогда отключать "автоповторение". А потом ещё и свои механизмы для реакций на мышь вводить. А я ещё xcb пытался освоить. Мне xlib уже кажестя "слишком" низкоуровневым.
Начну пожалуй с графики. Нужно сделать систему "пространство-камера-объекты". Объекты - это конкретно obj файлы (которые уже реализованы). Объекты включают в себя информацию о точках, нормалях, текстурных координатах и типе объекта (затенённый/сплошной/сглаживаемый).
Пространство - это некоторый тип данных, который хранит объекты, хранит некоторую нулевую точку, от которой все объекты отсчитвыаются. Правильнее сказать, это "сцена" а не пространство. Также, в пространство можно отнести скайбокс (у меня это был просто градиент с зади). То есть некоторая картинка которая отрисовывается сзади по-умолчанию. Также в сцену можно добавить "солнце", просто как вектор откуда солнце светит, чтобы потом можно было какие-нибудь фишки с освещением делать (да и просто для модульности и понятности кода).
Чё ещё?
Ещё камера. Нужно сделать некоторый объект, который хранил бы в себе координату камеры, направление камеры, и плоскость проецирования.
Тогда метод rander_scene(scene ⚹scn1, camera ⚹cam1) отрисовывал бы сцену.
Тфу.. какой метод. Это же не С++.
Начал учить С++, и вот всё бы это можно было бы сделать намного менее "топорным". Не удивительно что все движки после дума делались на C++ а не на С. Чё пальцы себе ломать говнокодом.
Ну да ладно... начал на С, значит будет на С.
Аноним  Вс 08 сен 2024 17:53:09 411974 68
Преимущество xlib только в том, что мануал подробный есть.
Аноним  Вс 08 сен 2024 19:26:13 412094 69
охжбл мне же весь парсер переделывать, ведь нужно чобы он ещё и координаты текстур брал
Аноним  Вс 08 сен 2024 23:52:10 412412 70
image.png 76Кб, 1112x811
1112x811
Насегодня - спать.
Завтра - вспомнить, что проблема парсилки оказалась в подсчёте элементов. Из-за того что добавились текстурные координаты и нормали, элементов стало больше, и старая схема с (вначале точки - потом полигоны), уже не работает. А сделать цепочку - точки-текстуры-полигоны, было бы ошибочно, так как не все модели содержат текстуры и нормали.

Зря узнал про существование С++. Теперь меня мучают мысли, что я занимаюсь полной хернёй.
Прогал бы на С++ мог бы несколько типов моделек сделать, для удобства. А так, начнёшь второй тип моделек делать - опять проблемы будут.
Аноним  Пн 09 сен 2024 12:52:42 412735 71
image.png 29Кб, 1376x819
1376x819
доблае утличка.
Удалил все функции count, и сделал процедуру которая считает вообще всё: и точки и текстуры и полигоны, и всю инфу записывает в массив.
Теперь всё работает.
Тут я понял, что у меня в программе предполагается, что модель содержит хотя бы одну точку и хотя бы один полигон. При попытке загрузить модель только из точке, программа упадёт при завершении, потому что будет пытаться очистить поле "полигоны" которое и не было заполнено вовсе.
Также и если модель вообще ничего не содержит (ни точек ни полигонов), при попытке очистить программа ляжет. Хз фиксить это или нет. С одной стороны: надо чобы всё работало, с другой: а зачем загружать модельки без полигонов?! в чём суть то? они всё равно не будут видны. Тогда уж проще отдельно сделать структуру "облако точек".
Аноним  Пн 09 сен 2024 16:18:31 413223 72
image.png 135Кб, 300x210
300x210
Так.. Я понял что делать камеру и сцену пока рано. Надо разобраться с выводом на экран.
Я кажется понял, что в играх используется двойная буферизация, за это на sdl и отвечала flush вроде. Пока один буфер рисуется, другой выводится. Поэтому, для начала проделать более так сказать "низкоуровенвую работу" (в том смысле, что мы занимаемся по-сути выводом кадра в видеопамять, а не самой графикой), сделать функции которые бы отрисовывали кадр, типо draw frame, и потом уже реализовывать осточертевшое тридееее, с камерами и сценами и пространством.

И ведь это правильно. Сцен и уровней должно быть много. А кадр всё равно один отрисовывает.

Тут правда я понял, что мне лучше бы изначально начинать с 2д огрызков от игр, а не полноценных 3д игр. Почему? Потому, что я понял, что 3d объекты на уровне могут быть тесно связаны с геймплеем. А могут не быть связаны, могут быть просто декорацией. Нужно ли для какого-то объекта считать столкновения или не нужно - это довольно не тривиальный вопрос с точки зрения программирования на С. Тут язык топорный.. вначале нужно три раза подумать, а потом написать, иначе если не так напишешь - всё заново переделывать придётся. Поэтому, лучше заранее придумать некоторую "игру" (в кавычках потому что игрового процесса никакого не будет. Суть только в том что разработать систему которая демонстрировала бы все возможности игрового процесса. Не придумав такую систему, можно напороться на большую такую иглу: графический движок уже будет готов, вот только использовать его будет совсем неудобно в рамках игры, придётся изобретать тысячи костылей либо напроч переделывать графический движок под свои нужны). Поэтому, пожалуй не нужно спешить с камерами. Нужно пподумать о фундаментальных вещах:
время, видеопамять, правила игры (под правилами я подразумеваю общие устройства, которым следует такая программа как "игра". То есть в частности, расчёт столкновений колизий, является правилом игры)
Нужно вначале почесать репу, подумать как это будет работать, потом разработать "прототип", упрощённую модель, и уже потом можно сыпать в неё трёхмерные модельки, затенения, и всё подряд.

В своих мыслях я пришёл к тому с чего начал: "ну и как собственно разрабатывать". Давайте думать. Погуглим немного подрочим, и придумаем.
Аноним  Пн 09 сен 2024 17:54:29 413612 73
Terry Davis - F[...].mp4 4950Кб, 640x360, 00:01:09
640x360
В голове какая-то каша из всего подряд. Так, что пожалуй начну мозговой штурм сам с собой! Накидываю идей на вентилятор

№1. Игру можно рассматривать как набор уровней. Таким образом, с такой точки зрения, создать игру это почти как создать систему хранения уровней.
Что тут можно сделать? Подумать над тем, а по каким правилам мы переходим из одного уровня в другой. И что, определяет эти правила. Являются ли правила перехода между уровнями, свойствами самих уровней. Например, уровни могут храниться в линейном односвязном списке, и тогда в игре может выполняться вызов функции Next_Level(), что переводит игровой процесс на следующий уровень. При этом Netx_Level() сама явно не знает какой уровень следующий. И тогда, последовательность уровней поределяет то, в каком порядке они записаны в структуру.
Или же можно хранить уровни в массиве, и Next_level(int lvl) вызывать в индексом уровня. Тогда порядок уровней становиться не важен, ведь ко всем ним можно обратиться по индексу.

№2 Можно было заметить из предыдущего пунтка, что с "переходом" в новый уровень не всё так гладко. Начнём с того, что, а что такое вообще этот "переход" межу уровенями?! Когда мы в Half-life переходим на новый уровень, у нас заменяется только моделька карты и все entyty на ней. А персонаж то остаётся. Получается, что персонаж - не часть уровня. А значит рассматривать игру как набор уровней уже нельзя. Получается, что игра должна иметь "состояние", помимо уровней. Набор уровней уходит на второй план. Раз уж мы думаем о "состоянии", то исходя из смысла слов, оно должно иметь возможность изменяться во времени (иначе непонятно зачем оно нужно). То есть игра это что-то из событийно-ориентированного программирования. Игра, это некоторый конечный автомат. В игру мы играем. Поэтому, игра должна на вход получать ввод с клавиатуры и мыши, а на выходе показывать нам экран, при этом каждый кадр меняя своё внутренее состояние.

№3. Можно заметить, что и с конечным автоматом не всё так гладно. Представить ситуацию, когда мы запустили игру, и не трогаем клавиатуру. В таком случае, игра должна замереть в одном состоянии. Ну а что ей ещё делать, если нет входных сигналов? Отображать то же самое что отображало. Но ведь персонаж в игре может умереть не по кнопке игрока. Подойдёт к нашему персонажу моб и убъёт его. Ввода не было - а игра должна перенестись на нулевой уровень, в меню. Получается, что игра должна сама в себя играть отчасти. Игра должна сама уметь влиять на своё состояние.
Это всё наталкивает на мысль, что кроме пользователя который вводит команды, должен быть и второй игрок "мир", который собственно влияет на состояние игры совместно с игроком. Нет проблем - мы можем создать отдельный процесс для этого, который будет как искуственный интелект играть в игру.

№4. И снова, нельзя не заметить недостаток. Пользователя у нас два, значит ввода два, а результат - один. Вопрос, чей ввод сильнее? Получается, что нам необходим посредник, который бы и определял взаимодействие мир/пользователь. Игрок бы давал свой ввод на посредника, мир свой, и задача посредника-среды, как раз правильно организовать всё это.
И как раз вот эта "среда" и является непосредственно похоже что игрой.

Пока что вот такие мысли. Надо ещё подумать, и поделать простые програмки в консоли, чтобы посмотреть как будет работать обработка событий от двух вводов.
Аноним  Пн 09 сен 2024 18:57:38 413728 74
Я же уже прокручивал эти мысли! И в прошлый раз я пришёл к выводу, что моя система схожа с Xorg-server. Так и есть.
В качестве клиентов у xorg-serverа выступают программы. Правда, клавиатура и мышь находятся на сервере.

Но в начшем случае немного по-другому. Надо организовать работу трёх процессов.
1.(client) Позльзователь. Может посылать на сервер данные о нажатии кнопок, о нажатии мыши. Может получать от сервера все необходимые данные по отрисовке кадра.
Клиент, впринципе может работать при помощи системного вызова select(). Ведь если отрисовывать нечего, и кнопок каких не нажато, то зачем выполнять работу? Таже в этой части находится и рендер, ведь только на клиенте рендерить и нужно. Рендер должен принимать информацию о сцене и правильно её отображать. Пользователь напрямую управлять игрой не может, он посылает сигналы на сервер.
2.(client) Мир игры. Работает как вечный цикл, причём каждое обновление вызывает системные часы, для определения времени прошедшего с предыдущего обновления. Содержит в себе игровую сцену, и все правила взаимодействия между объектами. Тут нужно придумать реализацию самих "правил игры"
3.(server) Серверная часть игры. Занимается координацией мира игры и пользователя, и хранит общие данные. На сервере харнится "состояние" игры и все необходимые компоненты. Также сервер может выполнять загрузку уровеней, и посылать данные для воспроизведения уровня клиенту 2 (мир). Также, севрер может получать запросы от клиента 1, на управление миром игры, или на явное пререключение уровня (например пользователь нажал esc - значит нужно перейти в меню). Также сервер занимается сохранением состояния уровней и игры. То есть сервер может формировать сейвы, и временные сейвы (например, чтобы можно было выйти из меню).
Аноним  Пн 09 сен 2024 19:51:40 413875 75
С другой стороны, почему бы тогда пользователя не соединить с миром в один процесс.

Или вовсе не сделать всё в одном цикле.

Чьёрт знает. Сделаю какой-нибудь калыч, по типо "чубрики против собачки", где собачка @ уклоняется от чубриков O.
На Ncurses само собой разумеется
Аноним  Пн 09 сен 2024 19:56:46 413885 76
image.png 905Кб, 1000x920
1000x920
Ахах. А что если на дваче такой кринж высрать.. там же постоянно типо делают серьёзные игры, а я приду к ним, создам свой собственный тред назову его "Собачка VS чубрики" и буду срать копеечным говном на ncurses. Ахаха. Ещё и в стим это говно запущу (или хотя бы прифотошоплю и сымитирую что моей игре гринлайт дали) чтобы у доверчивых долбоёбов бомбануло что за какой-то hello world дают миллионы.
Аноним  Пн 16 сен 2024 23:14:08 431585 77
2024-09-17 01-01-18.mp4 6264Кб, 1920x1080, 00:00:20
1920x1080
Что-то я очень грустный в последнее время. Ничего разрабатывать не хочется.

Но вот.. сделал такой эксперемент. тут просто генерируется матрица из случайных букв, и выводится на экран. Получается некоторый конечный автомат, из трёх состояний "меню/игра/пауза". Для начала игры нажимаешь m, и игра переходит из меню в игровое состояение. По нажатию p игра останавливается, и выводит время прошедшее с начала игры. При этом время берётся по системным часам, то есть пауза никак не влияет на время. По идее, весь мир может работать от функции изменения времени. То есть можно считать время прошедшее с предыдущего кадра, а не абсолютное время.

Я так подумал, пользоваться паралельными процессами не обязательно. Что такое вообще параллельный процесс? Он ведь на самом деле не парралельный. Все процессы выполняются в пакетном режиме. То что мы создаём процесс - это мы просто передаём полномочия по управлению операционной системе. Это накладывает кучу очевидных проблем, со всеми этими мьютексами, семаформаи и прочим. В это же время можно всё просто впихивать в бесконечный цикл. Надо только организовать собственное управление, чтобы, например, в меню и на паузе не было активного ожидания. А сам игровой процесс без активного ожидаения немыслим. Так, что зачем нужны паралельные процессы - мне не совсем понятно.
Аноним  Ср 18 сен 2024 16:29:02 433547 78
_ (1).jpeg 63Кб, 736x736
736x736
И опять же, заново.
Пока что представлю что вся игра находится в одном .с файле.
Что у нас есть на поверхности?
Игра - это событийно-ориентировання программа с одним вечным циклом. Сходу, можно назвать 3 состояния в которых может находиться игра:
1.меню, 2.проигрывание уровня, 3, временное меню (пауза)
Действия, которые выполняются в состоянии "меню" кажется не таким сложным: обыкновенная реакция на кнопки и клики мыши. Программа может даже заблокироваться в меню, и быть вычеркнута из планировщика ос, до тех пор пока пользователь не кликнет мышкой.
В следствии нажатий на некоторые менюшки, игра может переключиться в состояние "playing", в котором проигрывается текущий уровень.
Подрезюмировав этот абзац, можно сказать что "игра" - это структура из полей
typedef struct{
enum game_states state; //menu/playing/paused/loading/saving
int level_descriptor; //номер уровня
struct ⚹level; //указатель на структуру уровня
struct ⚹ current_gui; //указатель на текущий 2д интерфейс
} session;

Вот теперь всё сложнее. Как видно из структуры, тут есть поле cur_gui, которое предполагается не просто "двухмерную картинку", а некоторую структуру, с набором "кликабельных" элементов. Игра ведь не просто картинка. И если меню, можно было бы сделать "в упор" просто написав и расставив функции для отрисовки кнопок там где требуется, то в игре такое не прокатит, ведь игра должна изменяться со временем. В игре нужно много что придумать, и без удобного разделения кода тут не обойтись.
Начнём с простого. В отличии от меню, игра, никогда не блокируется. Известно, что игра должна делать следующие действия:
1.Каждый цикл игра считает сколько времени прошло с предыдущего цикла.
2.Каждый цикл, игра отрисовывает текущую сцену.
Так называемую "сцену" я ещё даже не накодил, но как видно из моих предыдущих постов, сцена - это некоторое 3d пространство с камерой и объектами. Грубо говоря "сцена - всё что необходимо для вывода трёхмерной графики в динамике". Сама сцена не содержит ничего "живого" чтобы позволяло объектам двигаться. Объекты и камера двигаются отдельно, а сцена - просто удобная структура которая это всё содержит.
Так, если мы отрисовываем "сцену", то она должна как-то двигаться. Не зря же мы её отрисовываем каждый цикл. Делать всё в главном цикле, очевидно идея глупая. Так, что можно создать процедуру в которой бы производились все необходимые изменения над сценой.
UpdateScene(scene ⚹cur_scn);

Продолжаем думать дальше. Допустим, у нас есть функция которая обновляет свойства объектов, по нажатию клавишь. Что с того? Нам ведь нужна игра, а не Paint3D для простмотра трёхмерных объектов. Следовательно, кроме клавишь, должна быть ещё и "игровая логика".
Что же я подраумеваю под "игровой логикой"? Это по-сути и есть игра. Это набор правил, которым следует программа, чтобы воспроизводить тот результат, что мне нужен. Например, если мы идём вперед, а впереди нас бочка - мы не должны проходить сквозь бочку (а если кусты, то должны). То есть функция, которая прежде просто перемещала персонажа на координату вперёд, должна ничего не делать, на том основании, что уравнение вычисляющее пересечение мешей, выдало положительный результат. Вот примерно так....(продолжение в следующем посте)
Аноним  Ср 18 сен 2024 16:29:44 433552 79
7697dee8-e90d-4[...].jpeg 109Кб, 736x952
736x952
(продолжение предыдущего поста) Тут автоматически возникает несколько соображений:
1.A выгодно ли нам вообще вычислять сложное "уравнение" по пересечению поверхностей? Это же всего лишь игра. Почему бы не запретить персонажу проходить сквозь радиус от центра бочки, а не от самой сложной геометрии бочки. Это соображение подталкивает нас на мысль, что вообще-то могут существовать и "невидимые" объекты. Этот радиус - получается, невидимый циллиндр колизий. Он есть в игре, при этом передавать его в функцию для отрисовки абсолютно бессмысленно, ведь это даже не трёхмерный объект. Это наталкивает на мысль, что должно быть что-то обобщённое, типо "entity" или "игровой объект" - это ни как таковой объект, а как некоторая сущность, которая может быть связана с 3d мешем, а может и не быть.
2.Если продолжить мысль, то получается подобных функций может быть много. Нас ведь могут интересовать совершенно разные вопросы внутри игрового мира. Не обязательно связанные со столкновениями. Например, вопрос, "а находится ли игрок на поверхности? если не находится то пусть падает" Или "игроку нанесён урон? или был промах" или (а нужно ли поменять камеру для отрисовки сцены?). Собственно, необходима некоторая "система" функций-отработчиков, которые бы вычисляли какой-то факт (то есть отвечали на вопрос "да/нет") и может быть в качестве побочного эффекта что-то бы изменяли на уровне, либо же выдавали некоторые данные для изменения.
Собственно, появилась идея "разделить" всё что у нас есть на три категории:
1) Данные - это сами 3д модельки-меши, текстуры, объекты коллизии, точки, камеры итд. Короче, всё что представляет из себя тип данных "структура".
2)Свойства - это некоторые отдалённые характеристики данных. Грубо говоря, это свойство, это к какой "группе относятся" данные, какое значение они имеют для игры. Свойства можно описать тремя полями
typedef struct{
enum entities usage; //назначение-свойство объекта (невидимая декорация, или объект для расчёта столкновений). Благодаря этой информации, другие функции знают, нужно ли рассчитывать колизию для объектов.
enum data_types type; //тип структуры (мэш, или точка, или вовсе камера).
struct ⚹pointer; //указатель на эти данные
} entity;
Возможно этот тип является избыточным, либо написан он с избыточными/не теми полями. В будущем я это уточню. Но прямо сейчас, у меня возникло желание сделать поле usage, типом "список отработчиков". То есть сделать так, чтобы было несколько "свойств", и весь список свойств тупо полистывается, и данные из него используются в качестве функции Poll, для обработчиков.
3)Действия. Это некоторый глобальный массив, из указателей на функции. Каждая функция возвращает логическое значение 1 или 0, а также либо выполняет какой-то побочный эффект, либо (если побочные эффекты сделаю программу недостаточно гибкой) вместо побочного эффекта возвращает универсальный парамер, который в дальнейшем может использоваться для изменения объектов уровня. К слову, одной такой функцией я уже пользовался при кодиге графики. Это функция OutOfCanvas(), которую я так долго и многострадально переписывал. Она получает объект - точки для рисования линии, и в качестве результата возвращает истину либо ложь. Если функция возвращает истину - это означает, что линия "полностью выходит за рамки холста", то есть такую линию не имеет смысла отрисовывать, ведь она невидимая. Если же хотя-бы кусочек линии попадает на холст, то функция "обрезает" ненужную часть и передаёт новые координаты только видимой части линии, "теперь то линия находится на холсте" пишет функция в поток. Если же линия изначально помещалась на экран, функция ничего не делает (хотя правильнее было бы сделать вариант, где она даже не вызывается, чтобы лишний стековый фрейм не тратить)

Таким образом, расчёт геймплея сводится к выполнению отработчиков над объектами игры, и последующем витвлении. Где-то тут, и следует добавит само понятие "игровой уровень", как упорядоченный набор всех игровых объектов. Пока, что я предполагаю "отрисовывать" сцену отдельно от всего уровня, ведь если бы функция UpdateScene принимала себе на вход именно "уровень", то ей приходилось бы каждый кадр выполнять поиск объектов для отрисовки. Зачем? если можно подавать функции объекты которые заранее необходимо отрисовать, т.е. сцену.
Это пока что очень поверхностное описание. У меня на реализацию простого конечного автомата ушло столько строк, что уже хочется что-то "отделить" в модуль. А тут ведь и расчёт колизий, и всего. Так, что скорее всего это выйдет не одним модулем, а будет неоднократно разбиваться.
Главное что я сделал - я в голове построил некоторую "модель" движка. И в дальнейшем буду пытаться её построить, посмотреть как она работает. Фронт работ обозначен, трудиться можно в двух направлениях
1) Создание и тестировка игры с самого её начала. То есть реализовывать вот то, что я настрочил в предыдущем посте (когда по клавише p программа становиться на паузу). Вот таким же образом нужно подумывать некоторый "шаблон" для подгрузки уровней. То есть делать игру непосредственно с начала.
2)Делать игру с конца. То есть копаться в способах вывода звука, например.
Улучшать и модифицировать графическую часть движка, делать эти самые "сцены", закодить текстурки наконец-то.

Кстати, относительно второго пункта. Я ведь нашёл доступ к видеопамяти! За два месяца, я таки нашёл устройство /dev/mem, и нашёл там видеобуффер для своего VGA устройства. Но это всё такая бесполезная затея... Какбы.. то что он выводит графику мешая другим программам-то это я предвидел, в этом ничего необычного нет. А вот то, что видеопамять храниться не "прямым" массивом, на это я почему-то не рассчитывал. Я вывел на экран простой градиент, и он начал выводиться небольшими двойными полосками, сверху которой была тёмная часть, а снизу светлая. Видимо, в целях оптимизации, видеобуфер состоит из некоторых "страниц"-массивов, которые располагаются в шахматном порядке. Получается, чтобы вывести что-то мне нужно ещё и свой драйвер для монитора писать. Таким образом это уже нихрена не "Games for FreeBSD"... Это "Games for моя личная видеокарта and FreeBSD ", нахуй. Нет такой глупостью я заниматься точно не буду. Ещё и пытаться организовать доступ к разделяемой памяти.. не нужно. Буду использовать Xlib. Для звуков какие-нибудь стандарнтые драйвера есть наверное.
Аноним  Ср 18 сен 2024 16:59:45 433626 80
И.. совсем забыл. Реализация анимаций!
Как сделать самую простую анимацию? Ну вон, посмотрите выше, я трёхмерный логотип FreeBSD замоделлил и отрендерил. Он поворачивается. Что это если не анимация? Для простого платформера подойдёт: персонаж двигается - шарик крутится, персонаж стоит - шарик стоит.
Как обычно, переходим от простого к сложному. Если так посмотреть - варвар с топором отличается от шарика только тем, что в нем координата меняется не у всех точек, а только у некоторых (например, у точек руки и ног).
Так, что мы можем в модуль для импорта 3d мэшей, добавить не только функции, которые бы позволяли двигать весь объект, но и те, которые двигают некоторый список его точек.
Тогда, реализация танцующего варвара, представлялась бы как код для станка с ЧПУ: функции одна за другой просто бы переносили его точки кадр за кадром.
Нельзя не заметить, что хранение анимации в таком виде, весьма ресурсозатратно: это ведь сколько кадров требуется чтобы простую ходбу реализовать. Поэтому, вместо покадровой анимации мы можем реализовать ключевую.
Функция для ключевой анимации получает только начальное состояние и конечное, затем вычисляет направление по которому следует двигаться, и затем циклом добавляет координаты до тех пор пока модель не "приедет" в конечное положение. Получается "плавный переход" между кадрами. И тогда файл анимации будет содержать только наборы ключевых точек, и количество итераций, за сколько до них нужно дойти.
Можно либо написать свой аниме-модуль, либо впихнуть поддержку анимации в wavefront-парсер. Написать свой модуль более логично, так как появляется некоторый отдельный тип "анимация" .anim. С другой стороны, лучше бы всё соединить для компактности, чтобы не засорять всё тысячью модулей.
Аноним  Ср 18 сен 2024 17:05:28 433636 81
image.png 14Кб, 458x322
458x322
Аноним  Пт 20 сен 2024 00:42:29 436493 82
2024-09-20 02-12-38.mp4 6501Кб, 1920x1080, 00:00:21
1920x1080
Во! Правильно сказал анон, что лучше начинать с 2d игр. Ncurses минималистичнее, и в целом отражает суть. Поэтому пока что нужно потренироваться на вот таких текстовых програмках, чтобы выявить подводные камни.

Создал протитип, описанной выше системы. Тут меню, является по-сути уровнем, но все объекты на нём имеют тип "кнопка" и поэтому не могут никак перемещаться.
Писать такой уровень-меню оказалось крайне неудобно. Формат для уровней я решил сделать простой: просто в каждую строку записаны атрибуты одного объекта, и сколько строк - столько и объектов на уровне.
Уровень воспроизводится в зависимости от свойств объектов. Если объект имеет тип "персонаж", то по кнопкам он перемещается.

Как видно, в меню, программа работает в "блокирующем" режиме, и ничего не делает пока пользователь ничего не вводит. А в режиме "игра" программа работает всегда (время идёт).

Тут сразу возникает много вопросов по организации кода. Во-первых, хранить все свойства в одном "объекте" неудобно. Некоторые свойства, например касаются только кнопок, а хранятся они всегда. Нужно как-то расфасовать сущности на подсистемы, чтобы кнопки могли существовать только для гуи, а объекты только для уровня итд.
Больше того, меня сильно беспокоит чистота кода. Я читал, что "конечный автомат не может управлять наступлением событий". Вот такая вот фигня. А у меня он фактически управляет: из функции MenuKeyResponse, можно перекочевать в функцию, которая изменяет состояние на loading. Лоадинг и вовсе напрямую меняет состояние на playing, единственно что делая - подгружая требуемый уровень. А Playing может снова вызвать Menu.
Хотя с другой точки зрения, а что значит "извне"? Может быть то, что функция подгружает новый уровень, это вполне себе "из вне", она же не знает когда уровень завершит загрузку.
Так, что хз если честно. Надо с этим разобраться. главное что какой-то прототип есть.
Аноним  Пт 20 сен 2024 14:30:28 437090 83
chubreks.mp4 8912Кб, 1280x720, 00:00:08
1280x720
Откомпилил статически для винды, через mingw по-приколу. Запустилось.

Сделал коллизию. Пожалуй на этом нужно завершать, потому что уже пошёл говнокод. Основное понятно, что нужно чётче продумать зону "отвественности" каждой системы. Нужно точно рассчитать, что система будет делать, а чего точно не будет делать, и из этого разделить данные на группы, а программу на части. Вот в этом примере всё попало, где попало, а поле "коллизия" у объекта вообще не используется.
Аноним  Пт 20 сен 2024 23:22:36 438212 84
В последнее время меня так ко сну клонт. Чъёрт знает что. Сложно думать. Мотивация есть, а думать не могу, всё в тумане каком-то, как угашенный залипаю в одну точку и могу просидеть так день.

Надо соображать, страраться.

Всё-таки сделать игру кросплатформенной выгодно ещё и с точки зрения структуры кода. Отдельный модуль обёрток функций для Xlib позволяет рассматривать ввод-вывод, как отдельную часть движка.
Когда мы реализуем функции ввода-вывода сразу на Xorg, мы перемешиваем зоны отвественности. Нам нужно мыслить и с точки зрения api xorg-a ( конкретные окна, дисплей, ивенты) и с точки зрения игры (двойной буфер, кадр, итд). То есть код заведомо получается слегка "грязный" для понимания.
Если же, всю конкретику xlib инкапсулировать в модуле core_xlib.c, то тогда, мы уже будем размышлять с точки зрения абстрактного фреймворка. "создать окно" и "вывести кадр" для нас становятся соверешнно понятными функциями, ведь они посылают вывод не в конкретную нагромождённую загагаулину XPutImage(*куча параметров*), а в вполне себе ёмкую UpdateFrame(frame *f).

Кстати, возможно поэтому в dwm и существует модуль drv. Я как-то его открывал, и находил там незначительные функции типл draw_rectangle, которые тупо копировали XDrawRect. Я думал: а зачем они это наговнокодили!? А теперь похоже что понимаю, что не зря!

Кстати, заметил, что я перестал стесняться писать большие модули сразу же. Ранее, я после каждой функции запускал компилятор и проверял её. Почему? Потому, что я опасался, что вот если возникнет ошибка, то я её в таком большом коде больше никогда не найду, и брошу всё и начну писать заново. Теперь как-то "приловчился". И ошибок стало меньше, и править их стало очевиднее. Ставишь printf в случайное место и смотришь результат, находишь подозрительные места которые могли повлиять на негативный результат и так всё отлаживаешь. Вот напишу свой движок, тогда наверное навыки разовьются и смогу вообще любой чужой код на раз-два прочитать!
Аноним  Сб 21 сен 2024 00:18:52 438347 85
>>438212
Важная заметка! похоже что реализация зажатя клавишь как раз лежит в том числе и на этом модуле!
Если тип Window из Xlib, можно заменить простой структурой window . Нам ведь не важны делали реазации окна, единственное что мы делаем - это выводим в него, и знаем его ширину. Остальное нас не волнует, поэтому инкапсулировать window довольно просто. Чего не скажешь об XEvent, ведь для реализации программы нам нужен доступ к его полям. Поэтому нам придётся сделать свой event! и свой PollEvent(), который бы и содержал оболочки для эветнов. Также, сюда автоматически стоит встроить focusin, чтобы отключить залипание. И раз уж у нас есть "свои" события, то зачем нам всё подчистую копировать у xlib, если можно сделать события типо key_pressed чтобы обозначить именно длительное зажатие клавиши.
Аноним  Сб 21 сен 2024 21:46:15 440180 86
Я пришёл к тому, что вообще нужно сказать отдельный интерфейс, который бы мог работать с "комбинациями" клавишь, "двойными нажатиями" итд.
Аноним  Сб 21 сен 2024 22:27:39 440429 87
image.png 75Кб, 884x577
884x577
нагуглил в интернете про какие-то "паттерны".
Надо почитать, звучит интересно.
Аноним  Сб 21 сен 2024 23:47:41 440719 88
А "паттерны" оказались годнотой! То что нужно. Это по-сути готовые "подходы к созданию".
Я и ранее использовал их, но я названия не знал.
Причём, я часто просто копировал целые функции из одного проекта в другой, чтобы "пользоваться удобной фигней и не заморачиватьчя". Один раз протестил - тащу повсюду. Например я сделал один раз реализацию односвязного списка, и функции, которые позволяют в него что-то записывать/извлекать, или вовсе уничтожить весь список сразу. У меня всегда голова ломалась на этих списках, потому я один раз понял, один раз сделал хорошо, а остальное время тупо эти функции тащил, изменяя лишь поля ячейки списка. Такой паттерн, когда задают "обьект" и операции над ними называется "фабрика". Правда, вот чем это от классов отличается? Добавить в структуру указатели на функции - вот тебе и методы класса.
Также, ещё одна фабрика - это двойной массив. Мне постоянно лень его правильно инициализацировать (это занимает много строк), поэтому у меня есть такие же функции типо init_canvas которые просто двухмерный массив инициализируют, и уничтожают.
Кроме фабрик я ещё использовал паттерн "стратегия", который я называл "callback" функциями или хэндлерами. Чем они отличаются я не знаю. Суть та же: некоторая функция принимает в качестве параметра другую функцию. И подобных "других функций" делается много, и все они рассчитаны на какое-то различное воздействие над данными.
На практике я такой паттерн не применял. Только в учебных целях сделал, и в скором времени понял что это какая-то безделушка.
Хочется всегда применить этот подход, но, я не понимаю зачем, ведь все это запросто заменяется на набор if() else.
Следующий паттерн "одиночка", я вообще не применял, и немного не понял, зачем он нужен. Суть в том, чтобы создать некоторый единственный объект. И если он неинициализирован, то при обращении он бы инициализировался и затем работал как обычно , а если инициаоищипован, то просто работал бы как обычно. А зачем? Где это может пригодиться?
Наиболее интересным мне показался шаблон "наблюдатьель". Вот это наверное можно попробовать применить для обработки событий.
Суть этого шаблона, что вот есть "объект", и если что-то в нем изменяется, все кто с ним связан, должны обновить информацию.
То есть, две основные функции и одна полочная:
1.Инициализировать объект и наблюдателей
2.Изменить значение обьекта (при этом после изменения должен быть вызвана функция для оповещения об этом наблюдателей.
3. static Оповещение наблюдателей. Тут у всех наблюдателей меняются свойства в зависимости от нового значения объекта.
Вот такие штуки интересные.
Аноним  Вс 22 сен 2024 16:44:29 441817 89
image.png 663Кб, 564x1136
564x1136
image.png 436Кб, 600x1062
600x1062
CubeCloneXperim[...].gif 395Кб, 500x384
500x384
https___twitter[...].gif 9443Кб, 374x375
374x375
Вот в таком стиле охота игры делать. Лоу-фай триде.
Аноним  Вс 22 сен 2024 23:48:20 442624 90
image.png 106Кб, 1919x1055
1919x1055
Так, сделал "зажатие клавишь".
То есть, у нас есть объект event, который может заполняться чем нибудь после вызова PollEvent (то есть в его полях появляется информация о длительности зажатия клавиши, итд). После того, как эвент получен, вызывается функция Notify Obsevers которая отсылает списку функций-наблюдателей, новые параметры на отработку. Функции-наблюдатели имеют одинаковый профиль. Так, что мы может указатели на такие функции добавлять в список и исключать.
Каждая функция, что получает event, как-то на него реагирует, изменяет как-то устройство сцены.
Сам объект events->keyboard имеет массив из 104 элементов. Каждый элемент равен 1 или 0. Если 1, значит клавиша зажата, если 0, значит не зажата. Также есть поле hold, которое отвечает за время которое продержалась клавиша.

Идея кажется довольно топорной и неудачной, но может потом когда будут возникать трудности, придумаю что-нибудь.
Ведь чисто технически, вдруг игре нужны будут "поля для ввода", чисто текстовые, такие же как везде. Проще было бы сбросить весь код по зажатию клавишь, и вернуть на момент ввода всё в каноничный режим "автоповтора".

Ладно, посмотрим. Может всё это вообще удалять придётся. Главное, что пока что я понимаю, как переоборудовать весь этот модуль под ncurses не меняя при этом функций.

Также я добавил объект "фрейм". Его суть в том, тчтобы иметь два буфера. Функция UpdateFrame выводит первый буфер на экран, и в случае, если активирован флаг Ready, то меняет буферы местами, а если неактивен, то оставляет второй буфер дозаполняться.
Аноним  Пн 23 сен 2024 19:19:56 443644 91
2024-09-23 21-08-17.mp4 6102Кб, 1920x1080, 00:00:20
1920x1080
Оно работает!
Я правда так и не понял, а зачем двойной буфер вообще нужен?
Думал, что для того, чтобы выводить из одного буфера, а второй заготавливать. Но у меня же нет паралельных программ. Отчего получилось вот такое "дрожание" нарисованной картинки.

Но в целом паттерн Observer реализован. Наблюдатель Pencil, рисует пиксель, когда клавиша зажата.
Единственный минус, а как связать наблюдателя с системой? Я так навскидку добавил ей параметр frame, чтобы наблюдатель имел доступ к картинке. Но ведь по-идее он должен иметь доступ и к игровой логике.
То есть он должен быть разнообразным. Есть идея, сделать так чтобы он возвращал какое-то значение, и это значение было бы управляющим для других программ. Например, он бы возвращал число, исходя из которого вызывался бы отработчик уже в главной программе. То есть
if(Pencil(e) == 25){
SetPixel(X,Y)
}
Вот типо такого. ЧТобы отработчики возвращали просто универсальный идентификатор, исходя из которого выполнялись бы программы. То есть правильно было бы функцию Pencil назвать не Pencil, а MouseHold. Таким образом, наблюдатели - это универсальные наборы клавишь.
Аноним  Пн 23 сен 2024 22:05:39 443949 92
И нафиг я туда код паттерна "наблюдатель" запихнул? Он же совсем никак не связан. Сейчас вот переделал модуль под SDL и код "добавления в список" остался тем же".
Аноним  Пн 23 сен 2024 23:23:16 444175 93
image.png 26Кб, 300x271
300x271
Впизду.
Я понял, что моя система - полная хуйня. Кнопки управления залипают. Почему? Потому что они ориентируются на неправильные переменные. Короче, всё на переделку.
Аноним  Пн 23 сен 2024 23:35:45 444194 94
Или стоп паника, похоже что нашёл ошибку. У меня для некоторых ветвей else не был прописан выбор ивента. Из-за этого события focusIn, не ставили нулевой ивент, но и не меняли его на какой-то другой. Вот, теперь перед каждой итерацией событие это none, и уже потом если необходимо ему присваивается значение. Залипать перестало.
А то я уж было в демонов не уверовал
Аноним  Пн 23 сен 2024 23:52:56 444214 95
Но всё равно, сделал я какую-то откровенно путаницу.
Типо, вот по-идее "наблюдатели" должны реализовывать все механники клавиш. И они могут сделать реакцию, скомбинировав "состояние" клавиатуры. Но они ведь нихрена не могут реализовать такие вещи как "KeyToggle" (не знаю как назвать, ну короче, когда нажимаешь и отпускаешь клавишу, и результат 1, ещё раз нажимаешь и отпускаешь - результат 0. Как рычаг короче). Чтобы реализовать такую механнику нужно создавать отдельную переменную, которая бы отвечала на вопрос "активна ли кнопка". И тогда получается, что управление кнопками выходит за рамки функций-наблюдателей. Тогда, внимание, вопрос: нахрена эти наблюдатели нужны?!.
Вот и всё.
Надо придумать что-то более компактное.
Аноним  Вт 24 сен 2024 13:34:12 444614 96
image.png 42Кб, 1681x857
1681x857
Упростил код. Теперь тут нет всяких бесполезных нагромождений функций, связанных со временем нажатия клавишь. Убрал вообще все бесполезные типы "время" "мышь" "клавиатура" "кадр", нафиг всё это нужно. Теперь типа всего два "окно" и "контролс" (кнопки, мышь хз, короче всё что управляет).
Окно - это просто инкапсулированный тип "окна" для данного фрейморка/библиотеки. Окно можно отрисовать (на самом деле отрисовывается только буфер, а окно выводится только в функции UpdateFrame. Дело в том, что некоторые библиотеки могут не иметь никаких фреймов. Например SDL достаточно высокоуровневый, что там можно выводить сразу в некоторое окно. Так что окно, и буфер для окна тут "склеены" в одну структуру, для удобства).
Контроллеры - это реефецированная структура, для данных от устройств управления. hold - содержащий информацию нажата ли кнопка. Toggle - массив, содержащий информацию относительно механники кнопки с самоподхватом. Индекс массива - номер кнопки. Причём кнопки мыши считаются там же (так как я не заметил особой разницы между кнопками клавиатуры и мыши, разве что кнопки мыши могут остутствовать. В любом случае, Xlib представляет абстракцию кнопок в keysym (есть конечно и keycode, но зачем его использовать если разрабочтики xlib позаботились об абстракции вместо меня)).
Поля x и y - это координаты куда перемесилась мышь.
Поле type - записывает тип события (none. press, release) то есть нажатие клавиши, отпуск клавиши, или ничего.
Таким образом, можно сформировать три макроса PRESS HOLD и TOGGLE, каждая из которой, формирует логическое выражение, касаемо нажата ли клавиша единично, зажата ли, и была ли нажата ранее.
Теперь всё работает как по маслу. Главная цель выполнена - абстракция от конкретного фрейморка. Для теста я переделал модуль под SDL и он прекрасно работал. То есть теперь уже можно пытаться реализовать какие-то механники.
Вот первая простейшая механника - Pencil. Нажимешь клавишу "а" и теперь ты можешь рисовать, удерживая кнопку мыши. Нажимаешь ещё раз "а" и режим рисования исчезает. Работает без залипаний.
Аноним  Вт 24 сен 2024 14:14:09 444641 97
Ещё надо бы прикрутить функцию SetCanonical которая бы возвращала каноничный режим ввода. Например, если в программе есть поле, в которое нужно ввести текст. Стандартные средства xlib вполне себе пригодны для ввода текста, потому что включено автозалипание итд. Поэтому неплохо было переводить программу обратно в некоторый "стандартный" режим ввода.
К тому же, что касается шрифтов, нужно использовать функции xlib или ещё чего, ведь сам я работать со шрифтами и текстом никакого желания не имею. Мне хватило, что я в детстве пытался сделать красивый шрифт, а он вышел кривым и косым. Есть уже FreeType и прочее - вот этого достаточно. Писать собственную библиотеку шрифтов и текста - это как писать собственный xlib.
Я же на самом деле избегаю движков и SDL не потому что они плохие. Даже нет так. Движки точно не плохие, godot какой-нибудь условно, довольно приятный движок и по документации и по комплектности. Дело в другом. Дело в том, что готовые технологии - не панацея, и даже на мой вгляд вред для обучения. Обмазывясь кучей фреймворков, ты делаешь:
А) (делаешь) cвой код менее портативным. Некоторые библиотеки наотказ не компилируются статически (SDL например). А под Windows и вовсе, обычным делом является DLL, так что неприятно было бы получить программу которая заваливает сообщениями "ошибка, dll qt sdl gtk openai opengl не найден). Я считаю важен принцип "чем меньше зависимостей, тем лучше". В идеале программа вообще должна запускаться на голой операционке. Но на FreeBSD нет никакой стандартной поддержки графики, а Х11 стал практически каноничным (всё пишется под иксы). Поэтому я считаю что X11 использовать допустимо, ведь он есть у 99% десткопов. Учитывая что я обернул все функции xlib в "обёртки", программа становится портативной, и если так уж вышло что xlib нет, то адаптировать программу под Wayland не составит труда. Да хоть под свои драйвера адаптируй, суть в том, что программа отделена от конкретной библиотеки. В случае, когда таких библиотек много, отделиить программу уже не так просто.
Б)Ты делаешь одинаковые действия. Не зря в народе бытует мнение, что веб-фронтэндер - это макака. Поиск библиотек на каждый пук оставляет разработчику ничего: все сложные задачи за него выполняют библиотеки, а сам он просто пишет програмки не сложнее hello world. Таким образом, программирование превращается в рутину, которую легко заменит ЧатГПТ. Да да, чат гпт между прочим такой же тактикой и идёт: он тупо ищет готовую библиотеку и выдаёт код на пайтон. Чем чатгпт отличается от веб-макаки? Тем что чатгпт более вежливый. Для того, чтобы совершенствовать навыки необходимы нетривиальные задачи. Суть библиотек - свести нетривиальные задачи к тривиальным. Поэтому, невозможно развиваться используя библиотеку на каждый пук. Необходимо отказываться от библиотек. Необходимо изобретать велосипеды. Библиотеки можно использовать исключительно тогда, когда разработка их функционала не представляет никакого так скажем "научного интереса". То есть, вот я создал свою библиотеку для работы с TGA картинками. Я буду её использовать для хранения текстур. Почему? Потому что она милималистична, она моя, и если что я смогу её отладить. А если я захочу сделать свой растровый редактор картинок, то тогда я выберу стороннюю библиотеку для работы с картинками. Почему? Потому что я в общих чертах понимаю как происходит сжатие и хранение в памяти картинок. Мне не интересно изучать особенности jpeg формата, тем более что уже полно добровольцев которые сделали это за меня. Поэтому, от того что я реализую очередную библиотеку для нового формата скилы у меня не возрастут. Там ведь используются все те же принципы и конструкции. А вот если я релизую собственный гуй, и инструменты для рисования - вот это уже что-то новенькое.
Вот также и при разработке игры: мне лень разбираться в форматах звука, в драйверах видеокарт, поэтому я использую Xlib + OSS. Технологии железные и проверенные. А разрабатываю саму игру + некоторые модули, типо графический итд.
Когда я сделаю свой всрато-движок, возможно я перейду на OpenGL и на более нормальные технологии, которые реализовали профессионалы до меня. Но пока мне интересно сделать свои.
Аноним  Вт 24 сен 2024 15:28:16 444758 98
Добавил к функции PollEvent параметр mode. Пока что он воспринимает один флаг BLOCK_POLL и NON_BLOCK, т.е. будет ли блокироваться программа при выполнении опроса клавишь, или нет. Если программа не предполагает внутреннего мира (например меню игры), то пусть она блокируется. А если предполагает, то блокироваться она не может, потому что потом наступит обновления других событий.
Далее, я придумал следующую идею для "наблюдателей".
Наблюдатели теперь имею в качестве второго параметра не окно, а некоторый тип Changes (скорее всего список). Каждый отработчик добавляет свою ячейку в список для изменений. И затем этот список подаётся в функцию UpdateWorld, которая реагирует на изменения в своотвествии с игровой логикой.
Тогда наблюдатели тупо реализуют какую-то клавомышечную механнику, и заполняют декларацию changes, чё нужно поменять. А функция UpdateWolrld уже это всё меняет.
Аноним  Вт 24 сен 2024 15:34:31 444763 99
Таким образом в режиме реального времени можно "подгружать" механники нажатия клавишь, добавляя их в список и удаляя.
Правда, для того чтобы добавить что-то в список нужна механника клавишь?! получается в главном цикле управляется то, какие механники влияют на игру, а какие нет.
Аноним  Вт 24 сен 2024 16:03:56 444789 100
image.png 8Кб, 951x484
951x484
Вот примерно такой цикл получается. Верхняя линяя нарисована пунктиром, потому что PollControls и DrawSession, никак не связаны. DrawSession, отрисовывает сессию в текущий кадр, в то время как PollControls опрашивает дисплей на наличие изменений в клавишах. То есть эти две функции пользуются совершенно разными полями в струкруте window. В то время как controls полученый из Poll, передаётся наблюдателям, для обработки и выдачи ивентов "e", и список ивентов отправляется на UpdateSession, чтобы повоздействовать на игровую сессию, (в общем-то сессия может обновляться и без событий, событие тут как дополнительный фактор), и затем функция DrawSession, выбирает ту часть сессии которая отрисовываема, и рисует её (например поле "сцена")..
Аноним  Вт 24 сен 2024 16:10:33 444793 101
Остаётся вопрос, а какой тип данных выбрать для списка "e"?
Обычный int, который означал бы идентификатор изменений?
А может указатель на функцию? Тогда можно было бы сразу применить изменения. Но тогда у функции должен быть одинаковый профиль. А на с int можно идентифицировать всё что угодно.
Аноним  Вт 24 сен 2024 16:27:46 444808 102
С другой стороны, а нахрен нужно это всё, когда можно напрямую подавать в функции-наблюдатели параметр session, чтобы они изменяли в сесии вообще всё что хотели.
Аноним  Вт 24 сен 2024 22:37:13 445428 103
2024-09-25 00-30-05.mp4 7073Кб, 1920x1080, 00:00:23
1920x1080
Сделал кнопку из Windows 7. По её нажатию активируется рисовака рандомными цветами!!
Собственно, первый элемент гуя.
Дальше только усложнять - сделать кнопку более настраиваемой. Сделать другие типы графических элементов. И сделать список всех элементов, который назвать "гуй". И уже сделать порядок: отрисовывать фон->отрисовывать гуй.
Аноним  Ср 25 сен 2024 23:50:58 447409 104
image.png 57Кб, 1232x838
1232x838
Реализовал шрифты.
Ну... как реализовал... нашёл на гитхабе stb_truetype.h и тупо включил его через инклуд. Я хотел его отдельно откомпилировать, но он отдельно почему-то не компилируется - начинает выдавать ошибки. Короче, решил использовать так, как задумано автором. А задумано довольно странно - файл тупо инклудится в проект, и получается весь ворох функций просто в мой модуль компилится. Ну и ладно. Он всё равно вроде кросплатформенный, а это главное.
Аллиасинг и сглаживание - насрать, главное что буквы хоть рисует, и на том спасибо. Функция просто "в лоб" рисует текст, и ничего более.
DrawText(w,200,200,50,f,0xffAA1122,"Caaaп эскейпчан фан!");
Вот так примерно. тут f - это шрифт. Думал сделать структуры типо "текст" но потом не понял зачем. В чём смысл, если текст удобнее хранить просто как строку.
Что ещё сделал? Ещё сделал побочный иструмент tga_to_pixmap, который tga-картинку переводит в массив const int [] = { 0xFF00AA11 ...
Таким образом проще хранить всякие иконки, кнопки и прочее. Я думал, ещё таким образом сделать один "встроенный" шрифт, который был бы всегда по-стандарту. Но это уже на будущее.
Короче, наговнокодился и рад!
Аноним  Чт 26 сен 2024 00:14:56 447443 105
Чем всратее - тем лучше. Получается эдакий "гараждный стиль". Игра в стиле поделок 90х. Не понимаю людей, которые отказываются разрабатывать свой движок. Никто же не говорит, что нужно разработать хороший движок. Никто не просит стать пизже unreal engine. Достаточно сделать что-то, что демонстрирует какой-то аспект. Например, вот добавил я шрифты - теперь мне не придётся отрисовывать тысячи кнопок меняя только название. Более гибкая технолгия. Теперь на кнопку можно нацепить "шрифт" и сделать хоть 100 таких кнопок.
Сама кнопка правда не масштабируется, и анимация у неё всратенькая - она просто менят указатель на битмап, когда на неё нажимаешь или наводиль. В Windows 7 было не совсем так, на семёрке когда ты наврдил мышь на кнопку - под мышью был красивый эффект градиента. Надо сказать, седьмая винда вприципе самая красивая. Не понимаю почему так любях XPюшу. У икс-пи вполне обычный дизаин. Вообще, если брать старые дизайны, то у xorg как раз по-красивее будет. А вот семёрка уже была с кучей подсветочек эффектов, всё полу-прозрачное аква. Красота в общем. Потом зачем-то ушли в плоский "минимализм" который по какой-то причине систему нагружает намного сильнее чем семёрочный фрутигер аеро.
Если потрудиться, то интерфейс семёрки можно переписать на иксах. В этом ничего принципиально неразрешимого нет: кадр зарисовывать умеем, мышь отследить можем, следовательно нужно сделать что-то на подобии "xeyes" которые бы следили за мышью и туда направляли градиент. Но всё это слишком запарно делать, и не-интересно. Мне интересны именно какие-то демонстратинвные фишки, типо "вот 3d" вот "уровень". Если я и использую сторонние библиотеки, то только те, которые несложно откомпилировать. Если библиотека легко компилиться как sqlite, то не вижу причин не включить её. Не самому же с этими глифами возиться. Если уж возиться, то я бы попроще что-нибудь сделал, типо битмапов.
Аноним  Чт 26 сен 2024 22:30:08 448526 106
image.png 4Кб, 800x600
800x600
image.png 8Кб, 800x600
800x600
image.png 93Кб, 800x600
800x600
image.png 6Кб, 800x600
800x600
Рисуй треугольник - треугольник сам себя не нарисует!

Сделал отрисовку треугольников. Но не всё так просто. Я же ранее создал свои "рациональные" числа. А поэтому, рассчёты конечно же решил проводить на них. И сразу же повылезали баги, которые я фиксил целый день. Точнее бага всего два, но фиксил я их целый день.
Первый баг я быстро заметил - программа падала с ошибкой "ошибка чисел с плавающей запятой". Очевидно, произошло деление на нуль. Но где? Моя функция деления защищена от деления на нуль. Ошибка оказалась в макросе INT_TO_RAT. Знак у числа почему-то вычислялся делениме его модуля на его самого. Разумеется, если это число 0, то результат будет - делением на нуль. Поэтому я заменил эту фигню "тернарной операцией".
Вторую ошибку я искал долго. Дело в том что треугольник превращался в многоугольники невиданной формы. Я не могу понять почему. Я начал тестить все функции. И все функции работали идеально, погрешность меньше 0,5.
Собственно, раз дело не в функциях, то что ещё остаётся? Ошибка оказалась в макросах. Причём, в ближайшем к предыдущему макросе - RAT_TO_INT, который собственно, переводит число обратно в целое. Дело в том, что в этом макросе не учитывался знак. И от этого собственно вся ошика. Добавив учёт знака, всё стало отлично.

Наконец-то понадобились Callback-функции. Вот, треугольник же нужно будет уметь красить тремя разными способами, зачастую всячески модифицируя: со сглаживанием, с текстурой, со светом. И поэтому, я сделал саму функцию для отрисовки пикселя Callback функцией. Таким образом, можно одну и ту же функцию для построения треугольника использовать с разными отработчиками. Вот три тестовых:
первая закрашивает просто цветом, вторая закрашивает градиентом по y, третья закрашивает рандомным цветом.
Кстати, тут можно сделать и примитивную поддержку альфа-канала. Вот на третьей картнке все цвета с первым байтом 0x00 не закрашиваются.
Аноним  Пт 27 сен 2024 12:56:47 449279 107
image.png 27Кб, 1338x477
1338x477
Короче, с рациональными числами я обосрался. Они работают намного медленее чем флоаты. НАМНОГО. 60 секунд против 9. Не знаю, чего я там намудрил, но похоже что идея гиблая. Хорошо хоть я сохранил старую версию с флоатами.
C оптимизатором вышло 22 секунды. Но это всё равно намного больше чем 9 (ещё неизвестно сколько бы на флоатах с оптимизатором вышло).
Идея гиблая, похоже что. Но можно попробовать оптимизировать.
Аноним  Пт 27 сен 2024 14:49:59 449556 108
Походу операция вызова функции сама по себе берёт столько же тактов процессора сколько и операция над float. Поэтому бессмысленно её оптимизировать.
Аноним  Пт 27 сен 2024 15:06:31 449594 109
image.png 14Кб, 667x462
667x462
image.png 16Кб, 667x462
667x462
Поэтому... Я уничтожил функци! Благодаря тернарной операции, всё это добро можно упаковать в макрос. И оно работает быстрее в разы! Вот только выдаёт неверный результат - опять многоугольникик какие-то. Но подход ясен. Нужно использовать как можно меньше операций/структур. Только битовые сдвиги.
Ещё можно попробовать inline-функции, но я не понял как их использовать, если они в другие модули не экспортируются. Главное, что добиться скорости - возможно!
Аноним  Сб 28 сен 2024 01:02:56 450622 110
image.png 4Кб, 800x600
800x600
image.png 13Кб, 667x462
667x462
image.png 18Кб, 667x462
667x462
image.png 3Кб, 800x600
800x600
Успех! Урезал всё по-максимуму. Теперь результат всего 3 секунды!
Единственный минус - у чисел выше 1000 высокий риск переполнения. А значит экран не может быть больше 1000
Вариант решения - попробовать снизить точность до 4 битов (чем меньше битов на дробную часть, тем больше на целую. Тогда точность падает, зато вместимость целого возрастает). Результат: 3 пик. Надо сказать, что вообще-то прикольный эффект. Типо игры 90-х.
Если первая картинка это разделение [1|21|10] (бит под знак| битов под целое| битов под дробное]
то это было
sqrt(2^(21)) = 1448 допустимое целое исключающее переполнение
и 1/(2^(10)) = 0,0009765625 точность числа
Если мы урезаем по-максимуму: [1|27|4]
то макс число sqrt(2^(27))= 11 585 хватает для самого большого экрана
и 1/(2^(4)) = 0,0625 погрешность большая, но даёт прикольный эффект.
Делать число большим чем 32 бит я пробовал, но это сказывается на быстродействии. Почему-то числа типа long long работают 11 секунд, что в общем-то медленее чем числа с плавающей точкой. Поэтому делать числа больше - нельзя. Но вот, впринципе можно найти что-то оптимальное типо
[1|24|8]
Идеальное соотношение. Особо никакой видимой погрешности не даёт, вместе с этим максимальное целое число становиться 4096, чего достаточно, если правильно сделать защиту выхода за пределы экрана для треугольника.
Аноним  Сб 28 сен 2024 13:21:31 450928 111
image.png 95Кб, 1024x768
1024x768
Начал интересоваться тем, а как бы мне "отсечь" ненужные треугольники и разбить их на несколько других, подобно тому как я делал с линиями. Оказалось, этой теме повсящено не мало алгоритмов, и оказывается, алгоритм по "отсечению" линий придумали до меня. Надо посмотреть, может у них оптимизированее Алгоритм Коэна — Сазерленда. Также полно алгоритмов для отсечения произвольных многоугольников. Но мне нужен конкретно для отсечения треугольника квадратом, и дальнейшего разбиения треугольника на другие части.
Аноним  Сб 28 сен 2024 14:00:28 450984 112
Я дурачок. Я понял, что флоаты то я без оптимизатора компилировал. А если с оптимизатором, то float занимают всего 2.9 секунды! так, что придётся всё переделать во флоаты
Аноним  Сб 28 сен 2024 17:00:07 451264 113
Профайлер ломает программу. Почему-то при компиляции с флагом -pg программа зависает когда делает линии большие чем экран. Иногда вылетает с ошибкой чёто там "mutex", хотя очевидно я никаких мьютексов не использовал, следовательно это ошибка связанная не со мной. Жаль, я хотел протестить, что быстрее, мой старый алгоритм клиппинга или новый. Хотя у меня есть идея, поставить координаты экранна намеренно меньше чем они есть, чтобы сымитировать подрезку.
Аноним  Сб 28 сен 2024 18:04:17 451299 114
Да. Так и сделал. И результат: одинаково. Что мой клиппер, что клиппер Cohen–Sutherland работают одинаково быстро. Оставлю пожалуй второй. Потому что мой клиппер занимает две страницы, и работает только с линиями до 45 градусов, а этот работает с любыми линиями, и довольно компактный и логичный в плане читаемости кода.
Аноним  Сб 28 сен 2024 23:32:26 451881 115
image.png 28Кб, 1429x997
1429x997
List outputList = subjectPolygon;

for (Edge clipEdge in clipPolygon) do
List inputList = outputList;
outputList.clear();

for (int i = 0; i < inputList.count; i += 1) do
Point current_point = inputList[i];
Point prev_point = inputList[(i − 1) % inputList.count];

Point Intersecting_point = ComputeIntersection(prev_point, current_point, clipEdge)

if (current_point inside clipEdge) then
if (prev_point not inside clipEdge) then
outputList.add(Intersecting_point);
end if
outputList.add(current_point);

else if (prev_point inside clipEdge) then
outputList.add(Intersecting_point);
end if

done
done
Аноним  Сб 28 сен 2024 23:51:57 451913 116
image.png 15Кб, 1436x598
1436x598
короче, устал думать как реализовать этот алгоритм хитрым способом. Поэтому сделаю "в лоб" как на википедии написано. Сделаю мини-структуру для хранения точек, и буду тупо туда записывать все отрезанные точки
Аноним  Сб 28 сен 2024 23:53:42 451915 117
алгоритм простой, просто вот думаешь, как бы не писать эти cur_x на тысячу строк. Ещё и чтобы удобно всё это хранить.
Аноним  Вс 29 сен 2024 00:05:44 451926 118
а.. постой, список то требует динамической памяти. Это наверное медленее будет, если он будет malloc по каждому пуку вызывать.
Надо макросы тогда попробовать, для большей читаемости
Аноним  Вс 29 сен 2024 02:23:03 452188 119
image.png 4Кб, 800x600
800x600
image.png 20Кб, 667x462
667x462
Наконец-то, получилось. 5 часов утра. Всю ноч этот алгоритм по отсечению шаманил
Аноним  Вс 29 сен 2024 12:51:13 452541 120
image.png 7Кб, 625x597
625x597
Аноним  Вс 29 сен 2024 13:04:29 452563 121
А вот с окружностями уже не всё так просто. Как вообще теоретически "обрезать" окружность? Если окружность обрезана, то это уже не окружность и под алгоритм рисования окружности она не попадает
Аноним  Вс 29 сен 2024 13:29:48 452595 122
2024-09-29 15-23-49.mp4 4631Кб, 1920x1080, 00:00:15
1920x1080
стресс тест!
Аноним  Вс 29 сен 2024 14:50:28 452745 123
image.png 839Кб, 638x670
638x670
вроде ошибок нет.
Круги хз зачем нужны. Это ведь даже не элипс, не кривая. Что можно сделать одним лишь кругом? Может только эффекты какие-нибудь. Да и учитывая, что круг нельзя подрезать - применение кругов становиться ещё более узким.
Вот кривые и элипсы - это да. В детстве я мечтал создать свою "криволинейную" графику. Я тогда программировать не умел. Но тогда уже начали появляться игры с NextGen реалистичной графикой, типо beyond two shouls. И там мне показалось, что на персонажах слишком много полигонов (на самом деле это не так. Я проверял. Там всё максимально ужато, и сделано по-уму с картами глубины, с нормалями. Но мне как полному нубу казалось что чем больше деталей - тем больше полигонов). Мне также почему-то показалось, что "много полигонов" это плохая идея, и нужно развиваться в других направлениях типо воксельной графики, или криволинейной графики. Я вот видел кривые Бизье и я думал: а почему нельзя такие же трёхмерные сделать? Сейчас, я уже понимаю, что вообще-то полигоны - это самое разумное и оптимальное решение, лучше которого, пока что теоретически ничего не существет.
Воксели - ещё туда-сюда идея. И как ни странно, они имет своё применение - те же карты parallax глубины, это по-сути и есть воксели. Спрайты и трёхмерные эффекты - тоже воксели. Хоть сама по себе отрисовка вокселя - это вещь менее затратная, чем функции по отрисовке полигонов (воксель ведь достаточно всего лишь спроецировать), но вот описать сложную геометрию уже будет затратнее, это ведь получается придётся каждую точку проецировать, в то время как у полигона нужно спроецировать всего 3 точки, а остальное уже дело двухмерного отрисовщика треугольников.
На счёт кривых NURMS, они точно не будут быстрее полигонов, просто потому что в каком-то смысле NURMS это такие же полигоны, только с точками изменяющимися нелинейно. То есть, если ранее достаточно было выполнить простой алгоритм брезенхема для отрисовки, то теперь вместо него работает вычисление некоторого более сложного закона. Вопрос: что быстрее "рендерить NURMS" или рендерить полигоны, это практически тот же вопрос, "что сложнее нарисовать 100 линий или 10 парабол". Кажется что 10 парабол то быстрее наверное! что вообще-то чистая правда. Вот только с увеличением сложности геометрии, эти 10 парабол превратятся в 200 парабол, при том, что приблизительно геометрию объекта можно изобразить всего 50 линиями. Вот 200 парабол против 50 линий, это уже значительно медленее.
Это я так, рассуждения в сферическом вакууме.
Резюмиру, разница между кривыми и полигонами, примерно такая же как между растром и вектором: растровые картинки хранить выгодно пока они маленького разрешения, а картинки высокого разршения выгодно хранить в векторе, ведь 4 точки и 4 параболы это быстрее чем матрица из миллиона точек. Вот только когда картинка не представляет собой треугольник на синем фоне, векторная картинка усложняется и в неё добавляется тысячи других механник. Что заставляет задуматься, а не проще ли обойтись растром?
Хотя, это опять же демонстрирует, что некоторые элементы NURMS могли бы быть полезны в графике. А именно я намекаю на простые гладкие формы. Сделать сферу или ткань проще как раз кривыми безье, и это будет намного эффективнее, с точки зрения рендера (для физики вроде как безразлично, 4 параболы у тебя или 4 линии, так что на других расчётах это не скажется). Но что касается более сложных объектов типо тела человека, то выигрышнее всё же использовать полигоны.
Аноним  Вс 29 сен 2024 15:01:52 452783 124
image.png 161Кб, 386x259
386x259
image.png 184Кб, 600x450
600x450
А. Что-то меня пробило на флешбек. Вспомнил какая у меня идея была в детстве.
Криволинейная графика + воксели.
Я вот только что сказал, что при помощи "криволинейных" пресетов можно намного быстрее отрисовать условно "сферу". Ведь что такое сфера - это всего лишь круг с шейдерами. Проекция сферы всегда будет кругом.
Но вот только сразу возникает вполне резонный вопрос "на какой чьёрт мне ваш круг? куда мне его заcунуть куда применить? я хочу модельки красивых дренеек в трусиках, а не чёртов кружочек.". И вправду. Когда мы начинаем делать что-то сложнее круга из составных частей (например при помощи кривых безье), то тут же алгоритм отрисовки усложняется в разы, и становится намного медленее чем тот же результат на полигонах.
Вот только, возникает другая идея: а что если найти применение примитивам"? Сфера, ну кружочек какой-то, только солнце нарисовать им можно, а ничего прочего абсолютно круглого в мире нет. А если добавить на неё воксельную карту глубин, и превратить сферу в голову? достаточно ведь вокселями часть формы искривить. вот это уже интереснее подход. Но всё это так... пища для размышления. Полигоны показали свою эффективность уже много лет, и копротивляться против классического подхода смысла особо не имеет.
Аноним  Вс 29 сен 2024 15:08:37 452807 125
К тому же есть способы рендеринга вообще без расчёта геометрии! Это так называемый "рей трейсинг". Это подход, при котором мы из камеры выпускаем "линии" (лучи), (точно также как мы делали с Z-буффером), а каждый объект у нас начинает иметь свойство "отражать" линии, то есть выпускать обратный луч, но под некоторым углом и интенсивности, цвета. И мы, просто камерой, практически как глазом, ловим эти лучи и рисуем на их месте соостветсующий цвет.
Насколько я знаю, это очень медленный тип рендерига, его используют не для игр, а чтобы красивые картинки заранее рендерить.
Аноним  Вс 29 сен 2024 17:25:13 453049 126
image.png 24Кб, 800x600
800x600
проволочный рендер сделан. Значит парсел wavefront импортирует всё верно.
Аноним  Вт 01 окт 2024 17:10:04 456422 127
image.png 13Кб, 800x600
800x600
гроб кладбище могилы страшна страшна

p.s. как же я задолбоался с этой перспективной проекцией. Ничего не рабоает, когда работать должно. Ещё и непонятно, насколько мой метод эффективен.
Аноним  Вт 01 окт 2024 18:54:37 456688 128
2024-10-01 20-28-36.mp4 6306Кб, 1920x1080, 00:00:20
1920x1080
Короче, если не выёбываться, и не строить из себя самого умного, и просто взять и списать решение с интернета, то там вообще всё по-другому. Все эти функции по нахождению пересечения линии и плоскости - в помойку.
Там идут более хитрым способом. Вместо того, чтобы пытаться спозициронировать плоскость в пространстве, камера вообще никаких плоскостей не содержит. Камера по-сути содержит только свою систему координат. И координаты любого объекта, пересчитываются в систему координат камеры, и затем, проецируются прощённой, ранее известной формулой
x' = xfov/z
y' = y
fov/z
В каком-то смысле это и есть проекция линии на плоскость. Вот только плоскость и линии специально подобраны так, чтобы умещаться в этот частный случай. Вывод формул я не понял. К тому же что в интернете часто матрицами пользуются. Страшны не сами матрицы, вроде как программу второго курса вспомнить могу.. проблема в четырёхмерных матрицах. Везде используют "кватернионы" и четырёхмерные пространства для удобства. Вроде как оно иногда бывает понятно, что вот в этом четвётром измерении мы можем хранить что-то дополнительно, но это вообще-то как-то неинуитивно и непонятно, типо вот что это за четвёртая фигня. Но, на самом деле так то пофиг. Математика интересная вещь, но лень, хочется чего-нибудь забабахать забавного и смешного! Надо делать тупое пока не надоест
Аноним  Вт 01 окт 2024 19:16:43 456785 129
единственное чо пригодилось из той фигни что накодил, это операции над векторами.
Аноним  Ср 02 окт 2024 01:11:05 457721 130
image.png 35Кб, 800x600
800x600
Протестил программу с флагом -DRATIONAL, который включает мои числа с фиксированной точкой (я типо чтобы не заморачиваться сделал две обёртки - первая просто макросы повторяющие обычные операции над флоатами, вторая - числа с фиксированной точкой).
И всё... программа снова не работает. Оказалось, я ошибся в операциях как раз в тот момент когда переводил их в макросы. У меня неправильно были сделаны вычитания и сложения. 0 - 1 выдавало 1, а не -1.
Я уж было подумал бросить это бесполезное дело. Но что-то мне стало лень, подумал, может всё-таки пофиксить эти числа.
В общем-то, частично всё пофиксил. И оно работает. Вот только когда запускаю анимацию - программа не выводится. Зависает на функции RenderWireframe. Надо чинить
Аноним  Ср 02 окт 2024 19:10:31 459078 131
2024-10-02 21-05-56.mp4 4120Кб, 1920x1080, 00:00:13
1920x1080
Вот это тряска. Причём считается намного дольше чем флоаты. И зачем нужны эти "числа с фиксированной точкой". В википедии столько пиздежа про их эффективность, а на деле одни тормоза неточности и лаги.
Аноним  Ср 02 окт 2024 20:30:55 459126 132
image.png 29Кб, 1342x485
1342x485
Короче впизду. Нахуй это говно.
1. Оно работает в 2 раза медленее
2. Оно постоянно переполняется при малейшем пуке. 32 битов просто не хватает. а 64 бита считаются в два раза дольше.
3. Оно даёт ебейщую погрешность и тряску.
4. Чем больше оптимизируешь, тем менее защищёнными становятся операции над числами.
5.Записи функций становятся навыносимыми. Место x*y - z приходится писать rat_sub(rat_mul(x,y),z) или вовсе расписывать функции построчно, будто бы пишу на особо стрёмном виде ассемблера. Короче впизду.
0/10.
100% говно.
0% профит.
Кал калыч, кал говна.
Перепишу всё на флоаты. На них всё нормально работает.
Пусть если кому-то нужно, у кого FPU нет, тот сам на уровне компилятора С свои флоаты и реализует.
Аноним  Ср 02 окт 2024 22:34:15 459269 133
Я это к тому, что если программа тупит по причине "чисел с плавающей точкой", то проблема явно не в числах с плавающей точкой, а в безграмотном их применении, потому что лично на моём FPU такие числа считаются довольно быстро. Целые числа считаются примерно в два раза больше, вот только для того, чтобы реализовать "минималистичный" набор функций, необходимо как минимум две операции (умножение и битовый сдвиг и деление и битовый сдвиг). То есть такие числа уже такие по скорости примерно одинаковы с флоатами. А если их сделать ещё и "по уму" чтобы не было деления на нуль, чтобы они не переполнялись, чтобы могли поддерживать как отрицательные так и положительные значения, то скорость таких конструкций оставляет желать лучшего. 7 сек против 4.
Аноним  Ср 02 окт 2024 23:38:01 459383 134
image.png 39Кб, 800x600
800x600
Вообще, в некоторых местах можно включать числа с фиксированной точкой. Например, там где точно известно, что все числа положительные.
Аноним  Чт 03 окт 2024 00:05:11 459442 135
image.png 16Кб, 667x462
667x462
image.png 16Кб, 667x598
667x598
image.png 63Кб, 800x600
800x600
Идея создать структуру "шэйдер", в которой хранилось бы три компонента:
typedef struct shader_t{
void ⚹data;
int(⚹Constructor)( void ⚹userdata);
void(⚹Plotter)(window ⚹w,int x,int y, int color, void ⚹userdata);
int(⚹Destructor)( void ⚹userdata);
} shader;
Эдакое ООП на чистом С (хотя ес честно я незнаю правильно ли это так называть). Суть в чём. Функция RenderShaded берёт в качестве аргумента шэйдер (кроме всего прочего берёт также "сцену", в данном случае это всего лишь объект, так как никакой "сцены" я ещё не придумал, и также берёт "окно" для отрисовки). Этот шэйдер имеет конструктор, плоттер, деструктор и пользовательские данные.
Что такое "пользовательские данные"? Это всё, что необходимо дать программе, для отрисовки треугольника. Это могут быть текстуры, или ещё что-то что как-то может задействоваться в функции plot. Например, там может быть z-буффер, текстуры итд итп. Функция Constructor вызывается чтобы инициализировать данные перед отрисовкой, например, эта функция может заполнять z-буффер для текущего расположения камеры. Деструктор, собственно, этот z-буффер очищает. Плоттер, ставит точку с учётом этого Z-буфера, и с учётом текстуры
Тогда можно функцию оставить такой же миниатюрной какая она есть, и добиться гибкости, чтобы можно было создавать разные "шейдеры"
Аноним  Чт 03 окт 2024 00:16:59 459485 136
image.png 61Кб, 800x600
800x600
Аноним  Чт 03 окт 2024 12:16:31 459807 137
image.png 18Кб, 659x788
659x788
image.png 18Кб, 656x791
656x791
Что-то ночью я задумался: а не дурак ли я? И походу эта.. дурак.
Все ведь эти проблемы со сложением и вычитанием чисел с фиксированной точкой вызваны тем, что у меня тип unsigned int . Приходится самому програмно реализовывать "отрицательные" значения, а значит и операции с учётом этих отрицательных значений. А почему я не сделал просто int ? Unsigned int кажется логичным, поскольку мы же делим 32 бита на части, что не входил в концепцию "знакового числа" которое на половине переполняется.
Но вот сейчас до меня дошло. А зачем я вообще этим байтоёбством занят? Мне, благородным языком С уже дана абстракция целых чисел, (как отрицательных так и положительных). Битовый сдвиг - эквивалентен домножению на 2^(n) для любого целого числа. Так тогда пусть они и сдвигаются с учётом знака, мне то какая разница как там биты заполняются, если результат будет интерпритирован верно.

Я уже перепелил всё под флоаты. Но может если сейчас реализовать fixed-point то может можно внедрить их куда-нибудь.
Аноним  Чт 03 окт 2024 12:37:54 459830 138
Y2meta.app-Бамб[...].mp4 9150Кб, 854x480, 00:03:39
854x480
А можно ведь сделать более гибко: каждую функцию с флоатами, дополнительно переписать под fixedы, и вторую часть отделить макросом условной компиляции #ifdef FIXEDPOINT #endif, и компилировать "выборочно". Некоторые функции например, может лучше оставить float, а некоторые fixed
Аноним  Чт 03 окт 2024 12:42:47 459837 139
И ведь идеально работает. Пока что никаки ошибок
typedef int fixed;
#define N 8
#define mul(a,b) ( ((a)*(b)) >> N )
#define div(a,b) (((a) << N)/(b))
#define FIXED_TO_FLOAT(f) ( (float)(f) * pow(2,(-N)) )
#define FLOAT_TO_FIXED(f) ( (fixed)((f) * pow(2,(N))) )
Почему я раньше так не сделал?!
Аноним  Чт 03 окт 2024 17:02:35 460189 140
image.png 51Кб, 800x600
800x600
Ну... Переполнения всё равно ломают весь рендерер. Тогда я сделал чисто растеризатор на фикседпоинтах, но это всё равно никакого выигрыша не дало. Примерно одинаково:
5.56 seconds на Floats
5.61 seconds на Fixed
Что я и говорил. Современные железки хорошо сделаны, их так просто не обманешь. Но, во всяком случае, минусом это явно не будет, поэтому оставлю фиксед-поинты в тех местах, где диапазон значений заранее известен. Например, в функции Rasterize которая закрашивает треугольник, все точки заранее подрезаны под экран. Так, что там не может быть впринципе чисел больше чем 4096 (по крайней мере я не видел таких экранов).
При вычислении интенсивности света, тоже очевиден диапазон от 0 до 1, можно применить фикседпоинты, разницы особо не будет. Зато может на некоторых старых некропк они дадут прирост производительности.
Аноним  Чт 03 окт 2024 22:58:18 460666 141
image.png 9Кб, 667x462
667x462
image.png 144Кб, 1016x530
1016x530
Вот так примерно буду упаковывать userdata. Тупо все указатели в массив, затем передаём в юзердата и интерпритируем.

Переписал модуль IO под винду. И всё работает. Единственное, на винде функции SetPixel и CloseWindow заняты стандартным апи. Поэтому я переименовал все функции префиксом io_, чтоб точно ни с чем не было конфликтов в будущем.
Аноним  Пт 04 окт 2024 15:17:37 461466 142
image.png 19Кб, 800x600
800x600
Это Z буфер это победа
Кстати, вот ещё одно применение чисел с фиксированной точкой: буфер глубины. Он как раз требует чёткий диапазон значений, от максимального до нуля.
Аноним  Пт 04 окт 2024 15:59:37 461572 143
image.png 25Кб, 800x600
800x600
image.png 48Кб, 800x600
800x600
По-приколу сделал функцию которая отдельно Z-буфер рисует. Прикольна!
Аноним  Пт 04 окт 2024 16:13:36 461603 144
image.png 14Кб, 667x462
667x462
Со структурами типа "шейдер" не стал заморачиваться. Тем более что обычно такой подход в С заранее карается какой-то бессмыслицой. Если уж классы делать то на С++, а на С практически всегда лучше оставить всё как есть, и пользоваться тем что дано. Поэтому, я тупо сделал отдельное поле в камере fixed ⚹⚹zbuffer, которое инициализируется при создании камеры, и заполняется функцияей FillZBuffer, которая представляет собой по-сути тот же рендерер, только в качестве отработчика Plot, тут выступает функция DepthFilter, которая вообще не вызывает io_SetPixel, ни в каком виде, а просто заполняет буфер по указанным x и y.
Рендерится этот буфер в один подход, просто перебором всех точек.
Очищается также, просто двумя циклами перебираются все точки и обнуляются.
При отрисовке затенённого объекта с учётом Z-буфера, работает другой отработчик, который называется DepthPlot, он уже берёт из Z-буфера точку, сравнивает её с отрисовываемой, и в случае если точка имеет аналог ближе, то не рисует.
Удобно, что функции "отделены", так что каждая помещается в 80 строк. Нет путаницы. Однако есть и минус: если пользователь не знает ничего про Zбуфер, то программа просто ничего не отрисует, если не найдёт заполненного Zбуфера. Простое решение - поставить флажки, о необходимости z-буфера. Но мне почему-то кажется, что есть решение по-лучше, поэтому пока что оставлю так.
Аноним  Пт 04 окт 2024 18:49:13 461832 145
image.png 14Кб, 667x462
667x462
image.png 14Кб, 667x462
667x462
Короче, я хотел сделать так, чтобы типо буффер заполнялся тогда же когда и рендерится. Но я не понял как это сделать.
И чисто теоретически: чтобы понять, лежит точка ближе или дальше от нас, нам нужно вначале знать, а нет ли на другом каком-то полигоне другой такой же точки. Чтобы это узнать, нам для начала нужно просканировать всю модель, а потом уже принимать решение. Полигоны ведь порядка не имеют, поэтому, по-сути невозможно найти "противоположный полигон" не перебрав все полигоны.
Поэтому, я пришёл к выводу, что это какая-то глупая и нереалистичная идея. Поэтому, я просто добавил флаг buffer_refil_required. Если он истина - буфер нужно заново заполнить. Если ложь, то рендеринг происходит с тем буфером, что есть.
Буфер надо заполнять, если камера сдвинулась. Мы же не можем предсказать, камера будет ближе или дальше, поэтому если буфер заново не занулять, то он может просто отражать неверную картину.
Поэтому, все эти манипуляции с zбуфером, я сделал статиками. Теперь это внутренние функции модуля. При инициализации камеры, ставится флаг о том, что необходимо заполнить Zбуфер. Если камера повернулась - буфер обнуляется, и ставится флаг о том, что нужно заполнить Zбуфер. Сам буфер заполняется в функции рендеринга. Если у камеры есть флаг, что необходимо обновить z-буфер, то функция рендеринга вначале заполняет буфер, а потом уже рисует объект. Если такого флага нет (например, камера не поворачивалась), то функция рисует по старому буферу.
Аноним  Пт 04 окт 2024 18:51:00 461835 146
Для рендеринга декораций, травы например, можно просто сделать отдельную функцию, которая рендерит без учёта буфера.
Аноним  Пт 04 окт 2024 19:27:53 461877 147
чё дальше?
-Текстурки
-Сглаживание гуро
-(опционально) клиппинг трёхмерного пространства (можно сделать и позже, пока что непонятно, может и так норм)
Аноним  Сб 05 окт 2024 00:13:01 462494 148
image.png 54Кб, 800x600
800x600
image.png 62Кб, 800x600
800x600
image.png 88Кб, 707x530
707x530
Ура! запилил текстурки, при помощи самописного модуля tgatool.
Вообще, tgatool это моя первая программа, (хотя это не программа это интерфейс для импорта, экспорта и рисования на tga картинках. Формат tga я выбрал только из-за простоты).
И вот, это поделие мне пригодилось.
Аноним  Сб 05 окт 2024 00:28:09 462547 149
image.png 55Кб, 800x600
800x600
image.png 49Кб, 800x600
800x600
Пофиксил свет. Там оказывается из-за signed char'a переполнение всё это время происходило, а я даже и не понимал в чём проблема.
Аноним  Сб 05 окт 2024 00:30:33 462550 150
image.png 133Кб, 1575x590
1575x590
завтра будем реализовывать тонирование гуро
Аноним  Сб 05 окт 2024 00:33:33 462559 151
image.png 54Кб, 800x600
800x600
на фикседпоинтах тоже всё стабильно работает.
Аноним  Сб 05 окт 2024 14:57:49 463283 152
2024-10-05 16-54-02.mp4 3983Кб, 1920x1080, 00:00:13
1920x1080
Встречайте! Ультрагладкий софтверный гурозатенённый йоба бсд!
Аноним  Сб 05 окт 2024 21:15:54 463987 153
image.png 51Кб, 800x600
800x600
Дополнил модуль Wavefront.c функцией CalculateNormals.
Теперь, даже если в модели нет нормалей, функция вначале вычисляет все нормали, и потом уже выполняет затенение.
Аноним  Сб 05 окт 2024 22:46:13 464160 154
2024-10-06 00-39-49.mp4 4555Кб, 1920x1080, 00:00:15
1920x1080
Ну и под конец, сделал функции для увеличения, перемещения и поворота объекта.

На этом рендеринг можно завершить.
Надо переходить к чему-то следующему.
Аноним  Пн 07 окт 2024 00:52:04 466080 155
VID_20241007_00[...].mp4 4376Кб, 1280x720, 00:00:08
1280x720
tq2r2am.jpeg 522Кб, 1080x2400
1080x2400
Итак, графический модуль готов на 99%.
За сегодня я сделал функции ImportObjEmbed и ImportTgaEmbed, для импорта файлов изнутри самого файла .с представленного в виде массива. То есть, теперь есть возможность "вшить" некоторые объекты прямо в игру. Чем это может быть полезно? Ну как минимум сделать базовый графический интерфейс какой-то, если необходимо. Чтобы игра не ломалась если меню удалить.
На винде эта функция работает костыльно. Оказывается на винде нет fopenmem ни в каком виде (там ядро ос просто не позволяет себе таких вещей). Поэтому я сделал функцию которая просто все массивы записывает во временный файл, затем открывает этот временный файл и отдаёт дескриптор. Работает. Перевёл ещё несколько функций на fixed-point.
Что дальше?
"отполировать" модуль можно ещё тремя новшествавами:
- клиппинг трехмерного пространства. Аналогично модулю basics, надо бы найти простейшие алгоритмы которые отрезают модели по границам камеры. Это наверное самое важное новшество, потому что модели которые находятся вне диапазона видимости камеры все равно тратят обороты расчёта рендерера, и тем самым добавляют много лишней работы.
- Полный перевод на числа с фиксированной точкой. Я так посмотрел: да нормально они работают. Возможно в прошлый раз я просто что-то не так сделал. Нужно выкинуть вторую версию на fixedах. Авось и полезно будет.
- Поддержка альфа-канала. Неплохо было бы создать некоторый "прозрачный рендер". Зачем?! Как минимум, сделать имитацию падающих теней. Сами тени я рассчитывать не хочу, как и динамический свет делать в мои планы не входит. А сделать прозрачную тёмную лужицу-текстуру под объектом - вот это было бы прикольно. Также, раз уж есть альфа-канал, то можно и стекло делать, в стиле cs 1.6.

Далее нужно уже задумываться и об игре.
Иерархия кода следующая. Вся игра состоит из трех глобальных объектов: окно, ввод, и сессия. Окно - это реефикат таких понятий как "экран, дисплей, окно конкретного фреймворка, звук, видеобуфер, итд". Одним словом, окно это единственный универсальный ввод-вывод. На окне мы можем рисовать, у окна мы можем запрашивать обновление событий, окно мы можем попросить обновить картинку.
Далее, ввод - это информация о том, что ввёл пользователь, какую клавишу нажал. То есть ввод - это просто структура в которой есть вся информация о клавишах, о мыши итд.
Далее, сессия - это "данные о текущем состоянии игры". Тут хранится указатель на уровень, state игры, (на паузе она или нет). Сессия нужна для управления всей игрой вцелом. Операции над сессией это: подгрузка уровней, изменение режима ввода, итд (в общем, все что лежит вне игрового процесса).

main() {
w = InitWindow();
c = InitControls();
s = InitSession();
while(s.state! = exit){
switch(s.state) {
case menu:
MainMenu(&s.events) ;
break;
case loading:
LoadLevel(&s)
break;
case playing:
GameLoop(&s.events) ;
break;
case paused:
PauseLoop(&s.event);
break;
case error:
HandleError(&s.events)
break;
case exit:
}
}

Это не конечный автомат. Логика конечного автомата тут нарушается, из-за того что каждый отработчик блокирует выполнение главного цикла.
Это по-сути цикл управления игрой. Каждый отработчик сообщает некоторый результат своей работы, в зависимости от которого игра переходит в следующий режим.
Например, отработчик MainMenu проигрывает по-сути программу для подгрузки уровней.
Отработчик LoadLevel смотрит на "очередь уровней" и подгружает тот, что необходим.
Отработчик GameLoop выполняет неблокирующий PollControl (запрос на обновоение ввола), затем обновляет шаг игровой логики, затем вычисляет физику на основании времени пройденного с предыдущего игрового цикла, затем вычисляет перемещения анимированных обьектов, затем рендерит все видимые объекты. Представить можно так
GameLoop() {
scene = InitScene(level)
while(response == none) {
PollControl(&c);
UpdateTime(&t)
UpdateGameLogic(c, &scene, t);
UpdatePhysics(&scene, t);
UpdateAnimation(&scene, t);
RenderScene(w, scene);
UpdateFrame(w) ;
}
}
Как тут можно заметить, некоторой общей "сесией" для всех компонент игры является "сцена". Сцена - это набор "сущность". Под "сущностью" подразумевается вообще любой игровой объект, будь то это просто декорация или невидимый хитбокс. Сущности имеют свойства, которые автоматически прикрепояют их к конкретному отработчику.
Например, физика: объекты могут быть проницаемыми, т. е. через них можно будет пройти. А могут быть и твердыми, что означает что через них невозможно пройти. И для тех и для других нужно рассчитывать столкновения. В случае с проницаемыми столкновениями, их нужно только высчитать, и отдать игровой логике еа отработку. В случае с колизиями, для них нужно принять чёткое решение о изменении физических параметров (например, вес объекта вызывает противоположную силу реакции опоры, или силу натяжения нити. То есть нужно рассчитать вектор этой силы, и на основании сил принимать решение об ускорении точек). А есть объекты - декорации, для которых и вовсе расчёт даже столкновений заранее не нужен.
Также и с анимацией: есть статические объекты, для которых изменения за кадр считать не нужно, а есть анимированные, которые в теории могут потребовать воспроизведения анимации.
Также и рендер: есть объекты которые следует ренлерить плоским шейдером, есть те к которым необходимо применять сглаживание гуро, а есть и вовсе невидимые объекты, которые рендерить и не нужно. Затем идёт отработка кадра, и повторяется все заново.
Игровая логика, в данном случае, стоит "над" всеми этими системами, потому что все системы обращаются именно к ней, а она к ним. Что может делать игровая логика? Игровая логика может подавать управляющие сигналы системам: мол "я нажал кнопку, прибавь-ка силы по оси x, (или просто энергии) к точке моего персонажа, на что физическая система в дальнейшем среагирует так " точка действует силой F на стену, следовательно стена действует на точку с силой N, а значит они вычииаются и ускорение равно нулю". Игровая логика как бы формирует воздействие на системы. Например, игровая логика считывает из сессии что произошло столкновение (этот расчёт сделала физическая система например), и после этого она решила активировать анимацию, поставив соответствующий флаг для этого, и указатель на следующий кадр. Тогда система анимации начнёт анимировать этот обьект.

Вот примерно такой концепт накидал для устройства игры. В будущем надо будет его подровнять, сделать более внятным. Но пока вот так.
Аноним  Пн 07 окт 2024 18:02:47 466877 156
image.png 87Кб, 800x600
800x600
image.png 61Кб, 800x600
800x600
Короче, не понял как реализовать клиппинг трёхмерного пространства. В гугле только двухмерное выдаёт.
Чатжпт говорит что у меня он уже реализован, при помощи far и cam_z < 0 у камеры (типо, чтобы не отрисовывать объекты которые из-за дальности превратились в точку и объекты которые позади камеры или паралельны камере ), а боковые подрезки это типо двухмерные клиппинг-механизмы реализует. Хз может врёт. Чатгпт может и фигню говорить.

Придумал как реализовать альфа-канал. В этом же наверное нет ничего сложного. Это нужно взять цвет из видеобуфера, и правильно его смешать с заданным цветом. Тогда можно и альфа-текстуры делать. Собсна, вот! прозрачный розовый BSD шар. Теперь при помощи этого можно делать тени, стекло и воду.

Чё там ещё? Хотел было перевести рендер на fixed-point, но потом понял, что это снова придётся таблицу корней делать. А таблицу корней нельзя никак ограничить, поэтому придётся делать большую таблицу корней. Большая таблица корней никуда не поместится, поэтому придётся делать интерполяцию... ну впизду короче, пусть на флоатах будет. Если таблицу косинусов ещё можно сделать, то таблица корней - всё, картоп.
Аноним  Пн 07 окт 2024 23:55:36 467525 157
image.png 23Кб, 512x280
512x280
Самое моё нелюбимое в паттернах, это что всегда когда ищешь паттерн, единственное что находится, это туполылый умник который такой: "ээээ ну эта короче вот компонент вот система... эээээ всё понятно?" и нихрена не понятно. 0 полезной информации. 0 сути. Только общие красивые слова типо "вот смотрите это "систееема"". Нужно не общие слова, нужна суть. Нужно придать свойства такому понятию как "система". Нужно придать свойства такому понятию как "компонент".

Так. Попытаюсь понять паттерн ECS при помощи размышлений.
Энтити - это "сущность". Пустышка другими словами. Какие свойства есть у "энтити"?
1.Идентификатор. Все энтити имеют свой id.
2.Компоненты.
Одним словом:

typedef enum set{ mesh, camera, vector, collision, player_state, intency, total } set;

typedef struct entity_t{
int id;
void *component[total];
} entity;

То есть энтити - это какое-то количество разных данных (свойств), с одним id.

Что же такое "компонент"? Это данные какого-нибудь типа. Например wavefront_obj, или vector, или ещё какие-нибудь. Причём, чем более "несвязные" типы данных, тем лучше. То есть "тёплое, мягкое, квадратное и координаты" - это хороший пример компонент. Важно подобрать компоненты так, чтобы каждый компонент был независим. То есть, нельзя объединять компонент "точка" и "3dмодель" в один. Почему? Потому что точка может быть без 3dмодели. А модель, в общем-то можно отрисовать и без точки (например, если он всегда стоит в нулевой координате, то есть земля например какая-нибудь). Совсем неинтуитивно, но также дела обстоят и с текстурой. Чево?! Да. Текстуру имеет смысл представить отдельным свойством. Казалось бы: "а зачем? у нас ведь кроме объекта нет ничего чтобы могло брать на себя текстуру? текстура ведь отдельно от объекта не существует". Но легко представить ситуацию, когда текстура нужна как отдельное свойство. Это, например погоревшее делево. Моделька дерева типо "сгорела", и у неё должна измениться текстура на обуглевшую. И вот на этом моменте становится понятно, что текстура тоже является независимым свойством. (это конечно в том случае, если в игре имеет место изменение текстур).
Из всего этого можно представить следующий список компонент:
1.Wavefront модели
2.TGA картинки
3.Векторы (по-просту, можно сказать "точки") (этот компонент помогает явно асбтрагироваться от визуала, и понять, что в общем-то компонентом может быть даже простой int, никак не связанный ни с визуалом ни вообще с игровым процессом. Главное что это какие-то данные, т.е. свойство чего-то).
4.Анимации (свой формат)
5.Кнопки, панельки, формы ввода, клетки. Одним словом, то что описывается структурой GUI (к слову, гуй можено и не включать в компоненты. Но если игра предполагает "игровой гуй" то есть, допустим диалоги с персонажем" то лучше всё-же включить это в ECS.
6.Сессия искуственного интелекта (ну, то есть если энтити - это какой-то NPC, то у него как у конечного автомата должна быть своя "сессия").
7.Видимость для рендера.
8.Состояние персонажа (здоровье, сила, ловкость).

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

Далее, "системы". Системы, это отработчки "энтити". Каждая система, отрабатывает "энтити" в зависимости от данных которые в ней вложены. Например, если в энтити есть данные "3д модель" и "объект видим для рендера" то RenderSystem отработает такой энтити. Логика построения систем также лежит на авторе, но как уже понятно, имеет смысл делать системы так, чтобы все данные играли какую-то роль. Тот же пример с текстурой: если в игре все текстуры статичны, и отрабатываются, разве что модулем для анимации, то выделять тестуру в отдельную сущность никакого смысла не имеет, ведь она ни одним отработчиком не будет задействована.
Какие у нас могут быть системы.
1.RenderSystem - рендерит всё что можно отрендерить.
2.AnimationSystem - мониторит анимации, и выполняет итерацию для активных.
3.GUI - система кнопок, инвентарей, диалогов, изменяет состояние кнопок в зависимости от ввода.
4.Physics - механника точек. обнаружение столкновений.
5.AI - отдельно ведь нужно искуственный интеллект просчитывать! совсем забыл уже.
6.GameLogic - основная игровая система.
7.Аудиосистема.
Система ввода лежит за пределами ECS так я понял, просто потому что у неё нет компонент. Кстати о компонентах. Компоненты - это некоторые типы данных используемые в игре.

Наверное, этот паттерн нужен уже тогда, когда все системы готовы. Пока даже и неизвестно, сколько всего типов данных получиться. Поэтому, далее нужно делать модуль анимации, а затем модуль физики.
Аноним  Вт 08 окт 2024 11:58:30 468258 158
image.png 550Кб, 736x736
736x736
image.png 608Кб, 564x564
564x564
image.png 335Кб, 564x358
564x358
Поспал. Мне приснился кошмар, что в моём доме живут десять скуфов и таджиков, и я не могу их выгнать, потому что выгонять их теперь незаконно.

Зато немного переварил вчерашнюю информацию. Я понял некоторые поправки относительно ECS.
Во-первых:
Компоненты не то чтобы должны быть "несвязными", компоненты скорее должна быть наиболее широкими и представлять некоторую характеристтику. "несвязанность и абстракция" я бы сказал. Компонент не должен подразумевать, что его как-то конкретно применяют. То есть, компонент должен передавать чистое свойство, без какого-то применения. В таком случае, компонент "текстура" это всё-таки плохой пример, ведь текстуры всё же бывают только на обхектах. Хорошим набором компанент было бы:

enum set{ mesh, image, camera, animation }

Потому что теперь, image можно использовать как свойство текстур ддля трёхмерных объектов, и как свойство битмапа для кнопок.

В это то и суть ECS как я понял, в эдакой "ориентированности на данные. Чтобы Entity полностью определялось набором компонент.
Вот взять компонент (т.е. свойство) "камера" у энтити. А что это за камера? Это "указатель на принадлежность к камере на которую следует спроецировать модель" для рендеринга? Или это сама по себе камера, как независимый объект, который можно инициализировать, повернуть, удалить. Или это "камера игрока" которой он может крутить и управлять.
Ответ: как угодно, хоть все три варианта сразу, как пожелает разработчик.
Так, собственно и можно сделать.
1.Если в энтити нет ничего кроме камеры, то эта энтити и есть камера. К ней можно применять функции для камеры.
2.Если в энтити есть камера и 3д модель, то 3д модель тут главнее. В таком контексте, это "указатель" на камеру для трёхмерной модели, т.е. та камера на которую её нужно проецировать. Если тут стоит NULL, то модель не нужно рендерить вообще. А если стоит какая-то другая камера, то может следует отрендерить с другого ракурса.
3. Если в энтити есть камера и "игрок", то значит, это камера которой управляет игрок. Т.е. крутится она должна уже по в зависимости от того как игрок вращает мышкой. При этом 3д модели может и не быть вообще (например, если игрок невидимый). То есть, если в пункте 2, у нас модель была основной (без модели, энтити превратился бы просто в пункт 1, камера), то если присутствует компонент "игрок", то модель уже отходит на третий план, и камера теперь уже свойство игрока а не модели. Причём, игрок то может не содержать в себе камеры. В таком случае камера может быть просто статично где-то закреплена, а игрок просто ходит и рендерится как в сайлент хиле, с неподвижной камерой.
Аноним  Вт 08 окт 2024 12:27:54 468305 159
image.png 12Кб, 667x462
667x462
Всвязи с тем, что мы можем рассматривать камеру как "свойство", я подумал, а в чём ценность такого свойства, если сам рендерер содержит функцию "perspective projection", что как бы предполагает что рендерер заранее знает что камера именно перспективная, и использует метод камеры. Непорядочно выходит! не по-полочкам!

Тогда, решил вот такую фигню отчебучить. Projection это у нас указатель на функцию. И камера, содержит метод Capture типа "указатель на функцию Projection". Тогда получается. что можно сделать два вида проекции, допустим перспективная и ортогональная. И внутри функцию Render, сам рендер будет вызывать метод камеры. Таким образом, далёкие объекты вообще можно рендерить чисто ортогонально. Либо ещё что-нибудь. Короче, это более гибкий и логичный подход, мне больше нравиться, так как выглядит более красиво, поэтому оставлю так.
Аноним  Вт 08 окт 2024 12:34:50 468328 160
image.png 67Кб, 800x600
800x600
И оно работает! как по-маслу. Ни одной ошибки при компиляции даже не выдал. Удобно.
Аноним  Вт 08 окт 2024 14:18:53 468493 161
Может начать реализовывать физику? Вернёмся на второй курс, теоретическая механника точки, кинематика, статика, динамика.
Аноним  Вт 08 окт 2024 14:21:36 468496 162
Или попроще, для начала анимации сделать.
Аноним  Пт 11 окт 2024 00:41:09 472862 163
image.png 6Кб, 800x600
800x600
image.png 14Кб, 667x462
667x462
image.png 15Кб, 667x462
667x462
Раз уж я начал кодить на С в стиле "ооп" то почему бы кнопки не отрисовать

Буквально ведь на С можно сделать практически "классы"
Аноним  Пт 11 окт 2024 00:46:55 472873 164
image.png 15Кб, 800x600
800x600
Ахаха. Я сегодня сделал функцию RescaleImage. Подумал, раз уж реализация текстурок научила меня тому, что в интерполяции ничего страшного и сложного нет, то почему бы не сделать механизм растягивания изображений.

Изначально я предполагал, что благодаря этому, можно будет взять один "шаблон" для кнопки, и задать ему разные размеры, а он будет растягивать картинку под эти размеры. Итог:пикрил. Растягиваются все картинки. И не удивительно, ведь картинка по-сути содержит просто указатель на холст. Холст не дублируется. Причём, остальные картинки например "выделенной иконки", остаются прежними в размерах, ведь картинка скалируется только когда инициализируется кнопка.

Ну и хуета. Но забавно, мне нравится когда ошибки выдают "забавный" результат.
Аноним  Пт 11 окт 2024 21:28:14 474195 165
2024-10-11 23-02-21.mp4 4610Кб, 1920x1080, 00:00:15
1920x1080
Почему-то кнопки тормозят. Если с флагом -O3 откомпилить, то торможение уйдёт. Но всё какая-то фигня. Что-то я неоптимально сделал. Даже 3д модель не тормозила, а кнопки тормозят.
Аноним  Пт 11 окт 2024 21:47:34 474249 166
2024-10-11 23-41-45.mp4 3754Кб, 1920x1080, 00:00:12
1920x1080
2024-10-11 23-43-37.mp4 7778Кб, 1920x1080, 00:00:25
1920x1080
Хз. Может в вычислении "середины надписи" дело. Там цикл стоит. А цикл - всегда источник потери лишних тактов.

Пофиг, пока оставлю так. По крайней мере, я вообще не планировал делать кнопки с надписями, потому что все кнопки должны быть нарисованы в интересном стиле каком-нибудь, где "просто шрифты" явно не подойдут.
Аноним  Сб 12 окт 2024 12:25:01 474959 167
image.png 437Кб, 512x384
512x384
image.png 553Кб, 564x567
564x567
image.png 393Кб, 564x411
564x411
image.png 473Кб, 564x564
564x564
Самое нудное и скучное в разработке - это создание 3d моделек. Даже на простую лоупольку может уйти 1-2 дня (это с текстурингом). А ведь некоторые модели ещё и анимированными должны быть. Разработка игровых ресурсов наверное занимает даже больше чем разработка движка.
Аноним  Сб 12 окт 2024 18:22:29 475655 168
image.png 5Кб, 800x600
800x600
Сделал так называемые "дженерик" кнопки. Это кнопки которые не содержат битмапов, и отрисовываются встроеными алгоритмами, со встроенным шрифтом. Хз зачем, просто чтобы были если вдруг лень будет с битмапами таскаться.
А, вот, нужно сделать чтобы их поля находились в "виджете" а не в "скине виджета" как это с обычными кнопками делается, чтобы можно было множество кнопок разных размеров создать, но с одним цветовым скином.
Аноним  Сб 12 окт 2024 18:54:59 475670 169
image.png 3Кб, 800x600
800x600
Во! Работают чуть по-быстрее чем обычные кнопки
Аноним  Сб 12 окт 2024 20:33:55 475786 170
2024-10-12 22-16-42.mp4 5612Кб, 1920x1080, 00:00:18
1920x1080
Тормозит похоже что ещё из-за OBS. Тесировал кнопки без OBS всё работало быстро.
Вот, сделал систему GUI получается.
Теперь можно под неё разрабатывать "ползунки", "инвенари", "миникарты" и другие элементы что используются в игре.
GUI по-сути выполняет только отрисовку и "реакцию" свойственную определённому типу элементов. А отработчик WidgetHandler заточен под то, чтобы придать виджету функционал, т.е. отдать что-то "сесии" основываясь на внутренних полях кнопки.
Тут сразу несколько паттернов используется:
- стратегия
- наблюдатель
- синглтон.

Стратегия заключается в том, что сама по себе "система виджетов" просто хранит общие свойства "какого-то" абстрактного виджета. Каждая ячейка хранит "текст, координаты, смещение, статус, тип, скин" итд. А то, чем является виджет определяет поле "тип" которое задаётся исплючительно функцией, типо AddButton, AddMenu итд.

Наблюдатель, заключается в том, что все виджеты вызывают метод "действие" каждый цикл (либо может быть не вызывают его). Суть в том, что каждая кнопка - это "подписчик клавиш управшения" и она выполняет свои функции в зависимости от поступления новой информации.

Синглтон заключается в том, что есть такой объект как "дженерик шрифт" соостветственно для дженерик кнопки. Он создаётся единственный раз, при первой инициализации кнопки. В будущем, если создаётся кнопка с другим скином, новый скин просто "перенимает указатель" на уже созданный шрифт.
Скин сам по себе отчасти выполнен как "синглтон". У скина существует "количество ссылок". И при инициализации новой кнопки, вначале проверяется, присвоен ли этот скин кому-то ещё. Если присвоен - то количество ссылок у скина увеличивается. Когда удаляется - напротив, количество ссылок уменьшается. И в случае, если удаляемый объект содержит скин с 0 ссылок, то этот скин из памяти удаляется.
Тут правда есть большое неудобство: а что если мы заходим убрать все кнопки, а потом заново восстановить. А все скины уже удалили. Так что хз, может я зря это сделал. Может не нужно было такое "самоочищение" организовывать.
Аноним  Сб 12 окт 2024 21:20:27 475821 171
image.png 493Кб, 563x576
563x576
image.png 209Кб, 513x630
513x630
image.png 114Кб, 328x386
328x386
Весь день убил на этот гуй всратый. А толку? Всего то ещё один дополнительный вид кнопок добавил.
И ведь нужно всякие другие элементы сделать. Например "ячейка" - ячейка инвентаря. Как в world of warcraft, minecraft и других играх. Часто используемый элемент гуя.
Аноним  Сб 12 окт 2024 21:28:53 475839 172
Ещё неплохо было бы сделать 2.5D объекты. Т.е 2д картинки, которые скалируются в зависимости от удалённости от камеры. и рендерятся в точке. Как в Doom короче. Такими объектами можно было бы сделать эффект "старой" графики. Плюс всякие динамические фишки типо "полоски урона".
Аноним  Пн 14 окт 2024 14:55:50 479133 173
image.png 289Кб, 564x410
564x410
image.png 280Кб, 564x450
564x450
image.png 498Кб, 564x423
564x423
image.png 1207Кб, 736x736
736x736
Аноним  Вт 15 окт 2024 14:32:08 481265 174
2024-10-15 16-29-43.mp4 7584Кб, 1920x1080, 00:00:24
1920x1080
Сделал свой каловый формат анимации
Аноним  Вт 15 окт 2024 16:45:30 481400 175
2024-10-15 16-56-53.mp4 3108Кб, 1920x1080, 00:00:10
1920x1080
Поправочка. Односвязный список же перебирается в обратном направлении. Значит нужно в обратном направлении и записывать кадры в файл, чтобы при воспроизведении он читал их в правильном порядке.
Аноним  Вт 15 окт 2024 20:01:15 481690 176
2024-10-15 21-52-21.mp4 1064Кб, 1920x1080, 00:00:03
1920x1080
таааак... какие-то проблемы с анимацией. Придётся переделывать.
Надо поступить по-другому. Сейчас у меня анимации рассчитываются исходя из изменения координат, т.е. dx, а нужно чтобы они явно указывали x, т.е. какая координата будет в следующем кадре.
Аноним  Вт 15 окт 2024 21:47:55 481827 177
2024-10-15 23-23-17.mp4 4845Кб, 1920x1080, 00:00:15
1920x1080
Результат получше. Есть свои плюсы и минусы так сказать
+ Обратимость. При желании можно отмотать анимации сразу на несколько кадров. Не требуется "сохранительного" буфера для начального положения.
+ Предсказуемость. Отсутствует дифференциальная ошибка (если выражатся языком ТАУ). Анимация в любой её форме является зацикленной, так как возврат в обратное положение происходит автоматически, за счёт того что все кадры - просто указывают координаты. Таким образом, можно не беспокоится что анимация куда-то "улетит", из-за отсутствия зацикленности.
- Требовательность вычислений. В отличии от анимации "по рассогласованию", для реализации ключевой анимации требуется "синтерполировать" координаты между кадрами. Если при dx достаточно было это dx поделить на количество фпс, то тут вначале нужно вычислить этот самый dx причём для каждой точки.
Наверное придётся оставить этот вариант, так как предыдущий череват помехами.
Аноним  Вт 15 окт 2024 22:54:25 482010 178
2024-10-16 00-51-30.mp4 5403Кб, 1920x1080, 00:00:17
1920x1080
А, проблема не в интерполяции. Пайтон-скрипт не в том порядке кадры формирует.

Настройки X
Ответить в тред X
15000
Sage
Добавить файл/ctrl-v
Стикеры X
Избранное / Топ тредов