Inscrit le: 14 Avr 2011 Messages: 1846 Sujets: 119 Spécialité en worldedit: fonctions paramétriques, équation de mouvement.
Posté le: 27/06/12 23:34 Sujet du message: [vjass] JumpingUnit
Nom de la fonction : JumpingUnit Créateur : Fulldragon
Fonctions requises : TimerUtils Code :
Jass:
//===================================================================================
// JumpingUnit by Fulldragon
//===================================================================================
//
// API :
//
// call JumpUnit(whichUnit, height, time)
//
// Requires :
//
// TimerUtils - Made by Vexorian
//
// Commentary
//
// You can use it without credits. it's totaly free.
//
//===================================================================================
// gl & hf
//===================================================================================
library JumpingUnit uses TimerUtils
globals
private timer T = CreateTimer()
private integer I = 0
private Parabole array P
endglobals
struct Parabole
unit u
real a
real b
real c
real incrementation
real x = 0
real max
static method Jumping takes nothing returns nothing
local integer i = 0
local Parabole p
loop
exitwhen i == I
set p = P[i]
set p.x = p.x + p.incrementation
if p.x < p.max then
call SetUnitFlyHeight(p.u, p.a * Pow(p.x, 2) + p.b * p.x + p.c, 0)
set i = i + 1
else
call p.destroy()
set I = I - 1
set P[i] = P[I]
call SetUnitFlyHeight(p.u, 0, 0.01)
if I == 0 then
call PauseTimer(T)
endif
endif
endloop
endmethod
endstruct
function JumpUnit takes unit jumper, real height, real time returns nothing
local real a = (height * 4)/ (-1 * Pow(time, 2))
local real b = -1 * a * time
local real c = GetUnitFlyHeight(jumper)
local Parabole p = Parabole.create()
set P[I] = p
set P[I].u = jumper
set P[I].a = a
set P[I].b = b
set P[I].c = c
set P[I].incrementation = 0.05
set P[I].max = time
set I = I + 1
if I == 1 then
call TimerStart(T, 0.05, true, function Parabole.Jumping)
endif
endfunction
endlibrary
Utilisation : Dans un escape poru sauter par dessus un obstacle.
Copyright : Totalement libre pas besoin de me citer où que ça soit.
Remarques : Attention SetUnitFlyHeight bug quelque peu sur la définition d'altitude. Il faut ajouter/enlever la compétence corbeau 'Amrf' pour pouvoir changer correctement la hauteur d'une unité lors de sa création. _________________
22:27:43<Seiraw> Bah y a deux genre de personnes
22:27:57<Seiraw> les soumis et les soumises
Dernière édition par kungfu-sheep le 29/06/12 11:51; édité 5 fois
* Pour la ressource en géneral, je pense que c'est correct pour une première :p mais bon j'ai regardé vite fait.
* Tu peux faire de ta fonction une static methode create avec un allocate dedans.
*
Jass:
call SetTimerData(GetExpiredTimer(), p)
et
Jass:
call PauseTimer(GetExpiredTimer())
me semblent être inutiles
* Actuellement le saut est purement esthétique, il ne permet pas de passer par dessus des units ayant une immolation ( unité de base des maze / escape / slide ). Il faudrait que tu rende l'unit invulnérable.
* Peut être pas la meilleur solution mais sa devrait régler le problème du SetUnitFlyHeight.
Secret:
Jass:
library AutoFly /* v1.0.0.1
-Credits to Magtheridon96 and Bribe for code update
-Credits to Azlier for original
-thehelper.net/forums/showthread.php/139729-AutoFly
*************************************************************************************
*
* Makes SetUnitFlyHeight possible
*
*************************************************************************************
*
* */uses/*
*
* */ UnitIndexer /* hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*
************************************************************************************/
private function i takes nothing returns boolean
return UnitAddAbility(GetIndexedUnit(), 'Amrf') and UnitRemoveAbility(GetIndexedUnit(), 'Amrf')
endfunction
private module Init
private static method onInit takes nothing returns nothing
call RegisterUnitIndexEvent(Condition(function i), UnitIndexer.INDEX)
endmethod
endmodule
private struct Inits extends array
implement Init
endstruct
endlibrary
EDIT : Merci d'utiliser mon template de présentation
EDIT 2 : Tu devrais te pencher un peux plus sur Timer Utils. Comme TB l'a dit tu ne sais pas encore l'utiliser. Je te passe une version qui me semble mieux que ton lien ( ou plus récente ) :
Secret:
Jass:
library TimerUtilsEx requires optional Table
/*************************************************
*
* TimerUtilsEx
* v2.1.0.2
* By Vexorian, Bribe & Magtheridon96
*
* Original version by Vexorian.
*
* Flavors:
* Hashtable:
* - RAM: Minimal
* - TimerData: Slow
*
* Array:
* - RAM: Maximal
* - TimerData: Fast
*
* All the functions have O(1) complexity.
* The Array version is the fastest, but the hashtable
* version is the safest. The Array version is still
* quite safe though, and I would recommend using it.
* The system is much slower in debug mode.
*
* Optional Requirement:
* - Table by Bribe
* - hiveworkshop.com/forums/showthread.php?t=188084
*
* API:
* ----
* - function NewTimer takes nothing returns timer
* - Returns a new timer from the stack.
* - function NewTimerEx takes integer i returns timer
* - Returns a new timer from the stack and attaches a value to it.
* - function ReleaseTimer takes timer t returns integer
* - Throws a timer back into the stack. Also returns timer data.
* - function SetTimerData takes timer t, integer value returns nothing
* - Attaches a value to a timer.
* - function GetTimerData takes timer t returns integer
* - Returns the attached value.
*
*************************************************/
// Configuration
globals
// Use hashtable, or fast array?
private constant boolean USE_HASH = false
// Max Number of Timers Held in Stack
private constant integer QUANTITY = 256
endglobals
private module Init
private static method onInit takes nothing returns nothing
static if not USE_HASH then
local integer i = QUANTITY
loop
set i = i - 1
set tT[i] = CreateTimer()
exitwhen i == 0
endloop
set tN = QUANTITY
elseif LIBRARY_Table then
set tb = Table.create()
endif
endmethod
endmodule
// JassHelper doesn't support static ifs for globals.
private struct Data extends array
static if not USE_HASH then
static integer array data
endif
static if LIBRARY_Table then
static Table tb = 0
else
static hashtable ht = InitHashtable()
endif
implement Init
endstruct
// Double free protection
private function ValidTimer takes integer i returns boolean
static if LIBRARY_Table then
return Data.tb.boolean[-i]
else
return LoadBoolean(Data.ht, i, 1)
endif
endfunction
private function Get takes integer id returns integer
debug if not ValidTimer(id) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to get data from invalid timer.")
debug endif
static if USE_HASH then
static if LIBRARY_Table then
return Data.tb[id]
else
return LoadInteger(Data.ht, id, 0)
endif
else
return Data.data[id - 0x100000]
endif
endfunction
private function Set takes integer id, integer data returns nothing
debug if not ValidTimer(id) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to attach data to invalid timer.")
debug endif
static if USE_HASH then
static if LIBRARY_Table then
set Data.tb[id] = data
else
call SaveInteger(Data.ht, id, 0, data)
endif
else
set Data.data[id - 0x100000] = data
endif
endfunction
function SetTimerData takes timer t, integer data returns nothing
call Set(GetHandleId(t), data)
endfunction
function GetTimerData takes timer t returns integer
return Get(GetHandleId(t))
endfunction
function NewTimerEx takes integer data returns timer
local integer id
if tN == 0 then
static if USE_HASH then
set tT[0] = CreateTimer()
else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: No Timers In The Stack! You must increase 'QUANTITY'")
return null
endif
else
set tN = tN - 1
endif
set id = GetHandleId(tT[tN])
static if LIBRARY_Table then
set Data.tb.boolean[-id] = true
else
call SaveBoolean(Data.ht, id, 1, true)
endif
call Set(id, data)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
function ReleaseTimer takes timer t returns integer
local integer id = GetHandleId(t)
local integer data = 0
// Pause the timer just in case.
call PauseTimer(t)
// Make sure the timer is valid.
if ValidTimer(id) then
// Get the timer's data.
set data = Get(id)
// Unmark handle id as a valid timer.
static if LIBRARY_Table then
call Data.tb.boolean.remove(-id)
else
call RemoveSavedBoolean(Data.ht, id, 1)
endif
//If it's not run in USE_HASH mode, this next block is useless.
static if USE_HASH then
//At least clear hash memory while it's in the recycle stack.
static if LIBRARY_Table then
call Data.tb.remove(id)
else
call RemoveSavedInteger(Data.ht, id, 0)
endif
// If the recycle limit is reached
if tN == QUANTITY then
// then we destroy the timer.
call DestroyTimer(t)
return data
endif
endif
//Recycle the timer.
set tT[tN] = t
set tN = tN + 1
//Tried to pass a bad timer.
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[TimerUtils]Error: Tried to release non-active timer!")
endif
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 28/06/12 10:23 Sujet du message:
[Mode chieur]
Mieux vaut n'appeler qu'une fois une réponse d'événement telle que GetExpiredTimer et la stocker dans une variable que de l'appeler plusieurs fois.
Lorsque l'on utilise la fonction Pow pour élever un nombre à une puissance connue, mieux vaut le faire manuellement. Donc ici ça donnerait time * time.
Certaines variables ne servent à rien, comme incrementation dans Jumping. Autant utiliser directement p.incrementation.
Tu peux utiliser thistype à la place de Parabole (bon je sais, ça sert à rien mais c'est plus bô ).
[/Mode chieur]
Ça serait bien que la fonction JumpingUnit renvoie p pour qu'ensuite on puisse utiliser des méthodes comme stop ou autre. Et l'inclure dans la structure serait une bonne habitude à prendre. Mais il faudra penser à ajouter une méthode destroy qui annule tout dans ce cas. Et rendre les attributs de la structure private serait nécessaire, ou du moins readonly.
Ensuite c'est vrai qu'utiliser CreateTimer lorsque l'on utilise ReleaseTimer ne sert pas à grand chose :p. De même que ReleaseTimer met déjà en pause les timers.
Tu ne libère jamais d'instance de structure avec la méthode destroy.
Dans Jumping, tu utilises SetTimerData alors que tu avais déjà défini la data tu timer comme étant p. Donc c'est inutile.
Lorsque l'on utilise des timers à si faible période, autant en n'utiliser qu'un comme dans l'exemple que je t'avais envoyé.
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: 28/06/12 16:43 Sujet du message:
Sapeur-Goblin a écrit:
Lorsque l'on utilise la fonction Pow pour élever un nombre à une puissance connue, mieux vaut le faire manuellement
Rien n'est moins sûr, on oublie trop souvent que le jass est un langage lentement interprété, et qu'il est souvent tout simplement impossible de faire mieux qu'une fonction native en terme de performance, c'est inhérent au jass.
Par ex j'avais essayé de remplacer la fonction Cos/Sin par une lecture de tableau, bah c'était l'utilisation de la fonction Cos/Sin qui était le plus efficace, alors que dans la plupart des "vrais" langages ça serait la lecture de tableau le grand gagnant.
Je parierais plutôt sur l'utilisation de Pow.
M'enfin cela n'a pas grande importance, mais si vous voulez tester, faites vous plaisir. _________________
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 28/06/12 16:50 Sujet du message:
Comment tester? Il pleins de petits trucs comme ça que j'aurais bien aimé tester, mais je ne sais pas comment faire.
Ça me paraîtrait quand même bizarre que Pow soit plus rapide qu'une multiplication... Parce que si on suit ta logique, l'appelle de fonction est aussi "interprété", non? _________________
Inscrit le: 14 Avr 2011 Messages: 1846 Sujets: 119 Spécialité en worldedit: fonctions paramétriques, équation de mouvement.
Posté le: 28/06/12 16:55 Sujet du message:
Sapeur-Goblin a écrit:
[Mode chieur]
Mieux vaut n'appeler qu'une fois une réponse d'événement telle que GetExpiredTimer et la stocker dans une variable que de l'appeler plusieurs fois.
fait
Citation:
Lorsque l'on utilise la fonction Pow pour élever un nombre à une puissance connue, mieux vaut le faire manuellement. Donc ici ça donnerait time * time.
déterminé inutile
Citation:
Certaines variables ne servent à rien, comme incrementation dans Jumping. Autant utiliser directement p.incrementation.
fait
Citation:
Ça serait bien que la fonction JumpingUnit renvoie p pour qu'ensuite on puisse utiliser des méthodes comme stop ou autre. Et l'inclure dans la structure serait une bonne habitude à prendre. Mais il faudra penser à ajouter une méthode destroy qui annule tout dans ce cas. Et rendre les attributs de la structure private serait nécessaire, ou du moins readonly.
rien capté x) tu peux expliqué plus en détail ?
Citation:
Ensuite c'est vrai qu'utiliser CreateTimer lorsque l'on utilise ReleaseTimer ne sert pas à grand chose :p. De même que ReleaseTimer met déjà en pause les timers.
fait
Citation:
Tu ne libère jamais d'instance de structure avec la méthode destroy.
???
Citation:
Dans Jumping, tu utilises SetTimerData alors que tu avais déjà défini la data tu timer comme étant p. Donc c'est inutile.
fait
Citation:
Lorsque l'on utilise des timers à si faible période, autant en n'utiliser qu'un comme dans l'exemple que je t'avais envoyé.
bin j'trouve ça chelou utiliser une loop c'est trop rapide oO ou sinon faudrait mettre une incrémentation très petite, ça fait beaucoup plus d'exécution au final on y perd.
Citation:
Je crois que c'est tout .
cool _________________
22:27:43<Seiraw> Bah y a deux genre de personnes
22:27:57<Seiraw> les soumis et les soumises
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 28/06/12 17:07 Sujet du message:
Citation:
Ça serait bien que la fonction JumpingUnit renvoie p pour qu'ensuite on puisse utiliser des méthodes comme stop ou autre. Et l'inclure dans la structure serait une bonne habitude à prendre. Mais il faudra penser à ajouter une méthode destroy qui annule tout dans ce cas. Et rendre les attributs de la structure private serait nécessaire, ou du moins readonly.
Tu as séparé la fonction permettant de créer le saut du reste de la structure. Pourtant, elle devrait en faire partie. Ça donnerait ça :
Secret:
Jass:
library JumpingUnit uses TimerUtils
struct Parabole
unit u
real a
real b
real c
real incrementation
real x = 0
real max
static method Jumping takes nothing returns nothing
local Parabole p = GetTimerData(GetExpiredTimer())
local real a = p.a
local unit u = p.u
local real b = p.b
local real c = p.c
local real incrementation = p.incrementation
local real x = p.x
local real time = p.max
set x = x + incrementation
if x < time then
call SetUnitFlyHeight(u, a * Pow(x, 2) + b * x + c, 0)
static method create takes unit jumper, real height, real time returns thistype
local real a = 40;height * 4)/ 40;-1 * Pow40;time, 2))
local real b = -1 * a * time
local real c = GetUnitFlyHeight40;slider)
local thistype p = Parabole.create40;)
local timer t = CreateTimer40;)
set p.u = slider
set p.a = a
set p.b = b
set p.c = c
set p.incrementation = 0.05
set p.max = time
call SetTimerData40;t, p)
call TimerStart40;t, 0.05, true, function Parabole.Jumping)
return p
endmethod
endstruct
endlibrary
Et là, la méthode create renvoie l'instance p, pour qu'on puisse la stocker dans une variable et la manipuler ensuite.
Si par hasard, tu tombes sur quelqu'un d'un peu tordu qui va modifier l'instance que tu lui renvoie, ça va causer des problèmes. Donc les membres de ta structure, mets les en privé. De même que s'il a en envie d'appeler la méthode destroy, mieux vaut qu'elle soit bien faite, parce que là, ça pourrait causer pas mal de problèmes.
Citation:
Tu ne libère jamais d'instance de structure avec la méthode destroy.
Bah, lorsque tu crées un objet (ici une parabole), ça utilise de la mémoire. Si tu ne le détruis jamais, ça cause du leak.
Citation:
Citation:
Lorsque l'on utilise des timers à si faible période, autant en n'utiliser qu'un comme dans l'exemple que je t'avais envoyé.
bin j'trouve ça chelou utiliser une loop c'est trop rapide oO ou sinon faudrait mettre une incrémentation très petite, ça fait beaucoup plus d'exécution au final on y perd.
Faudra demander à TB, mais il me semble que c'est la meilleure solution. _________________
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: 28/06/12 17:14 Sujet du message:
Sapeur-Goblin a écrit:
Comment tester? Il pleins de petits trucs comme ça que j'aurais bien aimé tester, mais je ne sais pas comment faire.
Ça me paraîtrait quand même bizarre que Pow soit plus rapide qu'une multiplication... Parce que si on suit ta logique, l'appelle de fonction est aussi "interprété", non?
La seule méthode que je connaisse c'est un "stress test", tu t'arranges simplement pour avoir une chute de fps signifiante et stable dans la durée mais pas non plus un freez total, et tu compares 2 façons de faire.
Il faut utiliser aussi des noms très courts pour les variables et noms de fonctions, car cela a son importance, étant donné que le jass est interprété.
On utilise un timer périodique avec une période très petite, puis à l'intérieur de celui ci on utilise une grosse loop, à la limite d'atteindre le limitop (pour atténuer au maximum le coût de l'expiration du timer).
La période est le paramètre variant et dépend totalement des ressources matérielles disponibles au moment du test.
Il faut bien entendu utiliser le même nombre d'itérations pour les 2 loop qui seront testés séparément mais dans les "mêmes conditions" (disponibilité des ressources pc similaire) pour les 2 tests.
Celui qui a le moins de chute de fps est le code le plus efficace.
Certes y'a d'autres trucs à savoir et ce n'est qu'une indication mais c'est ce que l'on peut faire de mieux en jass.
Oui il y a un temps d'interprétation de la fonction native, mais l’exécution d'une fonction native en elle même est sans comparaison par rapport à une fonction custom, et comme Pow est très court comme nom, ceci explique cela.
Mais comme je l'ai dit c'est à tester, y'a juste rien de certain à priori. _________________
Inscrit le: 21 Fév 2010 Messages: 1785 Sujets: 22 Spécialité en worldedit: La modestie Médailles: 1 (En savoir plus...)
Posté le: 28/06/12 19:12 Sujet du message:
Troll-Brain a écrit:
Par ex j'avais essayé de remplacer la fonction Cos/Sin par une lecture de tableau, bah c'était l'utilisation de la fonction Cos/Sin qui était le plus efficace, alors que dans la plupart des "vrais" langages ça serait la lecture de tableau le grand gagnant.
Hum, j'avais demandé à un prof à quel point un Cos était rapide à calculer et il m'a répondu que c'était du même ordre qu'une multiplication... Après, pas sûr que le Cos de W3 soit aussi optimisé (ou qu'il bénéficie des optimisations qui ont été faites dessus par la suite), mais moi ça ne me surprend pas du tout.
Ça dépend aussi de comment le langage gère les arrays, s'ils ne font rien comme en C, je suis d'accord que le Cos doit rester plus lent (et encore...), mais si les arrays sont naturellement dynamiques, le Cos est sans doute plus rapide.
D'autre part, je pense aussi que Pow(2) est plus lent qu'une multiplication... Personnellement, ça ne me viendrait même pas à l'idée de l'utiliser pour des puissances entières. _________________
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: 28/06/12 19:16 Sujet du message:
Sans test, c'est même pas la peine d'en discuter plus, penser n'est pas jouer.
Sinon moi aussi j'utiliserais une multiplication plutôt que Pow(2) mais j'aime bien rester factuel dans ce que je dis.
Et dans le même genre y'a rien de certain non plus à :
<real>*bj_DEGTORAD
VS
Deg2Rad(<real>) _________________
Dernière édition par Troll-Brain le 28/06/12 19:26; édité 1 fois
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 28/06/12 19:17 Sujet du message:
Fulldragon, j'ai relu ton code et j'ai remarqué que tu a opté pour la méthode un timer global. Mais si tu fais comme ça, il faut indexer les instances et les parcourir avec une boucle. Là ce n'est pas multi-instanciable, un timer ne peut avoir qu'une valeur. _________________
Inscrit le: 14 Oct 2009 Messages: 719 Sujets: 40 Spécialité en worldedit: Les bugs Médailles: 1 (En savoir plus...)
Posté le: 28/06/12 19:51 Sujet du message:
Bah non. La seule solution est donc d'indéxer, regarde l'exemple que je t'ai envoyé.
En gros t'as :
- Une variable Parabole array P (globale)
- Une variable integer I (globale) contenant le nombre d'instance en cour
Lorsque tu crées une instance, tu fais P[I] = instance, puis I = I + 1.
Ensuite, dans ta fonction tu fais une boucle de 0 à I exclus.
Et ensuite faut déindexer en faisant I = I - 1 et P[variable_parcourant_P] = P[I] _________________
Toutes les heures sont au format GMT + 1 Heure Aller à la page 1, 2Suivante
Page 1 sur 2
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