Ces actions sont effectuées 200 fois par seconde pour chaque héros slidant. La fréquence du périodique n'est pas importante, il faut juste savoir qu'il est très élevé et c'est pourquoi je cherche à l'optimiser au maximum. Il y a deux moyens pour l'optimiser : diminuer le leak (sil y en a) et diminuer les calculs (pour soulager le processeur). Il n'est plus la peine de parler du leak car il n'y en a tout simplement pas (plus). Quant au processeur, je me suis dit que les fonctions Sinus et Cosinus sont compliquées et qu'elles le font donc beaucoup bosser, bien plus que ne le feraient des additions ou des multiplications.
J'ai donc pensé à stocker le résultat des calculs de cosinus et de sinus dans des tableaux.
On ne peut bien sûr pas rentrer les résultats pour tous les angles, car il y en a beaucoup (normalement une infinité mais pas en programmation), vraiment très beaucoup. Il faut donc arrondir l'angle.
Il y a 360 degrés pour faire un tour complet, j'ai donc pensé au fait que 360 * 20 = 7200 < 8192. J'ai donc décidé de donner une précision au vingtième de degré près, ce qui est très satisfaisant je pense.
Je crée donc deux tableaux nommés COSINUS et SINUS qui seront utilisés comme des fonctions :
COSINUS[ angle ] -> fonction cosinus prenant un angle en paramètre.
La différence est que l'angle donné est sous forme d'entier et que l'unité est le vingtième de degré.
Déclo initialisant COSINUS et SINUS : (utilisation d'un périodique car on ne peut pas tout faire d'un coup)
Jass:
globals
real array SINUS
real array COSINUS
private integer id = 0
private real x = 0.
private integer nbExecutions = 0
endglobals
function Trig_cosinus_sinus_Actions takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= 1000 or x >= 360.
set SINUS[ id ] = SinBJ( x )
set COSINUS[ id ] = CosBJ( x )
set id = id + 1
set x = id * 0.05
set i = i + 1
endloop
if x >= 360. then
call DisableTrigger( GetTriggeringTrigger() )
call EnableTrigger( gg_trg_sliding ) //ici on active le slide
endif
endfunction
//===========================================================================
function InitTrig_cosinus_sinus takes nothing returns nothing
set gg_trg_cosinus_sinus = CreateTrigger( )
call TriggerAddAction( gg_trg_cosinus_sinus, function Trig_cosinus_sinus_Actions )
call TriggerRegisterTimerEvent( gg_trg_cosinus_sinus, 0.0001, true )
endfunction
Afin de comparer la différence d'utilisation du processeur, j'amplifie la "dose" de calcul à faire en faisant slider 100 unités, et en utilisant un périodique 5 fois plus élevé (période 0.001 s).
Création des 100 unités :
Jass:
globals
unit array udg_mobs
constant integer NB_MOBS = 100
endglobals
function Trig_create_monsters_Actions takes nothing returns nothing
local real x
local real y
local real minX = GetRectMinX( gg_rct_spawn_mobs )
local real maxX = GetRectMaxX( gg_rct_spawn_mobs )
local real minY = GetRectMinY( gg_rct_spawn_mobs )
local real maxY = GetRectMaxY( gg_rct_spawn_mobs )
local integer i
set i = 0
loop
exitwhen i >= NB_MOBS
set x = GetRandomReal( minX, maxX )
set y = GetRandomReal( minY, maxY )
set udg_mobs[ i ] = CreateUnit( Player( 0 ), 'hpea', x, y, GetRandomDirectionDeg() )
set i = i + 1
endloop
//===========================================================================
function InitTrig_create_monsters takes nothing returns nothing
set gg_trg_create_monsters = CreateTrigger( )
call TriggerAddAction( gg_trg_create_monsters, function Trig_create_monsters_Actions )
endfunction
Test de l'ancien déclo de slide :
Jass:
globals
constant real SLIDE_SPEED = 0.01
endglobals
function Trig_sliding_Actions takes nothing returns nothing
local real angle
local real newX
local real newY
local integer i
set i = 0
loop
exitwhen i >= NB_MOBS
set angle = Deg2Rad( GetUnitFacing( udg_mobs[ i ] ) )
set newX = GetUnitX( udg_mobs[ i ] ) + SLIDE_SPEED * Cos( angle )
set newY = GetUnitY( udg_mobs[ i ] ) + SLIDE_SPEED * Sin( angle )
call SetUnitX( udg_mobs[ i ], newX )
call SetUnitY( udg_mobs[ i ], newY )
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_sliding takes nothing returns nothing
set gg_trg_sliding = CreateTrigger( )
call DisableTrigger( gg_trg_sliding )
call TriggerAddAction( gg_trg_sliding, function Trig_sliding_Actions )
call TriggerRegisterTimerEvent( gg_trg_sliding, 0.001, true )
endfunction
100 unités, periode 0.001 s, avec calcul de cosinus/sinus :
proc 22~23%, fps ~51
Si on désactive les fonctions SetUnitX et Y :
proc 15~16%, fps 63~65
Test du nouveau déclo de slide :
Jass:
globals
constant real SLIDE_SPEED = 0.01
endglobals
function Trig_sliding_Actions takes nothing returns nothing
local integer angle
local real newX
local real newY
local integer i
set i = 0
loop
exitwhen i >= NB_MOBS
set angle = R2I( GetUnitFacing( udg_mobs[ i ] ) * 20 )
set newX = GetUnitX( udg_mobs[ i ] ) + SLIDE_SPEED * COSINUS[ angle ]
set newY = GetUnitY( udg_mobs[ i ] ) + SLIDE_SPEED * SINUS[ angle ]
call SetUnitX( udg_mobs[ i ], newX )
call SetUnitY( udg_mobs[ i ], newY )
set i = i + 1
endloop
endfunction
//===========================================================================
function InitTrig_sliding takes nothing returns nothing
set gg_trg_sliding = CreateTrigger( )
call DisableTrigger( gg_trg_sliding )
call TriggerAddAction( gg_trg_sliding, function Trig_sliding_Actions )
call TriggerRegisterTimerEvent( gg_trg_sliding, 0.001, true )
endfunction
100 unités, periode 0.001 s, sans calcul de cosinus/sinus (préeffectué) :
proc 22%, fps ~51
Si on désactive les fonctions SetUnitX et Y :
proc 13~16%, fps 63~65
Le résultat final n'est pas celui attendu, on passe de 22-23% à 22%, super utile !
Il semblerait donc que les fonctions Cos et Sin ne soient pas si compliquées que ça...
J'aimerais que quelqu'un qui en sait plus à ce sujet éclaire ma lanterne _________________
Inscrit le: 23 Aoû 2007 Messages: 7143 Sujets: 147 Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance Médailles: 2 (En savoir plus...)
Posté le: 12/03/09 21:00 Sujet du message:
J'avais ouvert un sujet similaire, en gros blizzard a optimisé les fonctions cos et sin, cela doit déjà être des lectures de tableaux, j'avais testé avec les fonctions custom natives de japi StopWatch... qui permettent de savoir le temps d'éxécution d'un code.
Inscrit le: 13 Jan 2009 Messages: 550 Sujets: 47 Spécialité en worldedit: La partie déclencheurs sauf le GUI.
Posté le: 12/03/09 21:08 Sujet du message:
Tu confirmes donc ce qui a été dit il y a peu de temps par [Master] :
[Master] a écrit:
Cosinus n'est pas toujours un calcul. Parfois (et ça semble être le cas ici) c'est juste un tableau géant et la fonction ne fait qu'une simple lecture dans ce tableau.
N'aurais-je donc qu'essayé de faire une optimisation qui aura déjà été faite par blizzard ? C'est trop marrant
Je suis content, j'ai appris quelque chose de très intéressant aujourd'hui
Là je suis à court d'idées pour améliorer mon déclo de slide, ce qui est à la fois une mauvaise et une bonne nouvelle _________________
Inscrit le: 13 Oct 2007 Messages: 994 Sujets: 25 Spécialité en worldedit: Codeur
Posté le: 12/03/09 21:52 Sujet du message:
Une chose que tu pourrais faire c'est prendre en compte le temps entre 2 exécutions du déclencheur. Parce que si a la fin de ta carte tu te rends compte que ça consomme trop et qu'il faut augmenter un peu le temps et bah tes glissades seront plus lente et il faudra que tu changes aussi la vitesse.
Sinon si tu veux vraiment optimiser à mort (ce qui n'est pas forcement utile tant que ta carte n'est pas ralentie), tu peux éviter l'utilisation des 2 variables newX et newY en plaçant directement les calculs dans les fonctions SetUnitX et SetUnitY.
De la même manière tu peux te passer de la variable angle. Ton code sera indigeste et vomitif mais après tu pourras pas vraiment faire mieux pour la rapidité. _________________
- La théorie c'est quand rien ne fonctionne mais tout le monde sait pourquoi.
- La pratique c'est quand tout fonctionne mais personne ne sait pourquoi.
- Chez moi la théorie et la pratique sont réunies, rien ne fonctionne et personne ne sait pourquoi.
Inscrit le: 23 Aoû 2007 Messages: 7143 Sujets: 147 Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance Médailles: 2 (En savoir plus...)
Posté le: 12/03/09 22:04 Sujet du message:
/Speed freak on
En toute logique utiliser des variables globales devrait être plus performant (pas de temps d'allocation/libération de la mémoire).
Faut voir aussi si la multiplication ou division par une constant real n'est pas plus rapide que la fonction Deg2Rad, enfin j'en doute étant donné que c'est une fonction native et on a vu comment Blizzou s'en est soucié pour Cos et Sin, on peut donc espérer de même pour les autres fonctions trigonométriques.
EDIT : Ouep en fait pas besoin de variable.
Pour garder ton code maintenable tu peux utiliser l'inlining (un appel de fonction d'une seule ligne est remplacée par son contenant, quand tu sauvegardes en mode debug off)
/Speed freak off
200 fois par seconde, uber utile, l'oeil humain ne peut faire une telle distinction, ou alors tu es la personne qui a inspiré la série The Sentinel. _________________
Inscrit le: 13 Jan 2009 Messages: 550 Sujets: 47 Spécialité en worldedit: La partie déclencheurs sauf le GUI.
Posté le: 12/03/09 22:58 Sujet du message:
ça c'est la théorie, et je fais confiance avant tout à ce que je vois. Même avec une fréquence de 200 fois par seconde, ce n'est pas parfaitement fluide, mais au delà je ne vois plus aucune différence. Le déplacement d'une unité de façon normale, telle que l'a prévu le jeu, ça c'est vraiment fluide. Je n'ai aucune explication à vous donner, mais on dirait que je suis le seul à avoir testé ça...
[Master] a écrit:
Une chose que tu pourrais faire c'est prendre en compte le temps entre 2 exécutions du déclencheur. Parce que si a la fin de ta carte tu te rends compte que ça consomme trop et qu'il faut augmenter un peu le temps et bah tes glissades seront plus lente et il faudra que tu changes aussi la vitesse.
C'est pendant l'utilisation qu'on se rend compte si ça consomme trop, pas à la fin de la carte. Ce serait plus adapté pour le leak.
[Master] a écrit:
Sinon si tu veux vraiment optimiser à mort (ce qui n'est pas forcement utile tant que ta carte n'est pas ralentie), tu peux éviter l'utilisation des 2 variables newX et newY en plaçant directement les calculs dans les fonctions SetUnitX et SetUnitY.
De la même manière tu peux te passer de la variable angle. Ton code sera indigeste et vomitif mais après tu pourras pas vraiment faire mieux pour la rapidité.
Je ne peux pas me passer de la variable angle, car sinon il faudrait que je calcule l'angle deux fois.
Je pourrais me passer de newX et newY mais je n'en verrais pas l'intérêt puisque ce qui fait bosser le proc, c'est avant tout les calculs effectués et les appels des différentes fonctions. A côté, la création des deux variables newX et newY est négligeable. A moins qu'il n'y ait pas que le taux d'utilisation du proc à prendre en compte.
Les calculs sont multipliés par 50 par rapport à lorsque 10 héros slident en même temps. (10 fois plus d'unités et fréquence 5 fois plus élevée)
Autrement dit, mon déclo de slide fait peu bosser le proc au final et ne ralentit rien du tout.
Si je veux encore l'améliorer aujourd'hui, c'est surtout pour les déclo faisant bouger des unités ennemies selon un déplacement personnalisé que l'on aura choisi (cercles, hélices, etc), où les unités sont alors plus nombreuses (dans ce cas je me contente d'une période de 0.02 s). Les actions contenues dans ce type de déclo sont similaires au slide. _________________
J'ai déjà testé et beaucoup d'autres l'ont fait: à 0.04 c'est fluide sauf sur internet à cause du temps de synchronisation, auquel cas 0.03 permet de corriger la chose.
Tu n'as peut être pas changé la valeur de SLIDE_SPEED, donc évidemment cela se déplace moins vite. _________________
Inscrit le: 13 Jan 2009 Messages: 550 Sujets: 47 Spécialité en worldedit: La partie déclencheurs sauf le GUI.
Posté le: 14/03/09 15:16 Sujet du message:
Ayane a écrit:
J'ai déjà testé et beaucoup d'autres l'ont fait: à 0.04 c'est fluide sauf sur internet à cause du temps de synchronisation, auquel cas 0.03 permet de corriger la chose.
On doit vraiment pas avoir la même conception de ce qu'est la fluidité.
Je viens d'ailleurs de montrer le slide à 0,005 à ma copine (qui n'a jamais joué à war3 de sa vie), jlui demande si c'est fluide, elle me dit "ben oui". Puis je passe à 0,04 et lui redemande si c'est fluide : "Non, ça fait mal aux yeux"
Je n'ai donc pas des yeux de "sentinel" ou chépa quoi. _________________
Inscrit le: 23 Aoû 2007 Messages: 7143 Sujets: 147 Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance Médailles: 2 (En savoir plus...)
Posté le: 14/03/09 16:52 Sujet du message:
@Profet :Peut être oui mais il faut tester, en gros c'est ce que j'avais dit
@Master : et tu as changé l'offset de déplacement en conséquence ?
De toute façon personnellement même si différence il y a, je ne pense pas que l'on puisse vraiment se permettre un si faible périodique avec le jass.
0.03 me convient tout à fait, ou à la rigueur 0.02
Tant mieux pour toi si cela te convient néammoins. _________________
Toutes les heures sont au format GMT + 1 Heure Aller à la page 1, 2Suivante
Page 1 sur 2 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