XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Желтая пресса: обучающие статьи
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

 
ZeToX2007

offline
Опыт: 7,009
Активность:
Работа с типом unit
Работа с типом unit

Введение


В этой статье Вы возможно не увидите ничего нового, но тут будут описаны методы работы с типом боевая единица – сохранения любых данных, отслеживание урона, работа со снарядами и другое…

Часть первая



Первое с чего начнем это хранения данных, у юнита есть весьма полезные функции – SetUnitUserData,GetUnitUserData, она может хранить integer. Прекрасно, часто бывает, что нам нужно прикрепить несколько данных… и для реализации нам потребуются несколько массивов и SetUnitUserData, она будет выступать в роли ключа в наших массивах.

Для удобство сначало сделаем так:

Код:
define GetIdUnit(u) ={GetUnitUserData(u)}


На cJass define это как бы автозамена , после компиляции все замениться на GetUnitUserData(u)

Прекрасно, следующая задача – это сделать так, чтобы у каждого юнита были разные значения, для этого нам понадобиться 1 массив и 2 переменные типа integer.

Код:
integer array Mass
integer I = 0
integer F = 0


В cJass, при объявление переменных не в функциях они будут являться глобальные, иначе локальными.

Пусть: define void = nothing

Код:
void AddUNIT(unit u){
    integer i = F
    if (F==0){
        I=I+1
        i=I}
    else{i=Mass[F]}
    Mass[i]=-1
    SetUnitUserData(u,i)
}


Кто не знает ещё cJass смотреть сюда: (после компиляции будет именно так)

Код:
function AddUNIT takes unit u returns nothing
    local integer i = F
    if (F==0) then
    set  I = I + 1
    set  i = I
    else
    set i = Mass[F]
    endif

     set Mass[i]=-1
    call SetUnitUserData(u,i)
endfunction


Эта функция будет давать юниту уникальный номер и сохранять его. Это конечно замечательно но массив в варике рассчитан на 8192 элементов, поэтому придётся нам убирать умерших юнитов, и давать новым юнитам старые номера.

Код:
void RemoveUNIT(unit u){
        integer i = GetIdUnit (u)
        RemoveUnit(u)
        Mass[i]=F
        F=i
    }


Довольно простая функция, выводит юнита из игры и освобождает номер… эту функцию мы вскоре будет дополнять…

и так объявив несколько массивов мы уже можем хранить данные и читать их, это самая быстрая система…
пример:

void TEST(){
integer i = GetIdUnit(GetTriggerUnit())
….
MyArray[i] = 5
MyArray2[i] = 10
….
}

Отлично, но тут ещё возникают ряд проблем, например как присвоить id более удобным способом ? тут все просто, при инициализации мы выбираем каждого юнита и взываем функцию AddUNIT, а так же создадим функцию – альтернатива CreateUnit.

Код:
unit CreateUNIT(player p,integer id,real x,real y, real f){
       integer i = F
       bj_lastCreatedUnit = CreateUnit(p,id,x,y,f)
        if (F==0){
           I=I+1
           i=I}
        else{i=Mass[F]}
        Mass[i]=-1
        SetUnitUserData (bj_lastCreatedUnit,i)
        return bj_lastCreatedUnit
     }


И так прекрасно ! теперь созданым юнитам будут прикрепляться номера.

Для удобство оформим это виде библиотеки




Код:
library UnitAll{
    private  integer array Mass
    private  integer I = 0
    private  integer F = 0
    
    void AddUNIT(unit u){
    integer i = F
    if (F==0){
        I=I+1
        i=I}
    else{i=Mass[F]}
    Mass[i]=-1
    SetUnitUserData(u,i)
        }
    

    unit CreateUNIT(player p,integer id,real x,real y, real f){
       integer i = F
       bj_lastCreatedUnit = CreateUnit(p,id,x,y,f)
       // Ваши действия

       //

        if (F==0){
           I=I+1
           i=I}
        else{i=Mass[F]}
        Mass[i]=-1
        SetUnitUserData (bj_lastCreatedUnit,i)
       
        return bj_lastCreatedUnit
    }
    
    void RemoveUNIT(unit u){
        integer i = GetUnitUserData(u)
        // Ваши действия
        //Обнуление
        UnitAll_Data1[i] = 0
        UnitAll_Data2[i] = 0
        
        UnitAll_Ax[i] = 0
        UnitAll_Ay[i] = 0
        UnitAll_Az[i] = 0
        //
        RemoveUnit(u)
        Mass[i]=F
        F=i
    }
    
    //Ваши данные
  public  real array Ax,Ay,Az
  public  integer array Data1,Data2
            
}


После удаления юнита важно обнулить все массивы, где это требуется.

Часть вторая




Приступим ко второй части… мы можем условно разделить юнитов на: Обычные боевые единицы и снаряды. У них конечно будут разные прикрепленные к ним данные и свойства… Для начало можно копирнуть библиотеку и переписать её аккуратно это основа. Для них будут разные номера и массивы.

Создадим две группы для каждой библиотеке

Код:
group UnitAll = CreateGroup()
    group SNAR = CreateGroup()


Мы так же будет добавлять юнитов и снарядов при создании и убирать при удалении функции дополняться:


Код:
void AddUNIT(unit u){
    integer i = F
    if (F==0){
        I=I+1
        i=I}
    else{i=Mass[F]}
    Mass[i]=-1    
    GroupAddUnit(UnitAll,u)
    SetUnitUserData(u,i)
        }


    unit CreateUNIT(player p,integer id,real x,real y, real f){
       integer i = F
       bj_lastCreatedUnit = CreateUnit(p,id,x,y,f)
       // Ваши действия

       //

        if (F==0){
           I=I+1
           i=I}
        else{i=Mass[F]}
        Mass[i]=-1
        SetUnitUserData (bj_lastCreatedUnit,i)
       GroupAddUnit(UnitAll,u)
        return bj_lastCreatedUnit
    }
    
    void RemoveUNIT(unit u){
        integer i = GetUnitUserData(u)
        // Ваши действия    
 
        GroupRemoveUnit(UnitAll,u)
        //Обнуление
        UnitAll_Data1[i] = 0
        UnitAll_Data2[i] = 0
        
        UnitAll_Ax[i] = 0
        UnitAll_Ay[i] = 0
        UnitAll_Az[i] = 0
        //
        RemoveUnit(u)
        Mass[i]=F
        F=i
    }


Тоже самое проделаем для библиотеки снарядов…

В этих группах будет находиться Все юниты и снаряды нам будет удобно обращаться к группам для реализации своих целей. так же добавим в библиотеки то что нам надо…

Например, чтобы юнит мог перемещаться по оси Z, так же отсаживание урона –
Допустим у нас есть триггер, где нам нужно получить урон и юнита, мы так же добавим в наши функции – TriggerRegisterUnitEvent. Для данной функции… для библиотеки снарядов это необязательно, зато добавим другое, например чтобы снаряд нельзя было выделить (москиты).


Заключение



Заключение: придерживаясь этой системы, мы можем наиболее быстро обращаться к данным юнита, так же отслеживать повреждения, работать со снарядами, с группами и разделять условно Юнитов на несколько типов, у которых будут свои свойства.
Прикрепленные файлы
Тип файла: w3x UNITs.w3x (21.6 Кбайт, 28 просмотров )

Отредактировано ZeToX2007, 20.09.2009 в 20:19.
Старый 14.09.2009, 19:01
NCrashed

offline
Опыт: 13,553
Активность:
  1. cJass, в данном случае он не очень нужен, но все же это первая статья, которая его использует. Поподробней опиши что на что заменяется, где пишется возвращаемый тип функции, что значит void, и т.п. Человеку, который си видел несколько раз в жизни будет непонятно (ко мне не относится ^^)
  2. Рассмотрена реализация структуры системы хранении информации о юнитах, а вот конкретных советов нету (например отражение снаряда от клиффа)
  3. Работа с типом unit не заканчивается на снарядах, расскажи про нативки (точнее об экзотическом примении их на практике). Например, не все знают про полезную функцию SetUnitPath.
Старый 20.09.2009, 20:15
ZeToX2007

offline
Опыт: 7,009
Активность:
Цитата:
Сообщение от NCrashed
cJass, в данном случае он не очень нужен, но все же это первая статья, которая его использует. Поподробней опиши что на что заменяется, где пишется возвращаемый тип функции, что значит void, и т.п. Человеку, который си видел несколько раз в жизни будет непонятно (ко мне не относится ^^)

Ок

Статья будет доработана, будут примеры использования, будет рассмотренна функция SetUnitPath, будет... только фиг знает когда всё это будет ).
Старый 20.09.2009, 20:34
adic3x

offline
Опыт: 108,439
Активность:
define GetIdUnit(u) ={GetUnitUserData(u)}
На cJass define это как бы автозамена , после компиляции все замениться на GetUnitUserData(u)
как бы вопрос - как бы зачем? т.е. это ничего не дает, тем более что может запутать, т.к. кто то сторонний при чтении кода куда лучше будет понимать вызов нативки
I=I+1
i=I
i = ++I
+ мне очень не нравиться имена переменных в этом примере, они могут провоцировать ошибки
Работа с типом unit
некоректное название - в тако случае стоило бы описывать нативки например. скорее это работа с данными
Старый 20.09.2009, 20:48
ScorpioT1000
Работаем
online
Опыт: отключен
вобщем, шлак полный. даже не постарался ошибки русского языка исправить.
На cJass define это как бы автозамена , после компиляции все замениться
угарно вобще)
Старый 20.09.2009, 20:51
ZeToX2007

offline
Опыт: 7,009
Активность:
Цитата:
Сообщение от ScorpioT1000
. даже не постарался ошибки русского языка исправить.

где ошибки ?О_о ?
Старый 20.09.2009, 20:57
Hellfim
Новичок
offline
Опыт: 79,707
Активность:
Автор кран. Серьезно. Это не оскорбление. Просто кран.
Если используешь сЖасс, то хоть используй все богатство возможностей, тот же перехват нативок...
+Названия переменных ниачомные, если тебе все понятно, то оставляй такую статью при себе и читай её, когда что-то забудешь.
+Весь твой код можно записать так:
library UnitData {
	
	private integer emptyCellIndex=0
	private unit array addedUnit

	 /*Массивы и
	|прочая хренотень
	|которая понадобится
	 \*пользователю*/
	
	private void addUnit (unit whichUnit/*, другие элементы, определяемые пользователем*/) {
		addedUnit[emptyCellIndex]=whichUnit
		/* записывание
		| других элементов,
		| определенных
		 \* пользователем */
		SetUnitUserData(whichUnit,emptyCellIndex++)
	}

	private void freeCell (unit whichUnit) {
		int overwritingIndex=GetUnitUserData(whichUnit)
		addedUnit[overwritingIndex]=addedUnit[--emtyCellIndex]
		 /* перезаписывание
		| других элементов,
		| определенных
		 \* пользователем */
		SetUnitUserData(addedUnit[overwritingIndex])
	}
}

Отредактировано Hellfim, 20.09.2009 в 23:15.
Старый 20.09.2009, 21:19
Van Damm
wait... what?
offline
Опыт: 22,268
Активность:
Hellfim, фейл, надо так:
newUnit=Create##Unit(p,id,x,y,angle)
Старый 21.09.2009, 01:02
Hellfim
Новичок
offline
Опыт: 79,707
Активность:
Van_Damm, нет, не фейл, или ты считаешь, что в систему надо вностить сразу при создании?
Бтв, у меня сначала так и было, но потом я подумал о том, что написано выше =)
Старый 21.09.2009, 15:41
Van Damm
wait... what?
offline
Опыт: 22,268
Активность:
Hellfim, фейл-фейл, у тебя бесконечный реплейс получался
Офк сейчас ты уже код изменил =)
Старый 21.09.2009, 19:17
ZeToX2007

offline
Опыт: 7,009
Активность:
Hellfim, Один вапрос, работать то так будет ? 0_0. когда SetUnitUserData принимала 1 аргумент? ну это пустики, способ не очень, так как мы при создание, и уничтожении юнита перезаписываем множество массивов. так же "айдишники юнитов" меняются это тоже не красиво и может повлечь за собой нежелательный результат. тут нет выйгрыша ни в скорости ни в логике,сорри это калл...
Старый 21.09.2009, 19:30
Hellfim
Новичок
offline
Опыт: 79,707
Активность:
Van_Damm
Отредактировано Hellfim, 20.09.2009 в 23:15.
кк, я до сих пор хз, как с помщью возможностей см "незаметно" редактировать пост -.-
ZeToX2007, да, с юзердата ошибся, ибо спешил =)
» исправленый вариант
	private void freeCell (unit whichUnit) {
		int overwritingIndex=GetUnitUserData(whichUnit)
		addedUnit[overwritingIndex]=addedUnit[--emtyCellIndex]
		 /* перезаписывание
		| других элементов,
		| определенных
		 \* пользователем */
		SetUnitUserData(addedUnit[overwritingIndex],overwritingIndex)
	}
при создание, и уничтожении юнита перезаписываем множество массивов.
Это в любом способе, даже в твоем, кол-во записываемых/перезаписываемых массивов зависит от кол-ва данных, которых польхователь хочет сохранить.
так же "айдишники юнитов" меняются это тоже не красиво
А у тебя в системе юнит вносится только при создании и убирается только при смерти. А если например мне на 5 секунд надо внести его в систему, а потом убрать? Юзердата юнитов меняется и это очень "красиво".
может повлечь за собой нежелательный результат.
Какой?
тут нет выйгрыша ни в скорости ни в логике
Есть и в первом и во втором.
Старый 22.09.2009, 14:24
ZeToX2007

offline
Опыт: 7,009
Активность:
Цитата:
Сообщение от Hellfim
Какой?

компактное хранение информации.

Цитата:
Сообщение от Hellfim
Это в любом способе, даже в твоем, кол-во записываемых/перезаписываемых массивов зависит от кол-ва данных, которых польхователь хочет сохранить.


У меня обнуляется только 1 раз, когда юнит умирает, у тебя и при создания и уничтожения.

Цитата:
Сообщение от Hellfim
Есть и в первом и во втором.


Собственно ответил выше.

Цитата:
Сообщение от Hellfim
А у тебя в системе юнит вносится только при создании и убирается только при смерти. А если например мне на 5 секунд надо внести его в систему, а потом убрать? Юзердата юнитов меняется и это очень "красиво".

непонятно что ты имел ввиду.

ZeToX2007 добавил:
Hellfim, а пример нежелательного результата:

Допустим мы дожны через некоторое время, что либо изменить (в массивах) прикрепив к таймеру, "ключ" юнита, по истечению таймера должно, что либо измениться в нужных массивах, а что будет если какого либо юнита убили и номер последнего переписался ?
Старый 23.09.2009, 16:31
Hellfim
Новичок
offline
Опыт: 79,707
Активность:
У меня обнуляется только 1 раз, когда юнит умирает, у тебя и при создания и уничтожения.
И еще раз: "а если мне не нужно заносить юнита в систему сразу при создании?"
Допустим мы дожны через некоторое время, что либо изменить (в массивах) прикрепив к таймеру, "ключ" юнита, по истечению таймера должно, что либо измениться в нужных массивах, а что будет если какого либо юнита убили и номер последнего переписался ?
Как именно ты собрался прикреплять?
Старый 23.09.2009, 16:37
ZeToX2007

offline
Опыт: 7,009
Активность:
Цитата:
Сообщение от Hellfim
И еще раз: "а если мне не нужно заносить юнита в систему сразу при создании?"

объясни в каких случаях тебе не нужно заносить в систему юнита ? и если не надо - не заноси сразу, ничего все равно не измениться )

Если в какой либо фунции вызвана GetUnitUserData и она присвоена какой либо переменной, то не имеет смысла прикреплять юнита к таймеру, а лучше это число. если меняем такие характеристики как Хп и другие, прикрепляем юнита, а потом получаем его "айдишник" в группе. но для 1 юнита это не играет роль, а если их 30 ? то для эффективного переноса удобней работать с int и с двухмерными массивами интежеров, чем с юнитами. выйгрыш минимальный кажется, а если таймер с периодом 0.05с и ниже ? и надо исходить из удобства...
Старый 23.09.2009, 23:10

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 20:48.