Posté le: 12/09/09 16:24 Sujet du message: A la recherche d'un créateur de creeps peu gourmand...
Bon. Maintenant que Stars 1.16 est presque fini, en dehors des tests, je me remet doucement à RC601. Et je viens de me rendre compte que mon système de création des creeps est...gourmand, puisqu'il utilise de nombreux timers.
Je voudrais savoir si quelqu'un peut m'aider à l'optimiser.
Les fonctions de ce système sont les suivantes:
-Quand un héro "joueur" entre dans l'une des pièces de RC601 (une région donc), des creeps doivent être générés rapidement.
-Les creeps sont envoyés en patrouille dans cette région (uniquement celle-ci)
-Un compteur d'expiration leur est ajouté pour limiter les leaks.
-Ce compteur est suspendu lorsqu'une unité joueur arrive à une certaine portée du creeps.
-Périodiquement, un déclencheur vérifie qu'il y a des joueurs dans chaque région; sinon tout les creeps sont supprimés de ces régions.
Voilà les déclencheurs (exemples)
Créateur d'unités pour certaines régions
Secret:
Jass:
scope sghoul initializer init
//=================================================
globals
private constant real TIMEOUTSUMMON = 1.00
private constant real TIMEOUTPATROL = 10.00
private constant real LIFESPAN = 60.00
private constant real AOE = 400.00
private constant integer OWNERCREEPS = 'A00M'
private constant integer LIGHT = 'o000'
endglobals
//=================================================
private function filtercreeps takes nothing returns boolean
return GetUnitAbilityLevel(GetFilterUnit(),OWNERCREEPS)>=1
endfunction
//=================================================
private function filterhero takes nothing returns boolean
return IsUnitType(GetFilterUnit(),UNIT_TYPE_HERO)==true
endfunction
//=================================================
private function filter takes nothing returns boolean
return IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==false and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false and IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD)==false and GetOwningPlayer(GetFilterUnit())!=Player(PLAYER_NEUTRAL_PASSIVE) and GetOwningPlayer(GetFilterUnit())!=Player(8)
endfunction
//=================================================
private struct strpatrol
unit creeps
real xmin
real xmax
real ymin
real ymax
group g
unit filtered
player pl
endstruct
//=================================================
private function bouclepatrol takes nothing returns nothing
local timer t = GetExpiredTimer()
local strpatrol dat = GetTimerData(t)
local real x1 = GetUnitX(dat.creeps)
local real y1 = GetUnitY(dat.creeps)
local real x2 = GetRandomReal(dat.xmin,dat.xmax)
local real y2 = GetRandomReal(dat.ymin,dat.ymax)
local integer n = 0
if GetUnitState(dat.creeps,UNIT_STATE_LIFE)>0 then
set dat.g = CreateGroup()
call GroupEnumUnitsInRange(dat.g,x1,y1,AOE,Condition(function filter))
loop
set dat.filtered = FirstOfGroup(dat.g)
exitwhen dat.filtered == null
call GroupRemoveUnit(dat.g, dat.filtered)
if IsUnitEnemy(dat.filtered,dat.pl) == true then
set n = n + 1
endif
endloop
call DestroyGroup(dat.g)
if n > 0 then
call UnitPauseTimedLife(dat.creeps,true)
else
call UnitPauseTimedLife(dat.creeps,false)
call IssuePointOrder(dat.creeps,"attack",x2,y2)
endif
else
call DestroyGroup(dat.g)
call ReleaseTimer(t)
call dat.destroy()
endif
endfunction
//=================================================
private function inipatrol takes unit creeps, real xmin, real ymin, real xmax, real ymax returns nothing
local timer t = NewTimer()
local strpatrol dat = strpatrol.create()
set dat.creeps = creeps
set dat.xmin = xmin
set dat.xmax = xmax
set dat.ymin = ymin
set dat.ymax = ymax
set dat.pl = GetOwningPlayer(dat.creeps)
set creeps = null
call SetTimerData(t, dat)
call TimerStart (t, TIMEOUTPATROL, true, function bouclepatrol )
endfunction
//=================================================
private struct strsummon
rect zone
player pl
integer numero
group g1
group g2
integer i
endstruct
//=================================================
private function bouclesummon takes nothing returns nothing
local timer t = GetExpiredTimer()
local strsummon dat = GetTimerData(t)
local real xmin = GetRectMinX(dat.zone)
local real ymin = GetRectMinY(dat.zone)
local real xmax = GetRectMaxX(dat.zone)
local real ymax = GetRectMaxY(dat.zone)
local real x = GetRandomReal(xmin,xmax)
local real y = GetRandomReal(ymin,ymax)
local unit creeps = null
local integer i = 0
local integer n = 0
local integer id = udg_creeps_type_ghoul[GetRandomInt(1,2)]
set dat.g1 = CreateGroup()
call GroupEnumUnitsInRect(dat.g1,dat.zone,Condition(function filtercreeps))
set n = CountUnitsInGroup(dat.g1)
call DestroyGroup(dat.g1)
if udg_c_summon[dat.numero]==true and dat.i <= udg_c_max[dat.numero] then
set dat.i = dat.i +1
if n<=udg_c_max[dat.numero] then
set dat.g2 = CreateGroup()
call GroupEnumUnitsInRange(dat.g2,x,y,AOE,Condition(function filterhero))
if CountUnitsInGroup(dat.g2)<= 0 and GetTerrainCliffLevel(x,y)<=2 then
call DestroyGroup(dat.g2)
set creeps = CreateUnit(dat.pl,id,x,y,0.00)
call UnitApplyTimedLife(creeps,'BTLF', LIFESPAN)
call UnitAddAbility(creeps,OWNERCREEPS)
call inipatrol(creeps,xmin,ymin,xmax,ymax)
if GetRandomInt(1,100)<=10 then
set creeps = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),LIGHT,x,y,0.00)
call UnitApplyTimedLife(creeps,'BTLF', LIFESPAN)
call UnitAddAbility(creeps,OWNERCREEPS)
endif
endif
endif
call DestroyGroup(dat.g2)
else
call DestroyGroup(dat.g2)
set creeps = null
call ReleaseTimer(t)
call dat.destroy()
endif
call DestroyGroup(dat.g1)
call DestroyGroup(dat.g2)
set creeps = null
endfunction
//=================================================
private function inisummon takes rect zone returns nothing
local timer t = NewTimer()
local strsummon dat = strsummon.create()
local integer i = 0
set dat.i = 0
set dat.zone = zone
set dat.pl = Player(11)
loop
set i = i + 1
exitwhen i >udg_c_nombre
if dat.zone == udg_c_rect[i] then
set dat.numero = i
endif
endloop
call SetTimerData(t, dat)
call TimerStart (t, TIMEOUTSUMMON, true, function bouclesummon )
endfunction
//=================================================
private function Conditions takes nothing returns boolean
return IsUnitType(GetTriggerUnit(),UNIT_TYPE_HERO)==true and GetPlayerController(GetOwningPlayer(GetTriggerUnit())) == MAP_CONTROL_USER
endfunction
//=================================================
private function Actions takes nothing returns nothing
local unit entering = GetTriggerUnit()
local integer i = 0
local real x = GetUnitX(entering)
local real y = GetUnitY(entering)
local player pl = GetOwningPlayer(entering)
loop
set i = i + 1
exitwhen i > udg_c_nombre
if RectContainsUnit(udg_c_rect[i],entering) then
set udg_c_summon[i]=true
set entering = null
set pl = null
call inisummon(udg_c_rect[i])
return
endif
endloop
set entering = null
set pl = null
endfunction
//=================================================
public function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterEnterRectSimple( t, gg_rct_Logistic_Sector_Material_1)
call TriggerRegisterEnterRectSimple( t, gg_rct_Logistic_Sector_Material_2)
call TriggerRegisterEnterRectSimple( t, gg_rct_Logistic_Sector_Material_3)
call TriggerRegisterEnterRectSimple( t, gg_rct_Logistic_Sector_Material_4)
call TriggerRegisterEnterRectSimple( t, gg_rct_Logistic_Sector_Material_5)
call TriggerRegisterEnterRectSimple( t, gg_rct_Logistic_Sector_Material_6)
call TriggerRegisterEnterRectSimple( t, gg_rct_BCL_Test_Room)
call TriggerAddCondition(t, Condition(function Conditions))
call TriggerAddAction(t, function Actions)
endfunction
endscope
Sécurité: suppression des creeps dans les zones sans joueurs.
Secret:
Jass:
scope TimerSetRectFlagsOff initializer init
//=================================================
globals
private constant real TIMEOUT = 30.00
private constant integer OWNERCREEPS = 'A00M'
endglobals
//=================================================
private function filtersummoned takes nothing returns boolean
return IsUnitType(GetFilterUnit(),UNIT_TYPE_SUMMONED)==true
endfunction
//=================================================
private function filterhero takes nothing returns boolean
return GetPlayerController(GetOwningPlayer(GetFilterUnit())) == MAP_CONTROL_USER
endfunction
//=================================================
private function boucle takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = 0
local integer n = 0
local unit filtered
local group g1 = CreateGroup()
local group g2 = CreateGroup()
loop
set i = i + 1
exitwhen i > udg_c_nombre
set g1 = CreateGroup()
set n = 0
call GroupEnumUnitsInRect(g1,udg_c_rect[i],Condition(function filterhero))
loop
set filtered = FirstOfGroup(g1)
exitwhen filtered == null
call GroupRemoveUnit(g1, filtered)
set n = n + 1
endloop
call DestroyGroup(g1)
if n <= 0 then
set udg_c_summon[i]=false
set g2 = CreateGroup()
call GroupEnumUnitsInRect(g2,udg_c_rect[i],Condition(function filtersummoned))
loop
set filtered = FirstOfGroup(g2)
exitwhen filtered == null
call GroupRemoveUnit(g2, filtered)
if GetUnitAbilityLevel(filtered,OWNERCREEPS)>=1 then
call RemoveUnit(filtered)
endif
endloop
call DestroyGroup(g2)
endif
endloop
call DestroyGroup(g1)
call DestroyGroup(g2)
set filtered = null
set g1 = null
set g2 = null
endfunction
//=================================================
private function Actions takes nothing returns nothing
local timer t = NewTimer()
call TimerStart (t, TIMEOUT, true, function boucle )
endfunction
//=================================================
public function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEventSingle( t, 1.00 )
call TriggerAddAction(t, function Actions)
endfunction
endscope
Parce que je me suis rendu compte que si je créé par exemple une zone où une cinquantaine de creeps sont générés, ça consomme des ressources PC assez monstrueuses :/
Or la carte est prévue pour huit joueurs, donc si chaque héros est dans une pièce différente, ça va faire une grosse saturation.
Je suis preneur de n'importe quel autre système si vous en avez, tant qu'il respecte les conditions données au début du message.
Merci d'avance!
Notes: la variable globale LIGHT sert simplement à éclairer la zone de temps en temps.
La variable OWNERCREEPS fait en fait simplement office de booléen local. En effet, j'utilise pour d'autres systèmes toutes les classifications (Ancien, tauren etc...) et je trouve plus souple d'ajouter une compétence dummy aux unités pour les trier rapidement.
udg_c_rect[] désigne les régions de la carte, donc les pièces. _________________
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: 12/09/09 16:29 Sujet du message:
C'est juste une intuition ou alors un fait établi, t'entends quoi par "ressources PC", utilisation de la mémoire vive et/ou du processeur ?
Lag, fps en chute libre ? _________________
Ecran saccadé. Donc pas du leak, mais, sous Vista et le gestionnaire de tâches, UC Utilisé assez élevé, et surtout, Frozen Throne ralenti (images non affichées etc...) _________________
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: 12/09/09 16:52 Sujet du message:
Y'a pas mal de choses à faire pour normaliser le code aux standards actuel, mais je crois plutôt que cela vient de la création d'unités.
Y'a un nombre max possible de création de creeps ?
Quand un creep meurt, il laisse un cadavre ?
Si oui de combien est le temps de décomposition ? _________________
Il y a un nombre maximum de creeps, vérifié par la condition:
Jass:
dat.i <= udg_c_max[dat.numero]
(Pour chaque région j'ai affecté plusieurs données: nom, nombre de creeps, etc..)
Les cadavressont présents pendant 30 secondes maximum, après quoi ils sont supprimés, et une unité nouvelle apparaît (résurrection des humains en zombies et des zombies en goules).
Os et Annulation: 30 sec
Chair: 10
Mais le problème ne vient pas de là, pendant mes tests, le problème a eu lieu sans que je ne tue aucun ennemi, mais une fois l'ensemble des creeps générés. Je me suis demandé si ça venait du timer qui fait patrouiller les creeps, (un par creeps), mais je n'ai trouvé nul part de messages indiquant avec 100% de certitudes qu'il fallait mieux un timer pour tout les creeps plutôt qu'un timer par creeps.
J'envisageais de refondre le système en utilisant des Tables, mais en dehors d'une lisibilité et d'une implémentation meilleures, je ne pense pas que ça changerait le problème. _________________
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: 12/09/09 17:19 Sujet du message:
Oh Table est le cadet de tes soucis ici, et désormais ce n'est plus aussi nécessaire qu'avant avec l'apparition des hashtables.
Je parlais plutôt de recycler les groups, coder dans l'enum, etc.
Je jetterais un œil plus attentif à ton code plus tard. _________________
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: 12/09/09 21:18 Sujet du message:
Apocalypse a écrit:
Merci mon Maître. (Faudra que je pense à gagner le droit d'avoir comme rang "Padawan de TB " un jour :p)
N'en fait pas trop quand même ...
Faudrait que tu m'envoies la map, j'aimerais bien comparer avec l'utilisation de mon "système" de timer, même si encore une fois j'ai un gros doute que ca soit cela, au moins j'aurais confirmation avant de poursuivre les investigations. _________________
Je doute fort que ce soit la raison mais tes timers locaux ne sont pas nullifiés =o
Aussi, la création de groupes pour des actions faites instantanément est superflue; utilises plutôt GroupClear à chaque fois
Sinon, dans le cas de huit joueurs dans huit pièces différentes contenant chacune une cinquantaine de creeps, on arrive à 400 unités. Dans une partie mêlée de Warcraft 3 avec 12 joueurs, à raison de deux de nourriture par unité on arrive à environ 300 unités maximum si je me souviens. Même si je doute que le problème se limite à ça, on touche un peu aux nombres maximums prévus par Blizzou ici, surtout avec une struct par unité. Pourquoi ne pas en faire plutôt une par groupe de creeps ? _________________
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/09/09 20:55 Sujet du message:
@Bantas :
Pas besoin de nullifier les variables locales de timer car il utilise TimerUtils, ou autrement dit les timers ne sont pas détruits mais recyclés.
Tu as besoin de nullifier une variable type handle ou tous les sous types tel qu'un timer, uniquement si l'objet ainsi référencé a été détruit.
GroupClear est superflu, on peut utiliser un groupe déjà créé et directement utiliser GroupEnum... _________________
Ok pour envoyer la carte, mais elle est trop grosse pour le filtre de ce site
Le nombre d'unités joue effectivement, mais là ça me pose un gros problème: pour avoir un décor interactif, j'utilise des unités en guise de destructibles . Donc là oui clairement il y en a beaucoup :/ _________________
Interactif: plus facile de faire bouger le décor grâce au gravity gun , grenades et autres avec des unités plutôt que des destructibles. (Genre ne serait-ce que pour SetUnitX et Y). _________________
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/09/09 19:41 Sujet du message:
Avec ta map de test et une armée de paladin imba cheatés j'ai pas le moindre problème de performance.
Dans le trigger globals j'ai édité à chaque fois la variable déployée de set façon.
Toutes les heures sont au format GMT + 1 Heure Aller à la page 1, 2, 3, 4Suivante
Page 1 sur 4 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