Раздел:
Триггеры и объекты
Содержание:
Структуры привносят в Jass элементы объектно-ориентированного программирования (ООП). Они являются удобными объектами для хранения каких либо данных, не затрагивая хеш-таблицу, которая является сама по себе довольно медленной.

Что ты такое?

Структура является сама по себе набором массивов на оригинальном Jass. Однако все сделано для очень удобного использования. С помощью них, можно хранить различные связки нужных нам данных, с которыми можно удобно работать. Хеш таблица работает медленнее структур, и обращаться к данным и хранить их более неудобно. Применение можно найти например в системах движения, в полностью триггерных системах урона, в системах, где необходимо запоминать связку нескольких данных к какому либо объекту.

Создание

Сначала, структуру нужно описать.
    struct A
        real a = 2.
        real b = 1.
        real c = 3.
    endstruct
    
    function SomeFunc takes nothing returns nothing
        local A local_struct = A.create()
        
        call BJDebugMsg(R2S(local_struct.a + local_struct.b + local_struct.c))
        <выведет 6.0>
        
        call local_struct.destroy()
    endfunction
Обратите внимание на то как нужно взаимодействовать с данными внутри структуры. Что бы создать структуру, можно пользоваться встроенным методом <название объекта структуры>.create(). Для уничтожения, используется метод <название структуры>.destroy(). Все функции внутри структуры называются методами, и эти 2 являются встроенными в каждую. Вы можете создать одновременно лишь 8190 структур одного типа. Если вы попытаетесь создать больше при существующих 8190, <название объекта структуры>.create() вернет вам 0. В конце я расскажу об альтернативном создании структур. 0 так же используется для обозначения null структуры
    if local_struct > 0 then
Важно: вы можете объявлять массивы внутри структур. Необходимо задать изначальный размер массива, однако при этом количество максимально возможных структур этого типа уменьшится на 8190/размер массива
	struct A
        real array a[10]
    endstruct
Задавать значения массиву можно в методе .create(), таким образом создавая их при создании структуры. Об этом ниже.

Со структурами можно работать как с обычными переменными, ведь по сути наш local_struct является целочисленной(integer) переменной указывающий на индекс структуры
    function SomeFunc takes nothing returns nothing
        local A local_struct_a = A.create()
        local A local_struct_b
        
            if local_struct_a > 0 then
                set local_struct_b = local_struct_a
            endif
            
        call local_struct_a.destroy()
        call local_struct_b.destroy()
    endfunction

Видимость

Можно делать как приватные, так и публичные, внутри Области либо Библиотеки
    library SomeLibrary
    
        private struct A
            real x
            real y
            real z
        endstruct
        
        public struct B
            unit owner
        endstruct
        
    endlibrary

Типы

Объявить структуру можно как локальную, как вы уже видели
    function SomeFunc takes nothing returns nothing
        local A local_struct = A.create()
    endfunction
так и глобальную
    globals
        A global_struct
    endglobals
Важно: создать структуру таким образом сразу нельзя, нужно делать это при инициализации
    library SomeLibrary initializer SomeFunc
    
        globals
            A global_struct
        endglobals
    
    
        function SomeFunc takes nothing returns nothing
            set global_struct = A.create()
        endfunction
        
    endlibrary


=== Методы ===

Я уже упоминал методы, это функции внутри структуры
    struct A
        unit some_unit
        
        integer attack = 30
        integer defence = 20
        
        real attack_speed = 1.
        
    
            method InitClassStates takes integer class returns nothing
                if class == 1 then
                    this.attack = 20
                    this.defence = 40
                elseif class == 2
                    this.attack = 30
                    this.defence = 35
                endif
            endmethod  
        
    endstruct
    
    
    function SomeFunc takes nothing returns nothing
        local A local_struct = A.create()
            set local_struct.some_unit = CreateUnit(Player(0), 'hpea', 0., 0., 270.)
            
            call local_struct.InitClassStates(2)
            
            call BJDebugMsg(I2S(local_struct.attack))
            <выведет 30>
            call BJDebugMsg(I2S(local_struct.defence))
            <выведет 35>

        call local_struct.destroy()
    endfunction
Внутри методов, используется ключевое слово this. Оно всегда указывает на текущую структуру в которой вызвалась функция. Впрочем, можно просто писать
    if class == 1 {
        .attack = 20
        .defence = 40
    }
Существуют так же такие стандартные методы как onInit, onDestroy
onInit является статичным методом, и запускается при запуске инициализации карты.
onDestroy запускается когда вызывается метод .destroy()

Альтернативное создание структуры

В обычном случае, как выше, мы указывали некоторые данные сразу в структуре, они задавались при создании структуры.
    struct A
        real x = 10.
        real y = 15.
        real z = 20.
    endstruct
При создании через .create() у нас будут уже такие заданные значения в этих переменных. Однако можно сделать вот как, обходя стандартный метод создания, при этом, значения вам нужно будет задать самим
    struct PhaserSlot
        real durability
        integer slot_id
        
        static method new takes integer id returns thistype
            thistype this = thistype.allocate()
                set this.durability = PhaserMaxHp[id]
                set this.slot_id = id
            return this
        endmethod
        
    endstruct
  • thistype всегда указывает на имя структуры, в данном случае PhaserSlot
  • static методы отличаются тем, что они не будет работать с конкретной структурой, тоесть если вы захотите обратиться к данным через this, у вас ничего не выйдет.
  • allocate() является встроенным методом который выделяет новый индекс структуре
По моим данным, такой способ создания является более чистым, ибо при стандартном создании создается много мусора.
Внутри структуры можно перегрузить конструктор create. Если структура не имеет определенный программистом метод create, парсер установит вызов метода allocate для выделения ячейки под структуру. Если метод create программистом определен, он сам должен вызвать метод allocate внутри конструктора
struct Point
	real x
	real y
	static method create takes nothing returns thistype
		local Point p = Point.allocate()
		set p.x = 0.0
		set p.y = 0.0
		return p
	endmethod
endstruct
Метод create должен быть статичным.

Наследование

Структуры могут наследовать данные друг друга
	struct A
        real a = 5.
        real b = 7.
    endstruct
    
    struct B extends A
        real c
    endstruct
    
    function SomeFunc takes nothing returns nothing
        B local_struct = B.create()
            
            <выведет 5.0>
            call BJDebugMsg(R2S(local_struct.a))
    endfunction
Структура B будет иметь переменные a и b, для этого необходимо использовать ключевое слово extends <имя наследуемой структуры>
Это необходимо, если у вас должно быть много разных структур, но у всех у них будут какие либо одинаковые данные, например количество здоровья. Аналогом из Jass можно привести в пример тип Widget, который всегда имеет количество здоровья, и является основой таким типам как Item, Destructable и Unit

Использование с таймер эксплоитом

Существует эксплоит таймера, который был найден пользователем ScorpioT1000
немного cJass'а
    define TimerStartEx(whichTimer, period, handlerFunc, userData) = {
            TimerStart(whichTimer, I2R(userData), false, null) // timer exploit, xgm 2007, by Scorpio
            PauseTimer(whichTimer)
            TimerStart(whichTimer, period, false, handlerFunc )
    }
    
    define GetTimerAttach(h) = R2I(TimerGetRemaining(h)+0.5)
Используя его, можно прицеплять на таймер целочисленное значение, а структура как раз передает свой целочисленный индекс
    struct A
        string str = "млг360ноускопе"
    endstruct
    

    function Result takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local A local_struct = GetTimerAttach(t)
                call BJDebugMsg(local_struct.str)
                <выведет "млг360ноускопе">
        call DestroyTimer(t)
        call local_struct.destroy()
        set t = null
    endfunction
    
    
    function Start takes nothing returns nothing
        local A local_struct = A.create()
        local timer t = CreateTimer()
            TimerStartEx(t, 1., function Result, local_struct)
        set t = null
    endfunction


Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
29
7 лет назад
0
Ппц что оригинал, что вот это очень плохие объяснения честно говоря
1
17
7 лет назад
Отредактирован GetLocalPlayer
1
Впрочем, если вы используете cjass, можно просто писать
Опускать this можно и в vJass. Из оригинала:
  • this is optional : You can use a single . instead of this. when you are inside an instance method. (For example set .member = value)
Однако можно сделать вот как, обходя стандартный метод создания, при этом, значения вам нужно будет задать самим
Внутри структуры можно перегрузить конструктор create. Если структура не имеет определенный программистом метод create, парсер установит вызов метода allocate для выделения ячейки под структуру. Если метод create программистом определен, он сам должен вызвать метод allocate внутри конструктора
struct Point
	real x
	real y
	static method create takes nothing returns thistype
		local Point p = Point.allocate()
		set p.x = 0.0
		set p.y = 0.0
		return p
	endmethod
endstruct
Метод create должен быть статичным.
Важно: вы можете объявлять массивы внутри структур.
И ни слова о том, как это делается
И еще много чего важного, чего хватит на 2 такие статьи (исключая множество фич которые мало кому вперлись).
Худо-бедно короче говоря. Многое сказано вскользь и с успехом опущены важные детали.
0
29
7 лет назад
0
Хороший комментарий. Я бы всё-таки предложил взять любую доступную стать по ооп для новичков по любому современному статически типизированному языку и просто слизать её переделав под вжасс и добавив реально полезные фичи, а не таймер экслойт.
1
30
7 лет назад
Отредактирован Clamp
1
Важно: вы можете объявлять массивы внутри структур.
Ни слова о том, что массивам нужно задавать размеры и ни слова о том, что массивы снижают максимальное количество экземпляров структуры до (8192/размер_массива).
Если честно, статью стоит перехерачить и дать не тупо "структура делается так", а пояснить, зачем это нужно концептуально и что позволяет делать на практике. После этого уже можно и матчасть пояснять.
я как раз занят написанием своей на эту же тематику, так сказать, по мере изучения
0
26
7 лет назад
0
И еще много чего важного, чего хватит на 2 такие статьи (исключая множество фич которые мало кому вперлись).
я не так просто добавил слово "основы" в заголовок. текущая информация я считаю вполне позволит начать работу со структурами.
Ни слова о том, что массивам нужно задавать размеры и ни слова о том, что массивы снижают максимальное количество экземпляров структуры до (8192/размер_массива).
забыл добавить про уменьшение размера, сорян.
Я бы всё-таки предложил взять любую доступную стать по ооп для новичков по любому современному статически типизированному языку и просто слизать её переделав под вжасс и добавив реально полезные фичи, а не таймер экслойт.
я смотрю с позиции варкрафта, и пытаюсь описывать для него. почему кстати таймер эксплоит не полезная фича?
0
30
7 лет назад
0
почему кстати таймер эксплоит не полезная фича?
Потому что и без него прекрасно можно всё делать, с более логичной и адекватной архитектурой.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.