Так то они есть, просто я не уверен, о чём рассказывать n-ая часть вещей довольно таки стандартна, чтобы это обсуждать. Но в целом да, можно бы и рассказать, какие стандартные вещи ( и менее стандартные но и не особо выделяющиеся ) в нём есть. Звук работает на OpenAL. Если кому-то нужно я могу добавить Direct Sound как вариант. Для физики используется BulletSharp, он примечателен тем, что можно создавать мягкие тела. Система физики в главном смысле готова, но кое-какие вкусные улучшения ещё будут — например, надстройка к движку, делающая так, чтобы объекты издавали звук когда они катятся или "скользят" ( определяется по скорости, дельте вращения и т.д. Сам звук, разумеется, нужно присваивать физическим материалам, чтобы он играл )
afq, документацию сделаю. А что вы имеете ввиду под секретами я не понял. Возможно, секреты по поводу функционала движка? Для сохранения интересов возможных разработчиков на этом движке есть один секрет — это как работает шифрование игровых архивов. Всё, что я скажу — это многоступенчатое шифрование. P. S данные могут храниться и не в архивах
TimKruz, игровой движок, хотя также может быть использован и для неигровых проектов, использующих рендеринг. Он имеет комбинированную систему компонентов И объектов, производных от главного класса объекта сцены, так что это кому как удобно. По поводу структуры движка, то я стараюсь сделать её удобной насколько меня хватает пока-что я сфокусирован на рендеринге из-за того, что это значительно влияет на структуру движка. Разумеется, я тоже согласен что в играх геймплей важнее. И да, самый главный компонент движка, то есть сам движок как библиотека, имеет вес всего 327 кб. ( без SDK. Размер SDK ещё не могу сказать ) Библиотека вмещает всё основное. Дополнительные функции ( например, встроенные сеты компонентов/объектов, специфичных для конкретных целей ) будут поставляться как надстройка в движку.
P. S. собственно, цель движка как раз в том, чтобы обеспечить максимальный комфорт от разработки проектов не теряя при этом возможностей.
Сообщение отредактировал dima13230 - Пятница, 03 Мая 2019, 16:13
Возможно В любом случае это лишним не будет, не правда ли? Даже персонально мне это может пригодиться. Я же не делаю кашу из всего этого, а структурирую в отдельные классы, пространства имён и т.д. Мешать не будет.
Грубо говоря да, но не совсем. Тем не менее, это отдельная система для отдельного использования вычислительных шейдеров в целях отличающихся от рендеринга. Допустим, нам надо процедурно сгенерировать мир, являющийся космическим пространством с высокодетализированными планетами. Делая всё это через рядовой процессор, пользователь успеет три раза выспаться и сходить на работу Гораздо эффективнее это делать через вычислительные шейдеры. С другой стороны, разумеется их можно использовать и наряду с обычными для рендеринга. Например, мой рендер использует вычислительные шейдеры в местах, где это выгодно.
И вообще я делаю движок не только для игр, но и для различных исследовательских проектов, например.
Сообщение отредактировал dima13230 - Воскресенье, 28 Апреля 2019, 20:49
Честно говоря, пока это никак не реализовано Насчёт DX11 я пока не думал, пока что я работаю над тем что касается OpenGL. Затем уже приступлю к DX и Vulkan. Идея в том, что создаётся отдельный буфер для вычислительных шейдеров, а также система, практически идентичная системе модулей рендеринга, но для вычислительных шейдеров. Всё будет происходить в отдельном, независимом потоке.
Сообщение отредактировал dima13230 - Воскресенье, 28 Апреля 2019, 17:51
Не совсем так, вы неправильно поняли что я имел ввиду. Один модуль рендеринга - это отдельная компилируемая библиотека. Он может обращаться к другим модулям, получать какие-либо значения от них через виртуальную базу параметров и т.д. Например, есть модуль SuperRender.dll; в нём происходят какие-либо главные манипуляции, затем он подаёт запрос на выполнение модуля PostEffects.dll и так далее. Это делает настройку рендеринга наиболее гибкой. В целом я планирую также сделать возможность создавать иерархию выполнения модулей через файл конфигурации, так что, например, пользователь будет иметь возможность настраивать то, как будет выглядеть игра. Можно перейти от графики AAA до таковой а-ля Tomb Raider 1996 года. Можно делать моды для игр, которые будут менять графику игры - немного или полностью.
Но, честно говоря, такое решение будет несколько уменьшать производительность. Тем не менее, ничто не мешает сделать весь процесс рендеринга как всего лишь один модуль - ограничений нет. Также можно распределять рендеринг объектов по слоям. Например, объекты слоя 1 рендерятся через SuperRender.dll, объекты слоя 2 через OtherRender.dll и так далее. В целом это даст наиболее настраиваемые возможности для рендеринга и также может иметь применение не только в геймдеве, но и каких-либо исследовательских проектах. Эти модули подключаются не во время компиляции, а во время выполнения, при этом можно подключать/отключать/переключать модули программно, прямо во время выполнения проекта.
Цитатаdrcrack ()
система компонентов имеет много минусов и поэтому в юнити уже есть альтернативное решение, более производительное и хорошо масштабирующееся под большие проекты
В целом помимо системы компонентов в Neira Engine можно делать классы, наследующиеся от класса объекта мира. Например, вместо компонента "PlayerController", можно сделать класс "Player", наследующийся от класса WorldObject, в котором можно переопределять методы типа Start; Update, после этого также можно сделать класс, который наследуется от "Player", например, "FirstPersonShooterPlayer", который будет расширенной версией класса "Player" и так далее по необходимости. При этом FirstPersonShooterPlayer сможет по прежнему иметь подключаемые компоненты.
Добавлено (28 Апреля 2019, 16:11) ---------------------------------------------
Цитатаmartuk ()
dima13230, есть уже офф. сайт, где можно было бы побольше информации потрогать? Этот движок можно подключить к c++ проекту? Оно распространяется как подключаемая библиотека или же вокруг вашего редактора нужно будет скакать?
Пока офф. сайта нет. Сам движок на С#, и в принципе я не планировал его связь с С++, так что подключить не получится. Разве что если выполнять С++ код из скомпилированной библиотеки ( C# предоставляет такую возможность ). Neira Engine будет доступен как всего лишь одна подключаемая библиотека, к которой будет иметь SDK с редактором и остальными инструментами.
Добавлено (28 Апреля 2019, 16:24) ---------------------------------------------
Цитатаdrcrack ()
Модули compute-шейдеров, выполняющиеся в отдельном потоке.
я честно говоря не понял что это
Вычислительные шейдеры, то есть вычисления, выполняющиеся на GPU, которые затем могут быть использованы CPU. И эти вычисления выполняются в отдельном потоке, независимо от рендеринга.
Сообщение отредактировал dima13230 - Воскресенье, 28 Апреля 2019, 16:44
drcrack, в целом, я хотел написать такой формат шейдеров, который был бы универсальным для всех API. Однако размышляя над вашими словами по поводу пользы этой затеи уже второй раз, соглашусь с вами. Что я могу взять из этой задумки, так это структуры, виртуально представляющие код шейдера, что уже использовать для визуального создания шейдеров. P.S. транслятор типа GLSL<->HLSL и вообще поддержка этих языков также планировалась, а NESL как надстройка для того, чтобы не было нужды постоянно транслировать один формат шейдера в другой и притом сохраняющий весь функционал и самые основные черты синтаксиса вышеназванных.
Цитатаdrcrack ()
касательно синтаксиса: 1. как так вышло что с языка выкинули все лишнее, но оставили uniform 2. чем color отличается от vector4 3. если = и присваивание и сравнение, то Код
int a = b = 4 // чему равно a? 4 или 1 (после конвертации из bool)?
1. Uniform там как раз для транслирования в GLSL или HLSL. Ведь как я уже говорил, NESL не выполняется, а транслируется в эквивалентный по смыслу но отличающийся по синтаксису код на GLSL или HLSL. 2. В целом — ничем. В HLSL, как мы знаем, есть семантики, так вот когда мы объявляем "color x", то для HLSL это транслируется в
Код
float4 x : COLOR0
Color0 это, color1 ли и так далее определяется по порядку инкремента, то есть с каждой новой переменной типа color, для неё будет свой семантик COLOR со своим номером.
3. В момент объявления а = 4. И в целом такая запись не будет интерпретироваться как условие. В этом языке всё было бы основано на логике: условие может быть только там, где оно нужно. Это if, for, while, в крайнем случае по прежнему объявление переменной, но внутри условного оператора типа [cond] ? (value if true) : (value if false). Когда мы дошли до условия, внутри if, например, переменной значение присвоить не получится да и не имеет смысла, не так ли? Поэтому автоматически знак равно распознаётся как символ условия, а не присваивания. Говоря на примере кода:
Код
// a = 4, как и b int a = b = 4
void main () // код внутри условия будет всегда выполняться, так как, во-первых, интерпретатор сразу понимает, что сразу после if может быть только условие и, во-вторых, а, как и b, равны 4. if a = b ... e
Сообщение отредактировал dima13230 - Среда, 01 Мая 2019, 09:58
Neira Engine - объектно-ориентированный движок на C#, поддерживает OpenGL, DirectX и Vulkan. ( на данный момент только OpenGL, остальное - в планах ) Имеет некоторые особенности, которые выделяют его среди остальных:
Система модулей рендеринга. Это когда независимо от всех остальных компонентов движка можно создать свою собственную систему рендеринга. Прошу не путать с той, что недавно появилась в Unity - данная система отличается довольно значительно. Отдельный модуль - отдельная .dll библиотека, один модуль может выполнять весь рендеринг или составлять "дерево рендеринга" с другими модулями. Объекты можно разделять на "слои рендеринга", таким образом, для определённых слоёв будут свои модули рендеринга. Под спойлером графическое представление, примерно демонстрирующее какое-нибудь "дерево" модулей, а также объяснение на основе этого изображения:
Итак. Допустим, мы подключили некий главный модуль. Этот главный модуль последовательно запускает и управляет модулями 1, 2, 3, 4. Данные модули имеют параллельную связь, это значит, что, выключив, например, модуль 3, все остальные, включая модуль 4 ( и вообще любые, какие могли бы быть после 3-его ) по прежнему выполняются в заданном порядке. С другой стороны, модуль 1 запускает и контролирует соответственно модули 1.1 и 1.2 - в данном случае, выключив модуль 1, выключатся, разумеется, и модули 1.1, 1.2. При этом каждый этот под-модуль по прежнему может запускать и управлять другими модулями и так до бесконечности. ( по крайней мере, до лимита, который может выдержать компьютер ) Как видно из картинки, они тоже имеют параллельную связь. В целом, не обязательно иметь главный модуль, можно начинать процесс рендеринга с любого количества модулей.
NESL - собственный язык шейдеров, имеющий очень простой синтаксис и именно тем особенный. На программном уровне разделяется на структуры, позволяющие процедурно генерировать шейдеры. ( поэтому это может быть использовано для визуального создания шейдеров ) Пример:
Код
uniform color x
color d(float a) return a * 2
void main() color i = d(x)
if i = 6 i = 9 else i++ e
i *= 1.5 outColor = i
Простота синтаксиса основана на элементарной логике, он не требует фигурных скобок или, например, табуляций, чтобы определять принадлежность к какому-либо методу ( при этом if-else, for, while в методах требуют "e", наподобие "end" в lua ). В шейдерах, если это не объявление переменной или структуры, не может быть кода вне объявлений методов, именно на этом и работает принцип синтаксиса. С другой стороны, метод может кончиться только когда после него объявляется другой метод или кончается файл. Переменные и структуры всегда объявляются в начале перед методами. Этот язык отличается от Си-подобных простотой синтаксиса ( нет нужды в точках с запятой, фигурных скобках ), но и никак не ограничивает функционал по простой причине: он интерпретируется не для выполнения, а для создания виртуальной структуры, репрезентирующей этот код, которая затем транслируется в эквивалентную запись на языке GLSL или HLSL в зависимости от используемого API.
Модули вычислительных шейдеров, выполняющихся независимо от рендеринга. Сами модули рендеринга также включают возможность выполнения вычислительных шейдеров, но в данном случае они, в большинстве случаев, будут использованы как раз для рендеринга. Однако иногда таковые нужны для другого типа вычислений, например, процедурная генерация большого мира. Система модулей вычислительных шейдеров же работает по очень похожему принципу что и система модулей рендеринга, но, во-первых, выполняется независимо от самого рендеринга и, во-вторых, предоставляет методы, помогающие именно в вычислениях на GPU, не относящихся к рендерингу.
Самое главное вроде-бы рассказал. Сам движок к релизу не готов, но скриншоты показать уже могу:
Задавайте вопросы, делитесь отзывами, мне интересно знать ваше мнение.
Сообщение отредактировал dima13230 - Вторник, 30 Апреля 2019, 23:55
Добавлено (14 апреля 2016, 22:26) --------------------------------------------- Есть проблема. Проходит время "темпа стрельбы" и турель начинает стрелять, но не с таким-же темпом а без перерыва
Код
public List<Transform> targets = new List<Transform>(); // Цели, но без тех, что не нужны, т.е без тех, которые не соответствуют тегу или находятся за препятствием List<Transform> separatedTargets = new List<Transform>(); public Transform target; // скорость вращения public float rotationSpeed = 1F; //мертвая зона вращения (чтобы турель не дергалась при x=0) public float deadZone = 0.1F; //направление вращения ( "0" - не вращать, "1" - вправо и "-1" - влево) private float rotateDirection = 0;
public GameObject Bullet; public bool IsShooting;
public int layerMask = 1 << 8;
public float ShootPeriod = 0.1f;
public TurretCannon[] Cannons;
void Start() { }
void LateUpdate() { if (IsShooting) { for (int i = 0; i < Cannons.Length; i++) { StartCoroutine(Cannons[i].Shoot()); } } if (targets.Count > 0) { List<float> distances = new List<float>(); for (int i = 0; i < targets.Count; i++) { if (targets[i].tag != "StaticObject" && targets[i].tag != "TurretFriendly" && targets[i].tag != "TurretIgnore" && !Physics2D.Linecast(this.transform.position, targets[i].position,layerMask)) { separatedTargets.Add(targets[i]); distances.Add(Vector2.Distance(this.transform.position, targets[i].position)); } } Debug.Log(distances.Count);
public GameObject Bullet; public Transform ShootPoint; public float ShootRate;
public AudioClip ShootSound; public float ShootingVolume;
public IEnumerator Shoot() { yield return new WaitForSeconds(ShootRate); MonoBehaviour.Instantiate(Bullet, ShootPoint.position, ShootPoint.rotation); AudioSource.PlayClipAtPoint(ShootSound, ShootPoint.position,ShootingVolume); } }
Добавлено (15 апреля 2016, 11:51) --------------------------------------------- Исправил, работает всё.
Турель:
Код
public List<Transform> targets = new List<Transform>(); // Цели, но без тех, что не нужны, т.е без тех, которые не соответствуют тегу или находятся за препятствием List<Transform> separatedTargets = new List<Transform>(); public Transform target; // скорость вращения public float rotationSpeed = 1F; //мертвая зона вращения (чтобы турель не дергалась при x=0) public float deadZone = 0.1F; //направление вращения ( "0" - не вращать, "1" - вправо и "-1" - влево) private float rotateDirection = 0;
public GameObject Bullet; public bool IsShooting;
public int layerMask = 1 << 8;
public float Rate = 1;
public TurretCannon[] Cannons;
//public bool IsShootingRaty = true;
void Start() { }
public void Shoot() { for (int i = 0; i < Cannons.Length; i++) { if (!Cannons[i].Shooted) { StartCoroutine(Cannons[i].Shoot()); } } }
void LateUpdate() { if (IsShooting) { Shoot(); } if (targets.Count > 0) { List<float> distances = new List<float>(); for (int i = 0; i < targets.Count; i++) { if (targets[i].tag != "StaticObject" && targets[i].tag != "TurretFriendly" && targets[i].tag != "TurretIgnore" && !Physics2D.Linecast(this.transform.position, targets[i].position,layerMask)) { separatedTargets.Add(targets[i]); distances.Add(Vector2.Distance(this.transform.position, targets[i].position)); } } Debug.Log(distances.Count);
Не знаю почему, но я добавил layerMask в аргументы Physics2D.LineCast и всё заработало
Добавлено (14 апреля 2016, 21:47) --------------------------------------------- а массив distances был пуст
Добавлено (14 апреля 2016, 21:48) --------------------------------------------- теперь нет
Добавлено (14 апреля 2016, 22:04) --------------------------------------------- Скрипт полностью готов и функционирует:
Код
public List<Transform> targets = new List<Transform>(); // Цели, но без тех, что не нужны, т.е без тех, которые не соответствуют тегу или находятся за препятствием List<Transform> separatedTargets = new List<Transform>(); public Transform target; // скорость вращения public float rotationSpeed = 1F; //мертвая зона вращения (чтобы турель не дергалась при x=0) public float deadZone = 0.1F; //направление вращения ( "0" - не вращать, "1" - вправо и "-1" - влево) private float rotateDirection = 0;
public GameObject Bullet; public bool IsShooting;
public int layerMask = 1 << 8;
public float ShootPeriod = 0.1f;
public Transform[] SpawnPointsTransforms;
public IEnumerator Shoot() { yield return new WaitForSeconds(ShootPeriod); for (int i = 0; i < SpawnPointsTransforms.Length; i++) { Instantiate(Bullet, SpawnPointsTransforms[i].position, SpawnPointsTransforms[i].rotation); } }
void Start() { }
void LateUpdate() { if (IsShooting) { StartCoroutine(Shoot()); } if (targets.Count > 0) { List<float> distances = new List<float>(); for (int i = 0; i < targets.Count; i++) { if (targets[i].tag != "StaticObject" && targets[i].tag != "TurretFriendly" && targets[i].tag != "TurretIgnore" && !Physics2D.Linecast(this.transform.position, targets[i].position,layerMask)) { separatedTargets.Add(targets[i]); distances.Add(Vector2.Distance(this.transform.position, targets[i].position)); } } Debug.Log(distances.Count);
dima13230, Ты бы делился своим кодом народу же интересно)
Нет проблем :)) Ловите код, но скажите, почему так сильно лагает когда турель наводится?
Код
public List<Transform> targets;
public Transform target; // скорость вращения public float rotationSpeed = 1F; //мертвая зона вращения (чтобы турель не дергалась при x=0) public float deadZone = 0.1F; //направление вращения ( "0" - не вращать, "1" - вправо и "-1" - влево) private float rotateDirection = 0;
public GameObject Bullet; public bool IsShooting;
void Start() { targets = new List<Transform>(); }
void LateUpdate() { if (targets.Count > 0) { float[] distances = new float[targets.Count];
Добавлено (14 апреля 2016, 16:42) --------------------------------------------- Сейчас буду работать над обнаружением препятствий, чтобы не стреляла и не наводилась на стенки :)))
Добавлено (14 апреля 2016, 18:30) ---------------------------------------------
Код
public List<Transform> targets = new List<Transform>(); // Цели, но без тех, что не нужны, т.е без тех, которые не соответствуют тегу или находятся за препятствием List<Transform> separatedTargets = new List<Transform>(); public Transform target; // скорость вращения public float rotationSpeed = 1F; //мертвая зона вращения (чтобы турель не дергалась при x=0) public float deadZone = 0.1F; //направление вращения ( "0" - не вращать, "1" - вправо и "-1" - влево) private float rotateDirection = 0;
public GameObject Bullet; public bool IsShooting;
void Start() { }
void LateUpdate() { if (targets.Count > 0) { List<float> distances = new List<float>(); for (int i = 0; i < targets.Count; i++) { if (targets[i].tag != "StaticObject" && targets[i].tag != "friendly" && !Physics2D.Linecast(this.transform.position, targets[i].position)) { separatedTargets.Add(targets[i]); distances.Add(Vector2.Distance(this.transform.position, targets[i].position)); } }
https://vimeo.com/channels/115146/page:2 смотри тут, все понятно и просто под себя переделать
тяжеловато мне будет с медленным инетом видео смотреть...
Добавлено (14 апреля 2016, 13:59) --------------------------------------------- даже сам сайт не грузится
Добавлено (14 апреля 2016, 14:11) --------------------------------------------- Итак, минимальное значение числа в массиве я получил, а как по нему найти индекс массива, в котором содержится это число?
Добавлено (14 апреля 2016, 14:19) --------------------------------------------- всё
Добавлено (13 апреля 2016, 22:21) --------------------------------------------- Так, попробовал переработать под турель, не работает
Добавлено (13 апреля 2016, 22:35) --------------------------------------------- Короче, может я сделаю круглую зону видимости? Типа у турели например камера во все стороны крутится и обнаружение звука.
В общем, мне нужно создать зону видимости в форме "сектора круга". Для наглядности и тех кто не знает, сектор круга выглядит вот так:
Добавлено (12 апреля 2016, 21:09) --------------------------------------------- P.S забыл сказать, что всё происходит в 2D среде
Добавлено (12 апреля 2016, 21:30) --------------------------------------------- Я кажется придумал. Я возьму картинку этого сектора, создам объект, добавлю Polygon Collider, включу режим Is Trigger, выключу Renderer спрайта и всё, остаётся только проверять, стоит ли объект в триггере.
Добавлено (12 апреля 2016, 21:35) --------------------------------------------- Но как определить сколько объектов входит в триггер и до какого из них меньше расстояние?
Добавлено (12 апреля 2016, 21:43) --------------------------------------------- У меня всплыл другой вопрос: как определить какое число в массиве самое маленькое?
Сообщение отредактировал dima13230 - Вторник, 12 Апреля 2016, 21:12
Короче, я опять столкнулся с проблемой, которую не могу решить :-))) Мне нужно сделать подстройку тайлов под террейн, то есть если террейн идёт в склон, то тайл должен меняться на "съезжающий"
Если нужно дать какой-то код, скажите.
Добавлено (24 марта 2016, 16:52) --------------------------------------------- P.S - выбор тайла осуществляется выбором "индекса" в картинке, то есть части картинки как бы "разделяются" на 15*15 маленькие картинки и среди них выбирается нужный тайл. Для наглядности вот:
P.S.S - я не делаю клон Террарии, пусть чуть-чуть задумка схожая, но у меня будет всё по другому. И то, что тайлы оттуда, это временно - других нет.
Сообщение отредактировал dima13230 - Четверг, 24 Марта 2016, 17:00
Добавлено (24 марта 2016, 01:28) ---------------------------------------------
ЦитатаFlyOfFly ()
Спасибо, поставил, включил, там половина экрана отображается, убрал деление на два - стало показывать на полный экран, теперь всё работает так, как нужно :).
Тогда попробуй так Код
for (int x = ((int)cam.Pos.X / 15); x < (cam.Pos.X / 15) + graphics.GraphicsDevice.Viewport.Width / 15; x++) { for (int y = ((int)cam.Pos.Y / 15); y < (cam.Pos.Y / 15) + graphics.GraphicsDevice.Viewport.Height / 15; y++) { if (x < 0 || x >= ViewTilesWidth) continue; if (y < 0 || x >= ViewTilesHeight) continue; if (tiles[x, y] != null) { int id = (int)tiles[x, y].type;
Спасибо, поставил, включил, там половина экрана отображается, убрал деление на два - стало показывать на полный экран, теперь всё работает так, как нужно :).