[Лог #7] Класс рисовальщика.

» опубликован

Рендер

Темой этого лога станет рендер. Расскажу немного о том как я себе представляю виртуального художника и почему лучше реализовать интерфейс IRender и класс-реализацию CRenderOGL, наример.
Хочется провести некоторые аналогии, которые по моему очень чётко вписываются.
Класс "рисовальщик" именовал я раньше как RenderDevice, но что это такое вообще? Зачем какие-то классы городить, когда есть, например, OpenGL? Конечно для удобства использования.
Класс IRenderDevice можно назвать художником, причём очень хорошо ему это имя подходит.
Можно сказать художнику "нарисуй мне вот тут квадрат", собственно это было бы эквивалентно такому вот вызову в коде "pRenderDevice->DrawQuad( .... )".
Художник не может нарисовать ничего, если у него нет холста, красок и кистей, и тут вновь можно провести аналогию.
Роль холста будет играть "контекст устройства"( как я понимаю это просто особая видеопамять, вернее её часть) - имеется у всех окон. Тут всё ясно холст - окно.
Кисти или их эквивалент - модели и геометрия, даже не имеет значения 2Д или 3Д. Возможно, кто-то знает, что геометрия(статичная?) в играх на движке Source, idTech и UnrealEngine называется Brush ( кисть ) - наверно просто совпадение, не думаю.
Кисть по холсту художник проведёт, но ничего не нарисует, поэтому нужны краски - текстуры, материалы, шейдеры (shaders). Думаю многие знают что из себя представляет шейдер - это подпрограмма для видеокарты, которая говорит как будет рисоваться 3Д модель. Экранный пост-процессы \ пост-эффекты - это тоже шейдер, например, свечение (glow, bloom), переход картинки в серость\цвет ( такой эффект был в игре Saboteur ).
Аналогии очень хорошо описывают набор классов графической библиотеки, однако, надо заметить, что нет конкретики. Это некая абстракция.
IRenderDevice - художник, а CRenderDeviceOGL - какой-нибудь Вася Пупкин, который вообще то тоже художник, но как видно уже конкретный.
Примерно вот так может выглядеть класс, вернее интерфейс для "художника":
class IRenderDevice
{
public:
	// Первичная инициализация GAPI-устройства
	virtual TResult	Init( WindowT *Window, int param ) = 0;

	// Инициализировать графический контекст для конкретного окна приложения 
	virtual TResult 	InitContextForWindow( WindowT *Window ) = 0;

	// Освободить граф.контекст окна
	virtual TResult 	CleanupContextForWindow( WindowT *Window ) = 0;

	// Сделать текущим(главным) контекст окна
	virtual TResult 	MakeCurrent( WindowT *Window ) = 0;

	// Сменить буфер изображения окна
	virtual TResult 	SwapBuffer( WindowT *Window ) = 0;

	// Финальная очистка граф.устройства
	virtual TResult 	Cleanup() = 0;

	virtual void ApplyView( GView * View ) = 0;
        virtual void SetMaterial( GMaterial * material ) = 0;
	virtual void DrawMesh( GMesh * Mesh ) = 0;
};
У методов этого класса нет реализации (конкретного кода) и они все виртуальные. Видно, что несколько первых методов - это инициализация, обновление кадра и освобождение ресурсов ( Init, SwapBuffer и Cleanup соответственно) - эти функции платформозависимые, что не есть хорошо вообще то. Но можно чуть-чуть избавится от зависимости "спрятав" зависимые от платформы типы и функции, например, тип переменной WindowT - произвольный (определённый мной, а не платформой), внутри которого есть платформозависимые переменные. Это сделано для того, чтобы не менять вызов функции, например:
Этот код не нужно будет менять для каждой платформы
pRenderDevice->Init( pMainWindow, 0 );
Для каждой ОС придётся лишь менять\написать код для класса WindowT и некоторые части от RenderDevice ( и\или других систем ).
Насколько это правильное решение - не знаю точно, возможно это вообще плохое решение.
Последние три функции интерфейса IRenderDevice - "применить вид", "установить материал" и "нарисовать модель". Конечно это не полный список функций, который пригодится, но для очень простых игр думаю даже такого хватит.
Функция ApplyView, которая принимает указатель на некий объект класса GView - особая штука, которой я можно сказать горжусь (хотя на самом деле нечем). GView - это что-то вроде виртуальной камеры, границ вида (вьюпорт \ viewport ) и матрицы проекции. Хранит в себе две матрицы - проекции (перспективная\ортогональная) и вида (положение и направление камеры).
Классы материала и сетки(mesh) вообще могут быть какими угодно, вернее информация которая в них хранится может быть различной и зависеть от "старшей" графической библиотеки (OpenGL \ DirectX).
Но не только материал и 3Д модель зависит от выбора библиотеки, собственно вся реализация интерфейса зависит от неё. Вот например если взять OpenGL, то может быть что-то вроде этого:
class GRenderDevice : public IRenderDevice
{
public:
	GRenderDevice();
	~GRenderDevice();

	// Первичная инициализация GAPI-устройства
	TResult		Init( WindowT *Window, int param );
	// Инициализировать графический контекст для конкретного окна приложения 
	TResult 	InitContextForWindow( WindowT *Window );
	// Освободить граф.контекст окна
	TResult 	CleanupContextForWindow( WindowT *Window );
	// Сделать текущим(главным) контекст окна
	TResult 	MakeCurrent( WindowT *Window );
	// Сменить буфер изображения окна
	TResult 	SwapBuffer( WindowT *Window );
	// Финальная очистка граф.устройства
	TResult 	Cleanup();

	void ApplyView( GView * View );
	void DrawMesh( GMesh * Mesh );

	void DrawVText( float x, float y, const char *strText, float size, bool bReversY = false );

	// Flags = 1 - color, 2 - depth, 4 - stencil
	enum{
		BIT_COLOR = 0x1,
		BIT_DEPTH = 0x2,
		BIT_STENCIL=0x4
	};
	void ClearScreen( int Flags = 0 );
	void ClearScreenColor( const float r, const float g, const float b, const float a );

	void BindTexture( GTexture * Texture );
	void SetWorldMatrix( const float * matrix );
	void SetWireframe( bool show = true );

	void	DrawRect( float x, float y, float xx, float yy );

protected:
	TResult		InitExtensions();
	HGLRC		m_hContext;      // На самом деле зависимая от платформы переменная
	WindowT		*m_pOwnerWindow;
};
Видно, что функций больше, да и переменные появились. (не забывайте, что это примеры, а в реальном проекте будет иначе). Можно создавать экземпляр этого класса и пользоваться всеми этими функциями, однако, если нужна независимость от OpenGL\DirectX, то нужно использовать IRenderDevice у которого функций меньше. Зачем тогда использовать этот урезанный класс? Дело в том, что реализацию художника можно загружать из DLL (если это реализовано, конечно), например, так сделано в Quake2 - рендер и механика игры загружаются из DLL.
Ну вот скажем та же функция ApplyView для OpenGL реализации будет выглядеть примерно так:
void GRenderDevice::ApplyView( GView * View )
{
	if( !View ) return;
// Задать вьюпорт
	View->SetViewport( 0, 0, GetBufferWidth(), GetBufferHeight() );

	glViewport( View->GetX(), View->GetY(), View->GetWidth(), View->GetHeight() );

// Утсановить матрицы (OpenGL-специичные функции)
	glMatrixMode( GL_PROJECTION );
	glLoadMatrixd( &View->GetProjectionMatrix().x[0][0] );
	glMatrixMode( GL_MODELVIEW );
	glLoadMatrixd( &(View->GetViewMatrix()).x[0][0] );
}
Или вот функция рисования сетки:
void GRenderDevice::DrawMesh( GMesh * Mesh )
{
	if( !Mesh ) return;

	GVertex3D * V		= Mesh->GetVertexArray();
	unsigned int Count	= Mesh->GetCountVertex();

// вновь специфичные функции
	glVertexPointer(	3,	GL_FLOAT, sizeof(GVertex3D), &(V[0].x) );
	glNormalPointer(		GL_FLOAT, sizeof(GVertex3D), &(V[0].nx) );
	glTexCoordPointer(	2,	GL_FLOAT, sizeof(GVertex3D), &(V[0].tu) );

// получить количество под-сеток
	unsigned int count_batch = Mesh->GetCountBatches();

// для каждой под-сетки ...
	for( unsigned int i=0; i< count_batch; ++i )
	{
		GBatch *b = 0;
		if( b = Mesh->GetBatch(i) )
		{

			if( b->m_MaterialID != -1 )
			{
//                             установить текстуру 
				BindTexture( FindTextureByID( b->m_MaterialID ) );
			}

//                     Нарисовать треугольники 
			glDrawElements( GL_TRIANGLES, b->GetCount(), GL_UNSIGNED_INT, b->GetPtr() );
		}
	}
}
Для DirectX реализации были бы совсем другие функции, но смыл бы не изменился.
Поэтому вызывая pRenderDevice->ApplyView( pView ) будет срабатывать специфичный код.
Честно говоря не очень хорошо получается у меня объяснить весь смысл, да что там - вообще не понятно что я тут написал :D
Конечно хотелось бы больше конкретного кода, но не учитель я :(
Да ещё и версия OpenGL, которую я ранее и использовал устарела, теперь придётся чуть обновить свои знания и подтянуть версию хотя бы OpenGL 3.3.

Что дальше ?

Думаю либо чуть увеличить разрыв между логами, либо небольшую паузу взять. Думаю начать уже конкретно проектировать само приложение (не писать код) и сделать небольшой альфа-прототип на каком-нибудь Unity (хотел вообще на GameMaker, но похоже с новым обновлением они отказались от WinXP - Steam отказывается запускать GM).
Заметьте ни одной картинки D: !


Просмотров: 21 239



» Лучшие комментарии


Doc #51 - 5 лет назад (отредактировано ) 3
Очень влияет на гибкость, она там прекрасная. Эта гибкость и есть минус.
Послушайте, когда-то я выдумывал как бы мне сделать систему способностей для пошаговой игры и где их хранить. Вот я тоже придумывал типа различные компоненты, которые значится где-то вместе связываются в цепочку, и хранятся в базе/в файлах, а потом достаются оттуда, парсятся и каждой компоненте присваивается действие, я подумал о разных вариантах абилок, понадобятся условия, циклы, модули, что-то еще... Да это целый скриптовый язык для абилок получается... НО У МЕНЯ УЖЕ И ТАК ЕСТЬ СКРИПТОВЫЙ ЯЗЫК, ЗАЧЕМ ИЗОБРЕТАТЬ ВЕЛОСИПЕД? Точно так же и в ск2 есть скриптовый язык, на котором можно написать все что угодно, нахрена вообще редактор объектов, на котором запиливание спелла может занять больше времени? Ого, я написал этот спелл без кода, я такой крутой! Правда тут пара хаков, там пара хаков, тут мелкий баг, ну никто все равно не заметит, а потратил то я всего два дня. Вы серьезно? Кому это нужно? А потом кода поднакопилось и в итоге половина логики, а половина там.
Всё уже сделано за вас, блин. Берете любой скриптовый язык и прикручиваете, ограничиваете сендбоксом область действия, пишете внятные интерфейсы/врапперы для объектов используемых в коде - вуаля, делаете ВСЁ, ЧТО УГОДНО. Гибче кода блин, ничего не будет. Что верно заметили, данные в нем хранить не нужно.
alexprey #52 - 5 лет назад 0
Doc, это такой вечный холивар между теми кто умеет программировать и теми кто привык мышкой блоки таскать
Doc #53 - 5 лет назад 0
alexprey, для таких придумали транслятор блоков в тот же самый код, гспди. А не парсер блоков и целую завязанную на нем систему билеберды и огромную архитектуру.
prog #54 - 5 лет назад 0
Doc, не знаю откуда такая лютая ненависть к ск2 и самой идее, но лично я пользуюсь и редактором данных и скриптами, когда у меня есть настроение что-то там по делать и нет настроения хардкорно кодить в более серьезном проекте. Что касается скриптового языка - это довольно удобно, но при такой архитектуре совершенно нереально часть работы спихнуть на геймдизайнера - все приходится кодить лично, что хорошо при работе в одно сопло, но отвратительно вписывается в командную работу.
alexprey #55 - 5 лет назад 0
но отвратительно вписывается в командную работу.
это еще почему?
prog #56 - 5 лет назад (отредактировано ) 0
alexprey, потому что команда, как правило, состоит не только из одних программистов и все доступные программисты, как правило, заняты не созданием контента и мыслями о балансе, а более важными вещами, вроде допиливания движка и багфикса.

Согласитесь, было бы странно, если бы, например, 3д-дизайнер вместо того, чтобы делать модели в 3д редакторе, прописывал бы их в коде или работал в редакторе, а потом экспоритровал результат не в сжатый бинарный формат, а прямо в програмный код.
Та-же судьба ждет и игровые данные, которых в крупных проектах становится все больше и больше - стать со временем независимыми от кода и получить отдельного специалиста для работы с ними.
Doc #57 - 5 лет назад 0
Но скрипты не обязательно должны быть прямо в коде и опять же, я писал о трансляторе, как это работает в вк3.
DarkDes #58 - 5 лет назад 0
Согласитесь, было бы странно, если бы, например, 3д-дизайнер вместо того, чтобы делать модели в 3д редакторе, прописывал бы их в коде
Собственно подобной мысли я держусь относительно некоторых конкретных игровых данных (это в тему псевдо-языка, вернее удобного хранения данных). Не буду говорить, что мол "вскроют блокнотом!Испортят весь баланс! ЧИТЫ!!11" - по идее можно зашифровать (а в случаи клиент-сервер вообще всё ложится на второго).
Думаю, что скриптовый язык - это жирно, правда я ещё не видел реальных примеров работы, например, lua и какой-либо игры. Не совсем понимаю, что можно хранить в скриптах отдельно от бинарного(основного) кода ?
alexprey #59 - 5 лет назад 0
DarkDes, да запросто
  • AlienShooter - почти вся игровая механика на скриптах О_О сам был в шоке когда нашел
  • World of Warcraft - вся логика интерфейса написана на lua, а так же пиратские сервера, большая часть логики написано тоже на нем же (не уверен)
  • Warcraft 3 - скрипты jass2, опять же большая часть логики для карт написана на нем
  • Stracraft 2 - Galaxy
Примеров тьма на самом деле
Doc #60 - 5 лет назад 0
Нет ненависти к ск2, есть ненависть к оверинжинирингу
prog #61 - 5 лет назад (отредактировано ) 0
Doc, мне кажется мы сейчас дискутируем о преимуществах теплого перед мягким и наоборот, когда на самом деле оба объекта зеленые.
Рассмотрим простейший пример - нанесение урона и необходимость его учитывать.
В случае с эффектами у нас есть базовый тип эффекта "нанесение урона" и, соответственно, класс DealDamageEffect, который знает все о нанесении урона - за какое яичко надо потянуть юнита, чтобы он понял, что его ударили, куда подуть AI, чтобы тот проснулся и отреагировал на издевательства над его юнитом, в зависимости от реализации, этот же класс может и влияние брони обсчитывать и много чего еще делать, а может и не делать сам, а только раздавать пинки другим классам.
В случае со скриптами, если мы, конечно, не хотим миллион раз дублировать один и тот же код, мы будем вызывать некий метод DealDamage из библиотеки скриптов или из API или дергать его в юните, а уже юнит будет делать все остальное.
Получаем примерно те-же тапки, только граблей вокруг одних раскидано больше, чем вокруг других т.к. зафейлить в написании скрипта чуть проще. Кроме того, в случае с эффектом в момент нанесения урона мы имеем доступ ко всей иерархии эффектов, которые к этому привели, а значит и кучу данных о том, как, куда, кем и зачем был нанесен этот урон, а из скрипта все эти данные нужно передавать вручную в параметрах (да, я осознаю что объем передаваемых данных одинаков, просто в одном случае их автоматическая передача подразумевается спецификацией, а во втором - нет). Еще можно было бы заикнуться о быстродействии за счет нативной реализации эффектов и кеширования цепочек, но скриптовые языки нынче шибко шустрые пошли, так что без реальных тестов это можно только предположить.
А теперь десерт - та спецификация, которой я буду следовать, если мне когда-нибудь еще раз удастся дойти до проекта, где подобная система будет необходима, подразумевает возможность использовать скрипты и эффекты одновременно. Правда напрямую скрипту не положено работать с игровыми объектами - только через другие эффекты и сравнительно небольшой список функций API, а на скрипт ложится больше задача по выполнению арифметических и логических вычислений и дерганию за усы нужных эффектов. При этом сам скрипт помещается внутрь эффекта соответствующего типа и его свободно могут использовать другие эффекты, не задумываясь о том, скрипт это или нативный эффект. Более того, редактор данных подхватывает константы из скрипта и позволяет менять их в будущем через инструменты для работы с данными, а также создавать клоны этого эффекта с другими числовыми значениями, не дублируя скрипт (в идеале еще можно добавить ручное управление линковкой между полями таблиц данных и константами в скрипте для тонкой настройки и возможность отделить клона от родителя, превратив в самостоятельный скрипт).
Напоследок хочу уточнить три вещи
  1. речь сейчас шла исключительно о взаимодействиях объектов, не затрагивая вопрос визуального отображения т.к. это отдельная тема
  2. все это применимо только к проектам, переходящим определенную планку по объему данных, связанных с взаимодействием между объектами - например, писать пакмена или тетрис с подобной системой в основе это оверкил, а вот для какой-нибудь доты, где данные регулярно пополняются новыми героями, а старые правятся в угоду балансу, это самое то.
  3. реализация визуального редактора данных в ск2 отстойна до такой степени, что голый xml часто предпочтительней, благо такую возможность разработчики предусмотрели, видимо их мапмекеры тоже от этого страдали когда кампанию делали.
Doc #62 - 5 лет назад (отредактировано ) 0
Блин да причем тут спецификации, на этой хрени просто будет неудобно разрабатывать. НИКОМУ не будет это удобнее, чем просто файл скрипта и файл данных, например. Напишу сотню спеллов, сделаю тысячу разных сущностей, в 90% случаев сущности не переиспользуются. Офигенно гибко, офигенно ненужно, никому не будет удобно постоянно создавать новые файлы, объекты, что угодно, пусть это супер чистое апи и здоровенская убергибкая архитектура от которой ни шагнуть ни вправо ни влево и на которой при этом можно сделать все, на реальном проекте это НЕУДОБНО. Это все, о чем я пытаюсь сказать.
Честно, уже не надеюсь, что меня кто-то поймет, в теории твоя штука выглядит оч здорово для любого неопытного программера.
alexprey #63 - 5 лет назад (отредактировано ) 0
Doc, я тебя прекрасно понимаю. Просто у каждого свои взгляды. Хотя сама идея prog'а мне оч даже нравится, но в реальном проекте, реально будет оч много костылей
prog #64 - 5 лет назад (отредактировано ) 0
Doc, важно отличать два этапа разработки - проэктирование и редактирование уже после завершения проектирования. Для каждого этапа нужен свой инструментарий и вот если рассмотреть, например, старкрафт2, то там хорошо сделан инструментарий для редактирования, но отвратнейше представлен инструментарий для проектирования, потому то мне и приходится лезть в чистый xml, как ты и говоришь - не удобно проектировать новые данные, когда есть только режим редактирования.
В идеале, инструментарий для проектирования полностью абстрагируется от системы, которая под ним работает - все нужные данные и связи между ними генерируются автоматически, а прямая работа с данными, выходящая за рамки "поменять 2 на 10" это удел особо тяжелых случаев, с которыми не справляется автоматическая генерация. И позволь тебя заверить, если случай тяжелый, то пилить его придется два дня, не зависимо от того, в данных это делается или в скриптах.

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

В зависимости от конкретных требований, можно добавить и заполнение числовых и строковых данных на этапе проектирования, а можно и вынести это на этап редактирования. Я бы, наверно, добавил возможность редактировать данные сразу на этапе проектирования, но сделал бы это не обязательным или отключаемым элементом.
Doc #65 - 5 лет назад 0
Это звучит круто, но это ТЕОРЕТИКА, потому что на ПРАКТИКЕ будет тысяча корнеркейзов, где чего-то где-то не хватит и тут уж либо костылим, либо забиваем. Ах, мы же сделали супергибко? Ну получай тогда охрененно громоздкий UI уровня трех блендеров, в котором нужно еще и разбираться тысячу лет. Так на это еще и время разработки нужно потратить!
Вот меня тут вы не переубедите. Я твою идею полностью понимаю и я много где её видел и для себя прокручивал в голове тыщу раз. Но это та самая идея, которая по моему стойкому мнению НЕ БУДЕТ РАБОТАТЬ. Ну никак! Только в голове и в теории.
prog #66 - 5 лет назад 0
Doc, ну так система гибкая не только в использовании, но и в разработке. Если возникает корнеркейс, то оценивается время на реализацию недостающего функционала, будь то новый тип эффекта, добавление параметров в существующий или допил модификатора в архитектурном приложении чтобы эффективнее использовать существующие эффекты. После оценки принимается решение - реализовать сейчас, отложить до следующей итерации или переубедить геймдизайнера, что нужно пойти другим путем.
Что касается UI, то он не может быть сложнее блендера - данные представляются в виде таблиц, как и в ск2, работа с геометрией отсутствует, работа со сложной анимацией в прямом смысле тоже, как и работа с материалами, рендерингом, параметрами сцены, камерами, светом - расставить примитивы, по таскать их по сцене, установить между ними связи, да вбить в таблицу данные - вот и все задачи архитектурного приложения.
Вот время разработки - да, его понадобится ощутимо больше, чем если ваять то-же самое, но на коленке. Так что эта технология скорее не для рядового инди разработчика, а для более-менее крупной студии, которая может себе позволить задержать очередной релиз ради разработки инструментария, который пригодится не только в текущем проекте.
DarkDes #67 - 5 лет назад 0
AlienShooter - почти вся игровая механика на скриптах О_О сам был в шоке когда нашел
World of Warcraft - вся логика интерфейса написана на lua, а так же пиратские сервера, большая часть логики написано тоже на нем же (не уверен)
Warcraft 3 - скрипты jass2, опять же большая часть логики для карт написана на нем
Stracraft 2 - Galaxy
Ого! Не знал этого. Возможно скрипты действительно мощный инструмент - ещё не пробовал на практике. Единственное, что делал дак это некий "язык разметки" для интерфейсов .. был удивлён, когда узнал, что на движке idTech3 аналогично сделано (только круче конечно).
В тему спеллов\скилов\эффектов. Визуальные редакторы таких данных - это конечно может быть удобно, но для внутренней разработки наверно будет достаточно и простых текстовых данных (кэп!). Ну вот например такая штука:
effect "burning" // регистрируем эффект "догорание"
{
    ... // тут различные параметры
}

skill "uber-shock" // типа регистрируем скилл
{
   target = AREA; // цель = какая-то местность
   radius = 5; 
   addEffect "burning", target_unit; // всем юнитам попавшим под этот спелл добавить эффект.
}
Это может выглядеть убого (возможно так и есть), но я бы сделал примерно так в реальном проекте. В подобных "скриптах" указал бы героев, их способности, модели и т.д., а в коде указал бы что нужно "выдернуть" ( хотя это не обязательно )
Doc #68 - 5 лет назад 0
DarkDes, сделай так, как пишешь, и когда обожжешься, поймешь мои слова. Нет смысла городить собственный скриптовый язык.
DarkDes #69 - 5 лет назад 0
Doc, ну это не скриптовый же язык, а форма заполнения данных )
Или предлагаешь все значения и всё всё всё хранить в самом коде? Не надоест билдить проект после каждого незначительного изменения в балансе?) Вообще внешние скрипты с логикой - это по мне лишнее, а вот различные данные хранить, да или тот же UI - это нормально, но это имхо конечно.
Doc #70 - 5 лет назад 0
Тогда расскажи ка что подразумевается под параметрами эффекта burning, а я тебе приведу примеры, для реализации которых эти параметры превратятся практически в скрипт, только корявый и неудобный.
И да, ребилда проекта не требуется, скрипты хранятся снаружи, для большинства не потребуется даже перезапуск приложения, при ченжах во время тестирования.
Данные хранить разумеется нужно отдельно.
DarkDes #71 - 5 лет назад 0
Тогда расскажи ка что подразумевается под параметрами эффекта burning
например, время горения, сколько урона наносит и сколько раз в секунду (или другой промежуток) этот самый урон наносится. Вообще базовую логику различных эффектов лучше хранить в супер-коде (основном коде программы).
И да, ребилда проекта не требуется, скрипты хранятся снаружи, для большинства не потребуется даже перезапуск приложения, при ченжах во время тестирования.
Это конечно круто, но надо ли ? Ладно там значения какие-нибудь, но когда работа с указателями различными (не в самом скрипте, просто скрипт дёргает такие штуки) - это проблема, хотя всё зависит от мощности скриптового движка.
Doc #72 - 5 лет назад (отредактировано ) 2
Оки. Хочу чтобы этот спелл можно было кастовать только на юнитов у которых меньше 100хп. И только на тех, рядом с которыми есть деревья, которые тоже загораются (это специальный интеракшн только с этим спеллом, сами деревья не больше чем декорации). И кастовать можно было только тогда (т.е. проверка должна быть еще на стадии нажатии кнопки, до выбора цели), когда рядом с кастером есть хотя бы 2 союзных юнита. Как это реализовать в параметрах и эффектах? Да и так чтобы если я еще что подобное захотел сделать, но с изменениями типа того, что юниты рядом должны быть вражеские или что еще, мне не пришлось бежать сломя голову в отдел прогеров движка. Мы же не хотим постоянно ребилдить проект, правда?
DarkDes #73 - 5 лет назад 0
Doc, окей, ты меня сделал.
можно вот всё это записать в супер-коде, а во внешнем файле хоть 2, хоть 8 юнитов чтоб было. 100хп, 200хп, всё зависит от движка жи.
Doc:
бежать сломя голову в отдел прогеров движка
Не знаю как там в современном инди, труЪ-инди и прочем на коленках, но думаю, что нет у них отдела прогеров с движком )
alexprey #74 - 5 лет назад 0
В тему спеллов\скилов\эффектов. Визуальные редакторы таких данных - это конечно может быть удобно, но для внутренней разработки наверно будет достаточно и простых текстовых данных (кэп!). Ну вот например такая штука:
почти похоже на JSON, но лучше используй JSON
Doc #75 - 5 лет назад (отредактировано ) 0
DarkDes, я говорю о том, что все это можно записать в двух внешних файлах, в одном скрипт, а в другом твои данные, которые скрипту подаются уже готовые. И никогда не придется ребилдить, скрипты они еще щас очень красивые в плане синтаксиса и много что прощающие, питон вон вообще как английский выглядит. И делается то, о чем я писал все вместе очень просто.
Тот же таргетинг допустим, определяется в скрипте какой-нибудь функцией типа
def isTargetable(Unit caster, Target target, SpellData data){
    if (target is GroundTarget)
        return false
    
    if (target is UnitTarget)
        return target.getUnit().isEnemy(caster) && Util.distance(target.getUnit(), caster) <= data.getCastRange()
    
}
Такой код и дурачок с базовыми знаниями англ языка поймет. А если для дурачков сделать красивый редактор с подсветкой синтаксиса (готовых либ тысяча в сети) и базовой проверкой самого скрипта (для этого достаточно просто вызывать функции из этого скрипта, банальные юнит-тесты), и код-темплейты, чтобы не приходилось начинать с нуля, то разберется и ребенок-дурачок, пожалуй.
И так с любыми условиями и запросами. Все уже сделано за Вас, честно.
Гспди, xgm, ну кто же делает word-wrapping в коде, ну?
-------------------
Если что, у меня все спеллы и юниты на скриптах. Единственное что сделано модульно, это периодические и временные действия выделены в отдельные переиспользуемые сущности с параметрами (т.к. игра пошаговая) и честно говоря, даже эти сущности надоедает создавать при разработке.
DarkDes #76 - 5 лет назад 0
Doc, возможно, скрипты действительно полезны - не узнаю пока сам не попробую на реальных (и правильных?) примерах )
Все уже сделано за Вас, честно.
Таки да, даже игры уже все сделаны :(
я понял, что речь о различных инструментах и либах
В тему внешних файлов - есть в юнити\С# быстрая и нормальная работа с внешними файлами? Как в Си++ например - всего 2-3 функции (открытие, закрытие, чтение). А то хочется некоторые данные выкинуть из С# кода.
Kozinaka #77 - 5 лет назад 0
DarkDes, скрипты действительно полезны. Я Lua использую, очень удобно специфическую логику уровней программировать - то, что нужно на конкретном уровне игры, а в движок заталкивать не хочется. Например на пятом уровне при нажатии кнопки "А" должен открыться люк "Б" и в соседней комнате появиться пять юнитов "Г".
DarkDes #78 - 5 лет назад 0
Kozinaka, надо будет почитать на эту тему. Вообще та идея игры типа ПвЕ-доты была рассчитана на несколько режимов\карт, поэтому скорее всего придётся эти самые скрипты использовать. Можешь посоветовать что-нибудь почитать\посмотреть по привязке lua к Си и как это работает ? (да можно это самому нагуглить, но вдруг знаешь хороший источник)
Kozinaka #79 - 5 лет назад 0
DarkDes, сходу не помню. Если гуглить, то вылазит много малюсеньких статеек, из которых ни одна не решает все проблемы. Поначалу сложно врубиться в то, как работает в Lua стек, через который с ним всё сообщение идёт. Давай, я лучше просто кину тебе классик, который у меня оборачивает всё взаимодействие с Lua и пример скрипта уровня на Lua. Как соберёшься врубиться в тему - дай знать. :)
DarkDes #80 - 5 лет назад 0
Kozinaka, реальные примеры - это всегда хорошо ) Врубаться в Lua можно хоть прямо сейчас ) Конечно медленно пойдёт изучение, но рано или поздно надо будет начать.