Inscrit le: 21 Avr 2008 Messages: 1607 Sujets: 81 Spécialité en worldedit: Utiliser le travail des autres Médailles: 3 (En savoir plus...)
Posté le: 12/05/12 23:43 Sujet du message: Problème Special effect - chemin, library xe?...
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 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.
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
//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 = thistype40;GetTimerData40;GetExpiredTimer40;)))
if pulse > 0 then
call DestroyEffect40;AddSpecialEffectTarget40;FX_CASTER, .caster, FX_ATTCH))
set pulse = pulse - 1
set temp = this
call GroupEnumUnitsInRange40;ENUM_GROUP, .x, .y, Range40;.lvl), function Data.VictimFilter)
static method VictimFilter takes nothing returns boolean
local unit u = GetFilterUnit40;)
local heal h
call BJDebugMsg40;GetUnitName40;u))
if IsValidTarget40;u, temp) then
set h = heal.create40;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 GetSpellAbilityId40;41; == SPELL_ID then
set this = thistype.Create40;GetTriggerUnit40;41;, GetUnitX40;GetTriggerUnit40;41;41;, GetUnitY40;GetTriggerUnit40;41;41;41;
endif
return false
endmethod
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...)
Posté le: 13/05/12 16:33 Sujet du message: Re: Problème Special effect - chemin, library xe?...
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. _________________
Inscrit le: 21 Avr 2008 Messages: 1607 Sujets: 81 Spécialité en worldedit: Utiliser le travail des autres Médailles: 3 (En savoir plus...)
Posté le: 14/05/12 16:40 Sujet du message:
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. _________________
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...)
Posté le: 14/05/12 16:48 Sujet du message:
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.
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...)
Posté le: 14/05/12 17:05 Sujet du message:
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. _________________
Page 1 sur 1 La question posée dans ce topic a été résolue !
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