Итератор |
Дневник |
Сколько ж ограничений в UnrealScript!
Вот, оказывается свой итератор нельзя объявить. Функция-итератор должна быть нативной. Нативную функцию можно объявить только в нативном классе. А нативный класс просто нельзя объявлять...
Но я это обошел.
Создаем функцию, подобную итератору, например:
function RPGInvActor(class<Inventory> BaseClass, out Inventory Inv)
Она подобна итератору:
native final iterator function InventoryActors( class<Inventory> BaseClass, out Inventory Inv );
из класса InventoryManager. Единственное условие - в Inv должна вернуть None, если не нашла.
Теперь вместо foreach используем:
do
{
...
} until( Inv != None);
Естестсвенно RPGInvActor должна при каждом вызове возвращать следующее значение. Этого можно достичь введя переменную в классе, которая сохраняет предыдущее найденное значение:
var Inventory InvCash; //Для итератора
И использовать ее для нахождения следующего айтема в списке для поиска...
Для чего мне все это понадобилось? Для своей реализации инвентаря.
Инвентарь у Эпиков представляет собой обычный односвязный список. Естественно поиск в нем не быстр, естественно Инвентаря в нем много хранить нельзя (Эпики об этом прямо пишут). Более того, хоть это и возможно принципиально, но у Эпиков в инвентарь нельзя добавлять одинаковые предметы.
Ну а в ролевых играх в рюкзаке у героя очень много предметов, очень много одинаковых...
Как это реализовать? - сделать свою структуру для инвентаря. Я сделал комбинированную.
Есть динамический массив, элементы которого - первые элементы в связанных списках. Тип элемента в массиве повторяться не может. А вот в списке, на который указывает элемент массива как раз наоборот - все элементы одного типа.
Метки: rpg рпг gamedev удк udk |
Тултипсы |
Дневник |
Сделал тултипсы к объектам. Появляются, когда ГГ смотрит на объект. Работают на всех типах объектов.
Работы еще много - главное на данный момент вывести его не где попало а чуть выше объекта. К сожалению разные типы имеют разные переменные высоты. К тому же у скелеталмешей почему-то боундинг в одном измерении значительно больше самого предмета... Вроде я алгорите придумал не зависящий от всего этого,
но нужно проверять еще...
Метки: gamedev rpg udk удк |
Без заголовка |
Дневник |
Взаимодействие AS и US.
1. Как вызвать функцию US из AS.
В том кадре в котором это надо (если надо в нескольких кадрах, то во всех) в начале скрипта вставляем строку:
import flash.external.ExternalInterface;
Тем самым мы подключаем библиотеку для работы с внешними приложениями.
Сам вызов производится так:
ExternalInterface.call("OnPressNewGameButton");
В кавычках - имя функции, которая есть в US.
Например при нажатии на кнопку AS "New Game" будет вызываться функция US "OnPressNewGameButton", которая загружает начальный уровень игры консольной командой:
function OnPressNewGameButton(GFxClikWidget.EventData ev)
{
PC.Player.Actor.ConsoleCommand("open Terra1", false);
}
Ну, естественно в AS нужно на кнопку "New Game" повесить слушателя и связать его с функцией...
"Полный" код AS:
import gfx.controls.ButtonGroup;
import flash.external.ExternalInterface;
function SendNewGameCommand() {
ExternalInterface.call("OnPressNewGameButton");
}
btn_NewGame.addEventListener("click", this, "SendNewGameCommand");
stop();
Аналогично добавляем для остальных кнопок меню...
2. Как передать данные из AS в US.
Для начала добавляем на главное меню слой, в котором будем хранить все переменные.
Добавляем в первый кадр скрипт с переменными. Опции лучше всего сделать так:
if (!options) {
var options:Object = {};
}
var defScreen:Number = 2;
var defBrightness:Number = 5;
var defContrast:Number = 5;
var defGamma:Number = 5;
var defSpeak:Number = 5;
var defMusik:Number = 5;
var defSFX:Number = 5;
var defAmbient:Number = 5;
options.selectedScreen = (options.selectedScreen) ? options.selectedScreen : defaultScreen;
options.Brightness = (options.Brightness) ? options.Brightness : defBrightness;
options.Contrast = (options.Contrast) ? options.Contrast : defContrast;
options.Gamma = (options.Gamma) ? options.Gamma : defGamma;
options.Speak = (options.Speak) ? options.Speak : defSpeak;
options.Musik = (options.Musik) ? options.Musik : defMusik;
options.SFX = (options.SFX) ? options.SFX : defSFX;
options.Ambient = (options.Ambient) ? options.Ambient : defAmbient;
тут мы сначала определили переменную - массив объектов (если ее еще не было). Далее заполнили массив начальными значениями (опять таки если их не было, то дефолтными)...
Выбор разрешения экрана у меня - это степпер CLIK-а, яркость и все остальное - слайдеры.
В кадре где выводится меня выбора опций в акциях добавляем в скрипт:
stp_Screen.dataProvider = ["800*600", "1024*768", "1280*768", "1280*1024"];
stp_Screen.selectedIndex = (options.selectedScreen) ? options.selectedScreen : defScreen;
sld_Brightness.value = (options.Brightness) ? options.Brightness : defBrightness;
sld_Contrast.value = (options.Contrast) ? options.Contrast : defContrast;
sld_Gamma.value = (options.Gamma) ? options.Gamma : defGamma;
Здесь определяем набор разрешений экрана (текст, который будет выводиться на степпере) и задаем начальные значения.
Далее на каждую опцию соответствующую функцию:
function SendBrightness() {
options.Brightness = sld_Brightness.value;
ExternalInterface.call("OnChangeGraphic");
}
Меняем данные, которые может получить US и вызываем функцию US, которая собственно получает эти данные.
Ну и слушатели для каждой опции:
sld_Brightness.addEventListener("change", this, "SendBrightness");
Разрешение экрана лучше не менять на лету, а менять только при выходе из меню. Т.е. для него функция слегка другая:
function SendChangeScreen() {
options.selectedScreen = stp_Screen.selectedIndex;
}
Нужно еще две функции:
function SetDefault() {
stp_Screen.selectedIndex = defScreen;
-----
options.Gamma = defGamma;
ExternalInterface.call("OnChangeGraphic");
}
Установка опций по умолчанию. И:
function ReturnToOptionsMenu2() {
options.selectedScreen = stp_Screen.selectedIndex;
options.Brightness = sld_Brightness.value + 0.001;
options.Contrast = sld_Contrast.value + 0.001;
options.Gamma = sld_Gamma.value + 0.001;
gotoAndPlay("optionsmenu");
}
Возврат в главное меню. Тут мы просто устанавливаем данные для получения в US и переходим в главное меню... Почему прибавляем + 0.001 - не помню уже, но оно надо...
Чтобы в конце US мог получить эти данные при выходе из меню нужно вызвать спецфункцию:
import flash.external.ExternalInterface;
ExternalInterface.call("OnCloseAnimationComplete");
stop();
Это в последнем кадре меню...
Теперь все это нужно в US получить...
Делаем функции:
function OnChangeGraphic()
{
Brightness = 2.f - MainMC.outer.GetVariableNumber("options.Brightness") / 5.f;
Contrast = 1.05f - MainMC.outer.GetVariableNumber("options.Contrast") / 10.f;
Gamma = MainMC.outer.GetVariableNumber("options.Gamma") / 10.f;
ChangeDisplayOption();
}
function ChangeDisplayOption()
{
local Player PP;
PP = GetLP();
PP.PP_HighlightsMultiplier = PC.PostProcessPresets[0].Highlights * Contrast * Brightness * 2.f;
PP.PP_MidTonesMultiplier = PC.PostProcessPresets[0].MidTones * Brightness;
PP.PP_ShadowsMultiplier = PC.PostProcessPresets[0].Shadows * ( 1.f - Contrast ) * Brightness * 2.f;
PC.SetGamma(Gamma);
}
.outer.GetVariableNumber - получает число от AS. MainMC - это GFxObject, который мы получили в функции Start так:
MainMC = GetVariableObject("_root");
Яркость воздействует сразу на все тона картинки, контраст только на светлые тона и тени, увеличивая "расстояние" между ними.
Для громкости:
function OnChangeAudio()
{
SoundSpeak = MainMC.outer.GetVariableNumber("options.Speak") / 10.f;
SoundMusik = MainMC.outer.GetVariableNumber("options.Musik") / 10.f;
SoundSFX = MainMC.outer.GetVariableNumber("options.SFX") / 10.f;
SoundAmbient = MainMC.outer.GetVariableNumber("options.Ambient") / 10.f;
ChangeAudioOption();
}
function ChangeAudioOption()
{
PC.SetAudioGroupVolume( 'SFX', SoundSFX );
PC.SetAudioGroupVolume( 'Dialog', SoundSpeak );
PC.SetAudioGroupVolume( 'Announcer', SoundSpeak );
PC.SetAudioGroupVolume( 'Music', SoundMusik );
PC.SetAudioGroupVolume( 'Ambient', SoundAmbient );
}
/ 10.f - т.к. значения слайдера меняются от 0 до 10, а в US от 0 до 1.
PC - это UTPlayerController :
var UTPlayerController PC;
function bool Start()
{
...
PC = UTPlayerController(GetPC());
...
}
Ну и разрешение экрана:
function OnCloseAnimationComplete()
{
ScreenRes = MainMC.outer.GetVariableNumber("options.selectedScreen");
switch(ScreenRes)
{
case 0:
UT_ConsoleCommand("setres 800x600x32xw", true);
break;
case 1:
UT_ConsoleCommand("setres 1024x768x32xw", true);
break;
case 2:
UT_ConsoleCommand("setres 1280x768x32xw", true);
break;
case 3:
UT_ConsoleCommand("setres 1280x1024x32xw", true);
break;
default:
break;
}
UTGFxHudWrapper(GetPC().MyHUD).CompletePauseMenuClose();
}
Передать в AS данные аналогично, только SetVariableNumber. Подробно пока писать не буду - закопался в DataProvider... Если кто видел нормальные уроки/описания по нему - укажите плиз...
Также еще один вопрос - по звукам в GFx меню. Как привязать звуки к нему я нашел:
Нужно просто в defaultproperties указать:
SoundThemes(0)=(ThemeName=default,Theme=UISoundTheme'UDKFrontEnd.Sound.SoundTheme')
Тут я использовал стандартные звуки УДК, но можно создать свою тему.
3. Где все это прописывать
В UTGFxHudWrapper есть функция TogglePauseMenu - там прописано создание нового объекта класса меню
PauseMenuMovie = new class'GFxUI_PauseMenu';
И установка его свойств. Там напрямую прописан клип, который вызывается по команде ShowMenu, забинденной на клавишу Esc.
Наследуешься от этого класса, прописываешь свой клип (Ну или просто в нем исправляешь на свой). После чего он будет вызываться при нажатии Esc. Ну а зная все это можно вызвать клип и любом другом случае...
Соответственно там прекрасно видно как обращаться с классом GFxUI_PauseMenu...
Вот в этом самом GFxUI_PauseMenu и прописаны все функции взаимодействия с AS, про которые я писал.
А вообще класс GFxMoviePlayer очень хорошо описан тут:
UDN
Там же ниже написано как вызывать функции AS из US и наоборот...
А вот как заставить УДК в меню воспроизводить музыку/ амбиент звуки/речь. Я найти не могу. Простое добавление:
PC.ClientPlaySound(MenuMusic);
в лучшем случае включает музыку после выхода из меню. В самом меню музыки нет. Поэтому меняешь громкость музыки "на глазок". Она меняется, но насколько можно узнать, только выйдя из меню. Это ненормально!
На УДН по ссылке выше есть код для вызова звука из AS:
if( _global.gfxProcessSound )
{
_global.gfxProcessSound(this, "SoundThemeName", "SoundEventName");
}
Однако у меня это не работает - звук начинает проигрываться только после выхода из меню (GFxMoviePlayer)...
Кто сможет решить эту проблему?!?
Метки: udk gamedev |
Терра, карты высот... |
Дневник |
В общем перенес я карту высот из Макса в УДК. Есть такой урок на unreal-level. Там все ОК, только не работает...
Там предлагают изменять оси развертки приналожении материала: UV, VW, UW. Так вот это у меня не работает и никогда не работало. Обходится достаточно просто. Накладывются две развертки в двух разных каналах. В 1-м канале как указано в уроке - Planar по z. Это для Render to Texture. Во 2-м канале Planar по y - это для наложения материала. В материале не забыть указать именно второй канал развертки.
Все остальное по уроку...
Только зря я это делал. В УДК все-равно огромное количество работы с полученной террой, т.к. вид у нее просто жуткий...
Поэтому я плюнул - взял меш терры, про который писал в предыдущей записи и подогнал терру УДК по ней. Все отлично получилось. Уже начал расставлять домики. Картинки на выложу - дома оставил
Возникла пара вопросов.
Во первых. Все объекты, перегнанные из Готики приблизительно в 2 раза больше чем надо (ориентируюсь по дверным проемам и стандартному персу УДК). Так вот вопрос - перс у нас все-равно будет другой - может лучше его подогнать под размеры остальных объектов, а не уменьшать все расставляемое на уровне в 2 раза?...
Во вторых. Не нравится мне расположение Ардеи. Ну что это задеревня рыбаков, которая находится за километр от моря? Она должна быть намного ближе к морю. Может переместить ее? Тогда куда поместить Лестера?
Метки: gamedev Gothica rpg udk |
Терра |
Дневник |
Перенес я в УДК утес на котором стоит Ардея. Он по полигонажу не такой и большой - всего 45к трисов. Правда по размерам великоват. Вот он в Максе:
Там где голубые дырки стоят дом Ардеи.
Так вот УДК при просчете света на нем повесился...
Буду думать как это перенести в карту высот - может с родной террой УДК нормально работать будет...
Метки: rpg gothic gamedev udk |
Глюки с развертками |
Дневник |
В процессе работы выявились некоторые глюки с развертками.
УДК обязательно нужно или в 0-м слое UVW нормальную развертку, помещающуюся в квадрат 0-1 и без взаимных наложений частей, или специальный слой (обычно 1-й) с такими параметрами.
В Готике на всех предметах аж по 4 развертки, и ни одна не подходит под нужные параметры. Поэтому пришлось добавлять пункт 15 в сообщении ниже.
Однако из-за этого пункта на некоторых объектах появляется глюк в УДК - дополнительный материал, которго вроде нет в Максе. Т.е., например в Максе у нас на объекте мультиматериал из 2-х материалов. Переносим в УДК и видим там не 2, а 3 материала. Самое интересное, что это происходит не со всеми предметами. Убрать этот лишний материал вообще почти невозможно.
Я долго думал из-за чего такое возникает и обнаружил, что из-за UVWMapping. Вот буквально сейчас, наконец-то увидел этот лишний материал в Максе:
UnwrapChecker не должно быть. Его я не накладывал. Появляется он при наложении UVWMapping. Исчезает при сворачивании стека.
Сейчас попробую импортировать в УДК - отпишусь...
А вот и пофиг - после сворачивания стека все равно в УДК 3 материала!
Единственное решение - полностью создать объект с нуля. Слава богу таких объектов мало. У меня их пока 3 из сотни...
Метки: gothic gamedev udk |
Работа идет |
Дневник |
Несмотря на некоторые выплывшие в процессе переноса тонкости работа продолжается. Всего перенесено 6 домов и 84 предмета. У всех настроены коллизии. Частично предметы не из Готики (сделанные мной).
Какие выявились тонкости:
Если есть на объекте прозрачность, то по краям могут появиться нежелательные полоски - артефакты. Они убираются установкой в текстуре не TA_Wrap, а TA_Clamp. Тогда текстура обрезается по границам квадрата 0-1, а не повторяется за его пределами. При этом необходимо, чтобы UV-развертка лежала в пределах этого квадрата. А в Готике она расположена "как левая нога захочет". Приходится слегка переделывать развертку.
На некоторых объектах почему-то риппер взял развертку явно со второго канала, где обычно лежит LightMap. У них приходится полностью переделывать развертку.
У дома на картинке ниже балки развернуты тяп-ляп. Просто наложен UVWMap с Box-ом. А балки сломанные. На изломах текстура сильно потянута получается. В игре, возможно, это незаметно, но мне режет глаза - пришлось переделывать...
Метки: 3ds gothic rpg udk |
Как переносим - 2... |
Дневник |
Некоторые тонкости...
Все это, если на объекте один материал. Если же на объекте их несколько, то Риппер их разбивает на подобъекты по количеству материалов. Для каждого подобъекта проделываем все манипуляции с 1 по 14. Далее:
1. Выделяем все полигоны подобъекта. Назначаем id материала 2. У следующего 3 и т.д. У нас должны получится куча объектов с id от 1 до n.
2. Выбираем первый. Attach List. Выбираем все подобъекты. Соглашаемся с установками по умолчанию. (Match Material id to Material, Condense Material and Ids)
Далее делаем все начиная с 15 пункта...
Метки: rpg gothic gamedev udk |
Как переносим? |
Дневник |
У Готики 3 так и не появилось модкита. Поэтому оттуда можно нормально выдрать только текстуры. Все меши приходится выдирать с использованием 3dRipper-а. Анимации выдрать вообще нельзя.
Итак - последовательность действий.
1. Запускаем через 3dripper готику. Приближаемся к интересующему нас предмету. Нажимаем F12. Рип сохраняется, после чего игра вылетает :(
Повторяем для всех нужных объектов...
2. Запускаем Макс. Находим рип. Загружаем. Удаляем все ненужное (прям как скульптор). Остается предмет, на котором невесть какие материалы.
3. Пипеткой берем материал с предмета. Это Multi/Sub-object материал. Ищем в нем подходящий материал для диффуза и нормалки. Они раскиданы по разным подматериалам. Обычно 3-4 сверху. Изредка бывает еще один подматериал для спекуляра.
4. Ищем в рипах текстур нужные текстуры диффуза и нормала - переносим их в свою папку контента игры.
5. С помощью компрессонатора от АТИ преобразуем их в tga, т.к. dds УДК не понимает. Если фотошоп понимает dds, то можно не преобразовывать, а просто в фотошопе сохранять в tga. У меня фотошоп 64х битный, и плагин от Нвидиа не подходит, поэтому приходится сначала преобразовывать в tga...
6. Если нашли спекулар - объединяем его с диффузом в фотошопе. Засовываем его в альфа канал.
7. В готике текстуры нормалей "упакованные". Отличие видно сразу - они зеленые, а не синие. Это, как я понимаю сделано для уменьшения занимаемого объема. Чтобы преобразовать их в нормальный вид переносим канал альфа в канал красного, а синий канал заливаем белым цветом. Если хочется, можно увеличить рельеф копированием слоя с наложением "перекрытие"...
8. В максе преобразуем предмет в EditPoly (Мне просто с ним удобнее работать). Велдим все вершины с Threshhold 0.001, чтобы получить нормальный меш.
9. Переносим Pivot в центр объекта.
10. Выравниваем объект по координатным осям.
11. Переносим его в начало координат.
12. Utils - ResetXform - Reset Selected. Сворачиваем стек модификаторов.
13. Еще раз переносим Pivot в центр объекта. И тут же сдвигаем в "точку крепления". Обычно это низ предмета. Так проще будет в УДК выставить его по вертикали.
14. Настраиваем группы сглаживания. Обычно достаточно нажать "AutoSmooth". Но нужно проконтролировать как лучше выглядит и, возможно оставить одну группу сглаживания...
15. Накладываем Unwrap UVW - меняем MapCannel на 2 - Edit. Выделяем все полигоны - Mapping - Flatten Mapping - OK. Это нужно для расчета карт освещенности в УДК.
16. Делаем простой объект, который заключает в себя наш. Чем проще, тем лучше. Что нужно избегать? - открытых ребер. Проверить можно модификатором STL Check. Этот простой объект будет коллизией. Для простых предметов - ящиков и т.п. его можно не делать. Называем этот объект UCX_имяпредмета. Например предмет - якорь с именем Anchor, тогда имя коллизии UCX_Anchor.
17. Сохраняем максовский файл на всякий случай, вдруг что переделать нужно будет.
18. Экспортируем предмет в ASE. Галочки должны стоять у:
Mesh Definition, Materials, Geometric, Mesh Normals, Mapping Coordinates
19. Заходим в УДК. Импортируем подготовленные текстуры. Импортируем меш.
20. Из текстур делаем материал. Накладываем материал на меш.
Наслаждаемся...
Метки: rpg gothic gamedev udk |
UDK |
Дневник |
Метки: rpg gothic gamedev udk |
Страницы: | [1] |