Worldedit
  Worldedit
Le site sur l'éditeur de warcraft 3 !
 
  FAQFAQ   RechercherRechercher   Liste des MembresListe des Membres    Groupes d'utilisateursGroupes d'utilisateurs   medals.php?sid=61643da766acc9f60d75db87948477dcMédailles   S'enregistrerS'enregistrer 
 ProfilProfil   Se connecter pour vérifier ses messages privésSe connecter pour vérifier ses messages privés   ConnexionConnexion 
  FAQFAQ World Editor   UploadUploader une map ou une image    UploadAjouter sa map à l'annuaire   UploadConsulter l'annuaire

Problème Special effect - chemin, library xe?...

 
Poster un nouveau sujet   Répondre au sujet    Worldedit Index du Forum -> Aide sur les déclencheurs
Voir le sujet précédent :: Voir le sujet suivant  
Auteur Message
 Crowolf
Animateur


Inscrit le: 21 Avr 2008
Messages: 1607
Sujets: 81
Spécialité en worldedit: Utiliser le travail des autres
Médailles: 3 (En savoir plus...)
Grand décorateur (Quantité : 2) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 12/05/12 23:43    Sujet du message: Problème Special effect - chemin, library xe?... Citer

Salut, j'ai voulu utiliser les libraries xedamage, xefx etc. pour un sort.
Le plus gros problème, c'est que le chemin spécifié dans le déclencheur pour le projectile n'est pas du tout le bon. Je me retrouve avec un projectile qui a le modèle d'une unité importée :/

Ensuite, il y a des petits problèmes au niveau de la destruction de ces effets spéciaux, ils restent trop longtemps visibles après être arrivés près de la cible.

Voilà, et même si le sort n'est pas tout à fait fini et optimisé, je prend les remarques sur le code Smile Je voulais utiliser les libraries xe.

Pour le sort:
Basé sur Coup de tonnerre (pas de cible)
Plusieurs projectile partent du caster vers les unités alliés proches avec un nombre de vague qui augmente selon le niveau du sort.
Arrivé près de la cible, la cible est soignée.
J'arrive à faire ça, c'est surtout ce problème d'effet qui me gave.

Secret:

Jass:
scope PhoenixTears initializer Init
//===========================================================================
//===========================================================================
//===========================================================================
    globals
        private keyword data
        private constant integer SPELL_ID = 'A01A'
        private constant real MIN_DIST = 80.
        private constant real FX_SPEED = 10.
        private constant real FX_SCALE = 1.
        private constant integer FX_RED = 255
        private constant integer FX_BLUE = 255
        private constant integer FX_GREEN = 255
        private constant integer FX_ALPHA = 255
        private constant string FX_CASTER = "Abilities\\Spells\\Undead\\ReplenishHealth\\ReplenishHealthCasterOverhead.mdl"
        private constant string FX_MISSILE = "Abilities\\Weapons\\DragonHawkMissile\\DragonHawkMissile.mdl"
        private constant string FX_HEAL = "Abilities\\Spells\\Items\\ResourceItems\\ResourceEffectTarget.mdl"
        private constant string FX_ATTCH = "origin"
        private constant real DELAY_PULSE = 2
    endglobals
   
    private function Range takes integer lvl returns real
        return 500. + 50 * lvl
    endfunction
   
    private function Heal takes integer lvl returns real
        return 45. + 15 * lvl
    endfunction
   
    private function MaxTarget takes integer lvl returns integer
        return 3 + lvl
    endfunction
   
    private function MaxPulse takes integer lvl returns integer
        return lvl * 1 + 0
    endfunction
   
     private function DamageOptions takes xedamage spellDamage returns nothing
        set spellDamage.dtype = DAMAGE_TYPE_UNIVERSAL
        set spellDamage.atype = ATTACK_TYPE_NORMAL
        set spellDamage.exception = UNIT_TYPE_STRUCTURE
        set spellDamage.visibleOnly = true
        set spellDamage.damageSelf = true
        set spellDamage.damageAllies = true //heals for amount of
        set spellDamage.allyfactor = -1.0   //hitpoints to allies.
    endfunction
   
    private function IsValidTarget takes unit u, Data s returns boolean
        return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE)==false and IsUnitAlly(u,GetOwningPlayer(s.caster))==true and IsUnitVisible(u,GetOwningPlayer(s.caster))==true
    endfunction
//===========================================================================
//===========================================================================
//===========================================================================
   
    globals
        private xedamage xed
    endglobals
   
        //struct for the missile
    struct heal
        timer t
        unit caster
        unit target
        xefx fx
        real x
        real y
        integer lvl
       
        static method create takes unit c, unit tr, real x, real y, integer lvl returns thistype
            local thistype this = heal.allocate()
            local real a = Atan2(y-GetUnitY(tr), x-GetUnitX(tr))
           
            set .x = x
            set .y = y
            set .caster = c
            set .target = tr
            set .lvl = lvl
            set .t = NewTimer()
            set .fx = xefx.create(x,y,a)
            set .fx.fxpath = FX_MISSILE
            set .fx.z = 500.
            set .fx.scale = FX_SCALE
            call .fx.recolor(FX_RED, FX_GREEN, FX_BLUE, FX_ALPHA)
            call SetTimerData(.t, this)
            call TimerStart(.t, XE_ANIMATION_PERIOD, true, function heal.onMove)
       
        return this
        endmethod
       
        static method onMove takes nothing returns nothing
            local thistype this = thistype(GetTimerData(GetExpiredTimer()))
           
            local real x = GetUnitX(.target) - .fx.x
            local real y = GetUnitY(.target) - .fx.y
            local real z = (GetUnitFlyHeight(.target) - .fx.z) + FX_SPEED
           
            local real distance = SquareRoot(x*x + y*y + z*z)
           
            local real angle1 = Atan2(y, x)
            local real angle2 = Acos(z / distance)
            local real angle3 = Atan2(z, SquareRoot(x*x + y*y))
           
           
            if not IsUnitType(.target, UNIT_TYPE_DEAD) then
                if (distance > MIN_DIST) then
                    set .fx.xyangle = angle1
                    set .fx.x = .fx.x + FX_SPEED * Cos(angle1) * Sin(angle2)
                    set .fx.y = .fx.y + FX_SPEED * Sin(angle1) * Sin(angle2)
                    set .fx.z = .fx.z + FX_SPEED * Cos(angle2)
                    set .fx.zangle = angle3
                else
                    call xed.damageTarget(.caster, .target, Heal(.lvl))
                    call DestroyEffect(AddSpecialEffectTarget(FX_HEAL, .target, FX_ATTCH))
                    call .fx.destroy()
                endif
            else
                call .fx.destroy()
                call .destroy()
            endif
           
        endmethod
       
        private method onDestroy takes nothing returns nothing
            call ReleaseTimer(.t)
        endmethod
       
    endstruct
   
        //struct for caster
    struct Data
        unit caster
        timer t
        xefx fx
        real x
        real y
        integer lvl
        private static thistype temp
        integer pulse
       
    static method Create takes unit c, real x, real y returns thistype
        local thistype this = Data.allocate()
       
        set .caster = c
        set .x = GetUnitX(c)
        set .y = GetUnitY(c)
        set .lvl = GetUnitAbilityLevel(c, SPELL_ID)
        set .pulse = MaxPulse(.lvl)
        set .t = NewTimer()
        call SetTimerData(.t, this)
        call TimerStart(.t, DELAY_PULSE, true, function thistype.onPulse)
       
    return this
    endmethod
   
    static method onPulse takes nothing returns thistype
        local thistype this = thistype(GetTimerData(GetExpiredTimer()))
       
        if pulse > 0 then
            call DestroyEffect(AddSpecialEffectTarget(FX_CASTER, .caster, FX_ATTCH))
            set pulse = pulse - 1
            set temp = this
            call GroupEnumUnitsInRange(ENUM_GROUP, .x, .y, Range(.lvl), function Data.VictimFilter)
           
           
        else
            call ReleaseTimer(.t)
            call .destroy()
        endif
       
    return this
    endmethod
   
    private method onDestroy takes nothing returns nothing
        call ReleaseTimer(.t)
        call .fx.destroy()
    endmethod
   
    static method VictimFilter takes nothing returns boolean
        local unit u = GetFilterUnit()
        local heal h
        call BJDebugMsg(GetUnitName(u))

        if IsValidTarget(u, temp) then
            set h = heal.create(temp.caster, u, temp.x, temp.y, temp.lvl)
        endif
        set u = null
       
    return false
    endmethod
   
   
//===========================================================================       
    static method Conditions takes nothing returns boolean
        local thistype this
       
        if GetSpellAbilityId() == SPELL_ID then
            set this = thistype.Create(GetTriggerUnit(), GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()))
        endif
    return false
    endmethod
       
endstruct 
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger PhoenixTearsTrg = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(PhoenixTearsTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(PhoenixTearsTrg, Condition(function Data.Conditions))
           
            //init xedamage
        set xed = xedamage.create()
        call DamageOptions(xed)
           
            //preloading effects
        call Preload(FX_MISSILE)
        call Preload(FX_HEAL)
        call Preload(FX_CASTER)
    endfunction
 
endscope


_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Crowolf
Animateur


Inscrit le: 21 Avr 2008
Messages: 1607
Sujets: 81
Spécialité en worldedit: Utiliser le travail des autres
Médailles: 3 (En savoir plus...)
Grand décorateur (Quantité : 2) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 12/05/12 23:59    Sujet du message: Citer

J'ai trouvé le problème de l'effet, c'était pas le bon code pour le dummy dans xebasic...
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7146
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1) Grand mage créateur de sort (Quantité : 1)

MessagePosté le: 13/05/12 16:33    Sujet du message: Re: Problème Special effect - chemin, library xe?... Citer

Jass:
...

    local unit u

    call GroupEnumUnitsInRange(ENUM_GROUP, .x, .y, Range(.lvl), null) // oui on ne filtre pas les unités
   
    loop
    set u = FirstOfGroup(ENUM_GROUP)
    call GroupRemoveUnit(ENUM_GROUP,u)
    exitwhen u == null

        if IsValidTarget(u,this) then
            set h = heal.create(this.caster, u, this.x, this.y, this.lvl)
        endif

    endloop

    // la même loop une fois convertie en jass mais moins verbeuse et error prone avec le nouveau jasshelper par Cohadar :

    for u in ENUM_GROUP
   
        if IsValidTarget(u) then
            set h = heal.create(this.caster, u, this.x, this.y, this.lvl)
        endif

    endfor
           
...


Oui il est plus efficace d'utiliser un filtre null plutôt qu'un filtre non null, car à chaque évaluation du filtre un nouveau thread est créé, ce qui est beaucoup plus coûteux que simplement rajouter toutes les unités, puis les filtrer avec la loop ci dessous.

Cela dit, encore une fois la différence de performance ici ne sera pas perceptible, par contre cela a d'autres avantages, tu ne divises pas ton code et donc tu ne dois pas passer par des variables globales temporaires comme tu le fais, tu peux directement utiliser les variables locales.
Le leak du filtre null avec un GroupEnum a été fixé depuis plusieurs patchs.

GetUnitTypeId(u) != 0 est superflu dans la fonction IsUnitValid car si tu peux énumérer des unités mortes, il est impossible d'énumérer des unités qui n'existent pas/plus dans le jeu.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Crowolf
Animateur


Inscrit le: 21 Avr 2008
Messages: 1607
Sujets: 81
Spécialité en worldedit: Utiliser le travail des autres
Médailles: 3 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1) Grand décorateur (Quantité : 2)

MessagePosté le: 14/05/12 16:40    Sujet du message: Citer

Merci Troll-Brain, le fait de faire une boucle comme tu m'as montré m'a en plus permis de faciliter le code pour choisir des unités aléatoirement.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7146
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 14/05/12 16:48    Sujet du message: Citer

Par contre pour un groupe qui a été gardé dans le temps, cette méthode est déconseillée, à cause des "ghost" units (unités remove du jeu mais pas du groupe).
Un ForGroup ne les énumère pas, mais il devient de plus en plus lent en fonction du nombre de ghost units qu'il contient, ainsi que vraisemblablement toutes les autres opérations sur le group.
Par contre elles seront énumérées avec cette loop.
FirstOfGroup retournera null avec un telle unité, et donc la loop faillira, car elle se terminera avant l'heure dans le cas très probable ou la ghost unit n'était pas la dernière à être énumérée dans la loop.

Mais pour les group que l'on a besoin de garder dans le temps j'ai créé une autre structure de donnée ici : http://www.hiveworkshop.com/forums/jass-resources-412/snippet-unitll-209540/
(un peu de pub ne peut pas faire de mal)
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Crowolf
Animateur


Inscrit le: 21 Avr 2008
Messages: 1607
Sujets: 81
Spécialité en worldedit: Utiliser le travail des autres
Médailles: 3 (En savoir plus...)
Grand décorateur (Quantité : 2) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 14/05/12 16:59    Sujet du message: Citer

Ok, donc la méthode plus haut pour des sorts et la tienne pour d'autres systèmes.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7146
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 14/05/12 17:05    Sujet du message: Citer

Bah l'exemple principal que j'ai donné en démo est un spell ^^
J'ai même d'ailleurs obtenu ma médaille pour ce sort foireux :p
C'est juste quand on a besoin de garder le "group" dans le temps, maintenant il est vrai que la grande majorité des spells custom se font de façon instantanés à l'event et basta.
Après rien ne te force à l'utiliser bien sûr, en toute objectivité (oupa) je trouves UnitLL super sexy à utiliser, même s'il faut comprendre les listes chaînées et comment les utiliser en vJass.
Cela dit, la plupart des opérations inhérentes aux linked lists sont gérées de façon transparente par le code de UnitLL.
Y'a aussi quelques ajouts sympatoches par rapport au group, tel que addUnit qui retourne true ou false, selon si l'unité a été ajoutée ou non, idem pour removeUnit.
Le très utile .count qui permet de savoir combien d'unités contient un groupe à tout moment, etc.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
Montrer les messages depuis:   
Poster un nouveau sujet   Répondre au sujet    Worldedit Index du Forum -> Aide sur les déclencheurs Toutes les heures sont au format GMT + 1 Heure
Page 1 sur 1
La question posée dans ce topic a été résolue !

 
Sauter vers:  
Vous ne pouvez pas poster de nouveaux sujets dans ce forum
Vous ne pouvez pas répondre aux sujets dans ce forum
Vous ne pouvez pas éditer vos messages dans ce forum
Vous ne pouvez pas supprimer vos messages dans ce forum
Vous ne pouvez pas voter dans les sondages de ce forum


Powered by phpBB © 2001, 2005 phpBB Group
Traduction par : phpBB-fr.com