vjass структуры, проблема наследования
Может кто знает принцип взаимодействия наследованных структур, ибо столкнулся с такой проблемой:
struct Tracker
    static method create takes real x, real y, string rpath, integer p returns Tracker
        ...
        set trk.tr = CreateTrackable(rpath,x,y,0)
        
        set trk.t_track = CreateTrigger()
        call TriggerRegisterTrackableTrackEvent(trk.t_track,trk.tr)
        call TriggerAddAction(trk.t_track,function Tracker.defaultTrack)
        call DisableTrigger(trk.t_track)
        
        call SaveInteger(hash,H2I(trk.tr),1,trk)
		...
    endmethod

    stub method OnTrack takes nothing returns nothing
        echo("track1")
    endmethod

    static method defaultTrack takes nothing returns nothing
        Tracker(LoadInteger(hash,H2I(GetTriggeringTrackable()),1)).OnTrack()
    endmethod
endstruct

struct Button extends Tracker
    stub method OnTrack takes nothing returns nothing
        echo("track2")
    endmethod
endstruct
хочу переопределить OnTrack но получается что приведение типа в статическом методе defaultTrack указывает четко имя структуры(не знаю как иначе сделать), метод которой будет вызван, т.е. по дефолту при наведение на трекебл выведется "track1", если же я в defaultTrack сделаю приведение типа Button то выведется "track2", но Tracker не должен знать о своих детях, потому вопрос в том, можно ли с помощью структур реализовать наследование экшенов или как привести тип к актуальному, а не конкретному?
Возможно я что-то упускаю.

Лучший ответ:
да вот только thistype возвращает структуру из которой он вызван, а не структуру инстанса идентификатора, т.е. getTrack будет всегда возвращать тип Tracker. Вопрос в том, как по идентификатору определить конкретный тип структуры и к нему привести.
Этот код тестировал? Он должен работать.

Структуры в vJass - массивы. Объект структуры - integer.
У каждой структуры есть массив, куда записывается тип каждого объекта структуры. Пусть у Trackle айди 1, а у Button 2. При создании объекта структуры будет сделано следующее: set массив_куда_записывается_тип[объект_структуры] = айди_структуры. При создании объекта Button и в массив типа структуры Button, и в массив структуры Trackle будет записано 2.

Перезаписываемые методы - массив триггеров, у которых в качестве условия записано тело метода.
Вызов такого метода - call TriggerEvaluate(массив_триггеров[массив_куда_записывается_тип[объект_структуры]]).
В нашем случае это будет выглядеть call TriggerEvaluate(массив_триггеров_OnTrack[массив_куда_записывается_тип[getTrack(h)]]).

Потому должно работать.



Просмотров: 175

XGM Bot #1 - 1 неделю назад 2
Похожие вопросы:

» ответ
стоп
а где заполнение массива структур?
мб все элементы массива одинаковы и ты просто инкриментишь одну и туже структуру 4 раза
создание структуры через статичный метод create идёт
» ответ
В помощь тебе библиотеки(library) и базы данных.
Либы — для обращения по виду library_name.functionName(arguments)
Базы данных — для выделения юниту своих переменных.
С БД может быть момент не совсем понятным, поэтому скидываю пример:
» Эта порнография разработана для личного пользования
У меня в коде есть иллюзия использования вжасса. Либа просто для доп табуляции и невостребованых манипуляций на случай импорта. При создании юнита ему присваивается ряд переменных, а номер этих переменных, относящихся к этому юниту, записывается в его(юнита) UnitUserData
library UnitDataBase
    globals
        constant integer       UnitDBSize = 512
        constant integer       UnitDBHeroesStart = 0
        constant integer       UnitDBHeroesUnder = 49
        constant integer       UnitDBUnitsStart = 50//Includes illusions of heroes. Or Should include them at least :P
        constant integer       UnitDBUnitsUnder = 319
        constant integer       UnitDBSummonsStart = 320
        constant integer       UnitDBSummonsUnder = 511
                 integer       UnitDBNextHero = 0
                 integer       UnitDBNextUnit = 50
                 integer       UnitDBNextSummon = 320
                 unit    array UnitDBUnit[UnitDBSize]
                 real    array UnitDBCurrentAnimationSpeed[UnitDBSize]
                 unit    array UnitDBForceAttackTarget[UnitDBSize]
                 integer array UnitDBAffectedByStuns[UnitDBSize]
                 real    array UnitDBMagicResistance[UnitDBSize]
                 real    array UnitDBPhysResistance[UnitDBSize]
                 real    array UnitDBCurrentArmor[UnitDBSize]//This armor does not include agility bonuses. Not used yet :>
                 real    array UnitDBWhiteMovementSpeed[UnitDBSize]
                 real    array UnitDBCurrentCustomSlow[UnitDBSize]
                 real    array UnitDBMagicDamageAmplifier[UnitDBSize]
                 real    array UnitDBPhysDamageAmplifier[UnitDBSize]
                 real    array UnitDBAdditionalHealth[UnitDBSize]//AKA Shield. Healed whenever unit takes damage.
        constant real          GravityAcceleration = 14.//Azeroth, bitch!
                 real    array UnitDBFlyingHeight[UnitDBSize]//Not used yet
                 real    array UnitDBFallingSpeed[UnitDBSize]
                 
                 integer array UnitDBItemUseVariable[UnitDBUnitsStart]//just don't ask
                 item    array UnitDBLastUsedItem[UnitDBUnitsStart]
                 real    array UnitDBCastPointX[UnitDBUnitsStart]
                 real    array UnitDBCastPointY[UnitDBUnitsStart]
                 
                 integer       UnitDBPreviousHero//Used for exitwhen event. Its next minus two.
                 unit    array UnitDBHeroHPBar[UnitDBUnitsStart]
                 unit    array UnitDBHeroMPBar[UnitDBUnitsStart]
                 unit    array UnitDBHeroSPBar[UnitDBUnitsStart]
    endglobals
    
    //Больно жирные для инлайна
    function UnitDBFindNextFreeVariable takes integer i returns integer
        local unit u
            loop
                set  u = UnitDBUnit[i]
                exitwhen u == null or GetUnitTypeId( u ) < 1
                set  i = i + 1
            endloop
        set  u = null
        return i
    endfunction
    
    function UnitDBAddHero takes unit u, real mdef, real armor returns nothing
        local integer i = UnitDBNextHero
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
            call UnitMakeAbilityPermanent( u, true, 'A00B' )
            set  UnitDBUnit[i] = u
            call SetUnitUserData( u, i )
            call GroupAddUnit( UnitsInPlayableArea, u )
            set  UnitDBItemUseVariable[i] = 0
            set  UnitDBCurrentAnimationSpeed[i] = 0.
            set  UnitDBAffectedByStuns[i] = 0
            set  UnitDBMagicResistance[i] = mdef
            set  UnitDBCurrentArmor[i] = armor
            set  UnitDBWhiteMovementSpeed[i] = GetUnitDefaultMoveSpeed( u )
            set  UnitDBCurrentCustomSlow[i] = 1.
            set  UnitDBMagicDamageAmplifier[i] = 1.
            set  UnitDBPhysDamageAmplifier[i] = 1.
            set  UnitDBFlyingHeight[i] = 0.//Doesn't include point height.
            set  UnitDBAdditionalHealth[i] = 0.
            /*if ( i == UnitDBHeroesUnder ) then
               call BJDebugMsg("|c00ff6060Hero limit reached! More heroes can be created, but things can go wild.")
            endif*/
            set  UnitDBNextHero = i + 1
            set  UnitDBPreviousHero = i - 1
            set  UnitDBHeroHPBar[i] = CreateUnit(BossPlayer1, 'hmil', x, y, 0. )
            call SetUnitAnimationByIndex( UnitDBHeroHPBar[i], 100 )
            set  UnitDBHeroMPBar[i] = CreateUnit( BossPlayer1, 'hrtt', x, y, 0. )
            call SetUnitAnimationByIndex( UnitDBHeroMPBar[i], 100 )
            set  UnitDBHeroSPBar[i] = CreateUnit( BossPlayer1, 'hwt2', x, y, 0. )
            call SetUnitAnimationByIndex( UnitDBHeroSPBar[i], 0 )
        set  u = null
        return
    endfunction

    function UnitDBAddUnit takes unit createdUnit, real mdef, real armor returns nothing
        local integer i = UnitDBNextUnit
        local unit u = UnitDBUnit[i]
            if ( u == null ) then
                set  i = UnitDBFindNextFreeVariable( UnitDBSummonsStart )
            endif
            set  UnitDBUnit[i] = createdUnit
            call SetUnitUserData( createdUnit, i )
            call GroupAddUnit( UnitsInPlayableArea, createdUnit )
            set  UnitDBCurrentAnimationSpeed[i] = 0.
            set  UnitDBAffectedByStuns[i] = 0
            set  UnitDBMagicResistance[i] = mdef
            set  UnitDBCurrentArmor[i] = armor
            set  UnitDBWhiteMovementSpeed[i] = GetUnitDefaultMoveSpeed( createdUnit )
            set  UnitDBCurrentCustomSlow[i] = 1.
            set  UnitDBMagicDamageAmplifier[i] = 1.
            set  UnitDBPhysDamageAmplifier[i] = 1.
            set  UnitDBFlyingHeight[i] = 0.
            set  UnitDBAdditionalHealth[i] = 0.
            if ( i < UnitDBSummonsUnder) then
                set  UnitDBNextSummon = i + 1
            else
                set  UnitDBNextSummon = UnitDBSummonsStart
            endif
        set  u = null
        set  createdUnit = null
        return
    endfunction
    
    function UnitDBAddSummon takes unit summonedUnit, real mdef, real armor returns nothing
        local integer i = UnitDBNextSummon
        local unit u = UnitDBUnit[i]
            if ( u == null ) then
                set  i = UnitDBFindNextFreeVariable( UnitDBSummonsStart )
            endif
            set  UnitDBUnit[i] = summonedUnit
            call SetUnitUserData( summonedUnit, i )
            call GroupAddUnit( UnitsInPlayableArea, summonedUnit )
            set  UnitDBCurrentAnimationSpeed[i] = 0.
            set  UnitDBAffectedByStuns[i] = 0
            set  UnitDBMagicResistance[i] = mdef
            set  UnitDBCurrentArmor[i] = armor
            set  UnitDBWhiteMovementSpeed[i] = GetUnitDefaultMoveSpeed( summonedUnit )
            set  UnitDBCurrentCustomSlow[i] = 1.
            set  UnitDBMagicDamageAmplifier[i] = 1.
            set  UnitDBPhysDamageAmplifier[i] = 1.
            set  UnitDBFlyingHeight[i] = 0.
            set  UnitDBAdditionalHealth[i] = 0.
            if ( i < UnitDBSummonsUnder) then
                set  UnitDBNextSummon = i + 1
            else
                set  UnitDBNextSummon = UnitDBSummonsStart
            endif
        set  u = null
        set  summonedUnit = null
        return
    endfunction
      
    //Система маг резиста была изменена на дефолтную, была введена аналогичная ей система физ урона.
    //Необходимо протестить эти системы на низких значениях. (могучий float и его точность). В нынешних условиях низкие значения не достигаются. На тест положен болт. Есть нерешенные проблемы с точностью(при восстановлении, опять же, резисты съезжают). Необходимо учитывать при вычислениях лишь первые три цифры после запятой, например.
    #define UnitDBIncreaseUnitMagicResistance( amount, userData ) = {
            set  UnitDBMagicResistance[userData] = UnitDBMagicResistance[userData] * amount
    }
    #define UnitDBDecreaseUnitMagicResistance( amount, userData ) = {
            set  UnitDBMagicResistance[userData] = UnitDBMagicResistance[userData] / amount
            if ( UnitDBMagicResistance[userData] > 0.99997 and UnitDBMagicResistance[userData] < 1.00003 ) then
                set  UnitDBMagicResistance[userData] = 1. 
            endif
    }
    #define UnitDBIncreaseUnitPhysResistance( amount, userData ) = {
            set  UnitDBPhysResistance[userData] = UnitDBPhysResistance[userData] * amount
    }
    #define UnitDBDecreaseUnitPhysResistance( amount, userData ) = {
            set  UnitDBPhysResistance[userData] = UnitDBPhysResistance[userData] / amount
            if ( UnitDBPhysResistance[userData] > 0.99997 and UnitDBPhysResistance[userData] < 1.00003 ) then
                set  UnitDBPhysResistance[userData] = 1. 
            endif
    }
    #define UnitDBReplaceUnitMagicResistance( before, after, userData ) = {
            set  UnitDBMagicResistance[userData] = UnitDBMagicResistance[userData] / before * after
    }
    #define UnitDBReplaceUnitPhysResistance( before, after, userData ) = {
            set  UnitDBPhysResistance[userData] = UnitDBPhysResistance[userData] / before * after
    }
    #define UnitDBIncreaseUnitMagicDamageAmplifier( amount, userData ) = {
            set  UnitDBMagicDamageAmplifier[userData] = UnitDBMagicDamageAmplifier[userData] + amount
    }
    #define UnitDBDecreaseUnitMagicDamageAmplifier( amount, userData ) = {
            set  UnitDBMagicDamageAmplifier[userData] = UnitDBMagicDamageAmplifier[userData] - amount
            if ( UnitDBMagicDamageAmplifier[userData] > 0.99997 and UnitDBMagicDamageAmplifier[userData] < 1.00003 ) then
                set  UnitDBMagicDamageAmplifier[userData] = 1. 
            endif
    }
    #define UnitDBIncreaseUnitPhysDamageAmplifier( amount, userData ) = {
            set  UnitDBPhysDamageAmplifier[userData] = UnitDBPhysDamageAmplifier[userData] + amount
    }
    #define UnitDBDecreaseUnitPhysDamageAmplifier( amount, userData ) = {
            set  UnitDBPhysDamageAmplifier[userData] = UnitDBPhysDamageAmplifier[userData] - amount
            if ( UnitDBPhysDamageAmplifier[userData] > 0.99997 and UnitDBPhysDamageAmplifier[userData] < 1.00003 ) then
                set  UnitDBPhysDamageAmplifier[userData] = 1. 
            endif
    }
    #define UnitDBIncreaseUnitShield( amount, userData ) = {
            set  UnitDBAdditionalHealth[userData] = UnitDBAdditionalHealth[userData] + amount
            //redraw
    }
    #define UnitDBDecreaseUnitShield( amount, userData ) = {
            set  UnitDBAdditionalHealth[userData] = UnitDBAdditionalHealth[userData] - amount
            if ( UnitDBAdditionalHealth[userData] < 0. ) then//Perhaps should be typed manually on every use. No need of that atm.
                set  UnitDBAdditionalHealth[userData] = 0.
            endif
            //redraw
    }
    function UnitDBAddUnitsCreatedOnInit takes nothing returns nothing
        local unit u = GetEnumUnit()
            if ( not IsUnitType( u, UNIT_TYPE_HERO ) ) then
                call UnitDBAddUnit( u, 1., 0. )//!!! whatever
            endif
        set  u = null
        return
    endfunction
    
endlibrary
» ответ
allocate() используется внутри статичного метода и возвращает лишь индекс новой структуры
Технически верно, но на практике использовать .allocate() есть смысл только при перегрузке .create() (равно как и .deallocate() только при перегрузке .destroy()). Собственно, согласно документации, для того эти методы и существуют.
» ответ
Напиши простейший код, скомпиль и посмотри во что превращается. Никаких структур в движке варика нет, вжасс это надстройка которая транспилит в обычный жасс.
» ответ
» - Я использую это:

данный код перебирает все активные ячейки структуры, которые были созданы через метод create, каждые 0.03125 сек.. При этом, если освободить одну из ячеек через метод destroy, то данная ячейка структуры не будет перебираться.

struct linkedList
        private  static  constant  timer     period  =  CreateTimer( )
        private                    thistype  prev
        private                    thistype  next


        private stub method destroy takes nothing returns nothing

//          Здесь должен находится Ваш код.

            set  this.prev.next  =  this.next
            set  this.next.prev  =  this.prev

            if ( thistype( 0 ).next == 0 ) then
                call PauseTimer( thistype.period )
            endif

            call thistype.deallocate( this )
        endmethod


        private static method iterate takes nothing returns nothing
            local  thistype  this  =  thistype( 0 ).next

            loop
                exitwhen ( this == 0 )

//              Здесь должен находится Ваш код.

                call this.destroy( )

                set  this  =  this.next
            endloop
        endmethod


        private static method create takes nothing returns thistype
            local  thistype  this  =  thistype.allocate( )

            set  this.next         =  thistype( 0 )
            set  this.prev         =  thistype( 0 ).prev
            set  this.next.prev    =  this
            set  this.prev.next    =  this

//          Здесь должен находится Ваш код.
            
            if ( this.prev == 0 ) then
                call TimerStart( thistype.period, 0.03125, true, function thistype.iterate )
            endif

            return this
        endmethod


    endstruct

здесь происходит выделение ячейки массива:

static method create takes nothing returns nothing

здесь происходит перебирание всех ячеек массива

static method iterate takes nothing returns nothing

здесь происходит освобождение ячейки массива:

method destroy takes nothing returns nothing
Для работы этого двусвязного списка требуется создать 2-е переменные с именами next, prev.

PT153 #2 - 1 неделю назад (отредактировано ) 0
Я не понял, что ты хочешь, но в vJass есть каст структур Нужный_тип(переменная_структуры_другого_типа).

Также по правилам ООП в переменной типа Tracker может быть как объект типа Traker, так и объект его детей.
struct MyTracker extends Tracker
    method OnTrack takes nothing return nothing
        call DisplayTextToPlayer(Player(0), 0., 0., 5. "HAHAHAH")
    endmethod
endstruct
...
function f takes nothing returns nothing
    Tracker t = MyTracker.create();
    t.OnTarck(); // выведет текст "HAHAHAH" и ничего больше не сделает.
endfunction

Вроде понял.
Ты делаешь каст integerа в Tracker, потому вызывается метод, описанный в Tracker. Если делаешь каст в Button, то сработает метод Button. Тебе нужно сделать метод defaultTrack не статичным и перезаписываемым.

Вот как я решил твою проблему.
struct Tracker
    ...
    static method getTrack takes nothing returns thistype
        return LoadInteger(hash,H2I(GetTriggeringTrackable()),1)
    endmethod

    stub method OnTrack takes nothing returns nothing
        call echo("track1")
    endmethod
endstruct

struct Button extends Tracker
    method OnTrack takes nothing returns nothing
        call echo("track2")
    endmethod
endstruct
...
function f1 takes nothing returns nothing
    local Button t = Tracker.getTrack()
    call t.OnTrack() // будет вызвано echo("track2").
endfunction

// Делает тоже самое, что и f1.
function f2 takes nothing returns nothing
    call Button(Tracker.getTrack()).OnTrack() // будет вызвано echo("track2").
endfunction
nvc123 #3 - 1 неделю назад 0
интерфейсы юзай
хотя я бы не советовал часто юзать полиморфизм на вджасс
он реализован через триггеры и при большом количестве объектов существенно растёт нагрузка на машину
exAres #4 - 1 неделю назад (отредактировано ) 0
PT153, вот только беда в том, что при регистрации TriggerAddAction(trk.t_track,function Tracker.defaultTrack) я должен указать именно статичную функцию, а вот с нее уже вызвать наследованную.
PT153 #5 - 1 неделю назад (отредактировано ) 0
вот только беда в том, что при регистрации TriggerAddAction(trk.t_track,function Tracker.defaultTrack) я должен указать именно статичную функцию, а вот с нее уже вызвать наследованную.
Так должно работать как нужно.
struct Tracker
    static method getTrack takes integer h returns thistype
        return LoadInteger(hash, h, 1)
    endmethod

    stub method OnTrack takes nothing returns nothing
        call echo("track1")
    endmethod

    static method defaultTrack takes nothing returns nothing
        local integer h = GetHandleId(GetTriggeringTrackable())
        call getTrack(h).OnTrack()
    endmethod
endstruct

struct Button extends Tracker
    stub method OnTrack takes nothing returns nothing
        call echo("track2")
    endmethod
endstruct
интерфейсы юзай
Ему же нужно создавать объект типа Tracker.
exAres #6 - 1 неделю назад (отредактировано ) 0
PT153, да вот только thistype возвращает структуру из которой он вызван, а не структуру инстанса идентификатора, т.е. getTrack будет всегда возвращать тип Tracker. Вопрос в том, как по идентификатору определить конкретный тип структуры и к нему привести.
PT153 #7 - 1 неделю назад (отредактировано ) 2

да вот только thistype возвращает структуру из которой он вызван, а не структуру инстанса идентификатора, т.е. getTrack будет всегда возвращать тип Tracker. Вопрос в том, как по идентификатору определить конкретный тип структуры и к нему привести.
Этот код тестировал? Он должен работать.

Структуры в vJass - массивы. Объект структуры - integer.
У каждой структуры есть массив, куда записывается тип каждого объекта структуры. Пусть у Trackle айди 1, а у Button 2. При создании объекта структуры будет сделано следующее: set массив_куда_записывается_тип[объект_структуры] = айди_структуры. При создании объекта Button и в массив типа структуры Button, и в массив структуры Trackle будет записано 2.

Перезаписываемые методы - массив триггеров, у которых в качестве условия записано тело метода.
Вызов такого метода - call TriggerEvaluate(массив_триггеров[массив_куда_записывается_тип[объект_структуры]]).
В нашем случае это будет выглядеть call TriggerEvaluate(массив_триггеров_OnTrack[массив_куда_записывается_тип[getTrack(h)]]).

Потому должно работать.
exAres #8 - 1 неделю назад 0
PT153, у меня есть привычка проверять сначала, если не уверен) так что да, тестировал, не работает, getTrack, который принадлежит Tracker, его и возвращает.
PT153 #9 - 1 неделю назад (отредактировано ) 0
у меня есть привычка проверять сначала, если не уверен) так что да, тестировал, не работает, getTrack, который принадлежит Tracker, его и возвращает.
Попробуй так.
    static method defaultTrack takes nothing returns nothing
        local thistype h = getTrack(GetHandleId(GetTriggeringTrackable()))
        call h.OnTrack()
    endmethod
Если и это не сработает, то правьте руки кинь свой код Tracker и его детей в мне в ЛС. Я уж гляну, что к чему.
PT153 #11 - 1 неделю назад (отредактировано ) 2
Прошёл день, а кода в ЛС я не увидел, проблема решена?

Ты делаешь каст integerа в Tracker, потому вызывается метод, описанный в Tracker.
А вот это неправда, и в этом случае вызывается так, как я описал в комментарии 7.
То есть даже код из вопроса работает, как нужно.
Небольшой совет: определение метода нужно писать над кодом, в котором этот метод передаётся как code, иначе на самом деле будет передана функция, что вызывает триггер, в котором уже вызывается указанный метод.

Карта, в которой есть подтверждения моих слов.
прикреплены файлы