Posté le: 02/02/12 20:06 Sujet du message: [vJass] LinearPatrol
Nom de la fonction : LinearPatrol Créateur : wareditor
Fonctions requises : Librairie UnitLL par Troll Brain et UnitIndexer par Nestharus
Code :
Secret:
Jass:
//===========================================================================
// LINEAR PATROL v 2.1 By wareditor - 19 / 02 / 12
//===========================================================================
//
// AIM :
//
// * Remove all the Desyncronisation
// * Completly remove the irrational movement due to patroling.
// * Good for Maze, Slide and Escape
//
// API :
//
// METHOD :
// * call LinearPatrol.create(whichUnit, speed, Xtarget, Ytarget)
//
// COMMENTARY :
//
// * All the patrol are Desyncronisated after a certain amount of time
// * Certain unit has got a irrational bahavior during patroling ( If you never found this bug
// I can give you a demo map with this )
//
//
// REQUIRES :
//
// * UnitLL - Troll-Brain -
// ( http://www.hiveworkshop.com/forums/jass-resources-412/snippet-unitll-209540/ )
//
// * UnitIndexer - Nestharus -
// ( http://www.hiveworkshop.com/forums/jass-resources-412/system-unit-indexer-172090/ )
//
//
//===========================================================================
// Enjoy
//===========================================================================
private constant real REFRESH = 0.01
//Every REFRESH the trajectory
//of the unit will be corrected
private constant real EPSILON = 5
//If the postion of the unit is > to EPSILON
//It will be correctecd
private constant real REORDER = 0.25
//freq that the order will be ordered
endglobals
//===========================================================================
// DON'T MODIFY THE SCRIPT BELLOW WITHOUT GOOD REASON
//===========================================================================
private unit whichUnit //Which unit is being moved ?
private real Xbase//The Unit Base Position
private real Ybase
private real Xtarget//The Target Position
private real Ytarget
private real duration//The Number of Refresh for one travel
private real a //X coef
private real b//Y coef
private real time//The 2nd Coef
private real reOrder
private boolean back//Back or Straight
local thistype this
local UnitLL ll = LL
local real x
local real y
local real xu
local real yu
set ll = ll.first
loop
exitwhen(ll == 0)
set this = CustomData[GetUnitId(ll.enum)]
set this.reOrder = this.reOrder + REFRESH
//Return or No
if( this.time >= this.duration)then
set this.back = true
call IssuePointOrder(whichUnit,"move",Xbase,Ybase)
elseif(this.time <= 0 )then
set this.back = false
call IssuePointOrder(whichUnit,"move",Xtarget,Ytarget)
endif
//The Unit is going back or straight
if not this.back then
set this.time = this.time+1
if this.reOrder == REORDER then
call IssuePointOrder(this.whichUnit,"move",Xtarget,Ytarget)
set this.reOrder = 0
endif
elseif this.back then
set this.time = this.time-1
if this.reOrder == REORDER then
call IssuePointOrder(this.whichUnit,"move",Xbase,Ybase)
set this.reOrder = 0
endif
endif
set x = this.a*this.time+this.Xbase
set y = this.b*this.time+this.Ybase
set xu = GetUnitX(this.whichUnit)
set yu = GetUnitY(this.whichUnit)
if (x - xu > EPSILON) or (xu - x > EPSILON ) or (y - yu > EPSILON) or (yu - y > EPSILON ) then
//SetUnitXY
call SetUnitX(this.whichUnit, x )
call SetUnitY(this.whichUnit, y )
endif
static method DeIndex takes nothing returns nothing
local integer id = GetUnitId(GetIndexedUnit())
local thistype this = CustomData[id]
call this.destroy()
endmethod
static method create takes unit whichUnit, real s, real Xtarget, real Ytarget returns thistype
local thistype this
local real distance
local real speed = s
//If the user fails
if (GetUnitTypeId(whichUnit) == 0) then //No null unit ( work even with ghost unit )
debug call BJDebugMsg("Warning: LinearPatrol has been given a null unit. Movement cancelled.")
return null
endif
//If Speed <= 0 , it will be the unit base mvs
if(speed <= 0)then
set speed = GetUnitMoveSpeed(whichUnit)
else
call SetUnitMoveSpeed(whichUnit,s)
set speed = s
endif
//Setting struct
set this = thistype.allocate()
set this.whichUnit = whichUnit
set this.Xbase = GetUnitX(whichUnit)
set this.Ybase = GetUnitY(whichUnit)
set this.Xtarget = Xtarget
set this.Ytarget = Ytarget
set distance = SquareRoot( (this.Xbase-Xtarget)*(this.Xbase-Xtarget)+(this.Ybase-Ytarget)*(this.Ybase-Ytarget) )
set this.duration = distance /( speed * REFRESH )
set this.a = (Xtarget-this.Xbase) / this.duration
set this.b = (Ytarget-this.Ybase) / this.duration
if(LL == 0)then
set LL = UnitLL.create()
call LL.onDeindex(function thistype.DeIndex)
endif
call LL.addUnit(whichUnit)
set CustomData[GetUnitId(whichUnit)] = this
method destroy takes nothing returns nothing
if LL.isUnitInside(this.whichUnit) == true then
call LL.removeUnit(this.whichUnit)
endif
set this.whichUnit = null
set this.Xbase = 0
set this.Ybase = 0
set this.Xtarget = 0
set this.Ytarget = 0
set this.duration = 0
set this.time = 0
set this.back = false
call this.deallocate()
endmethod
endstruct
endlibrary
//===========================================================================
// CONTACT ME AT : Wareditor.TFL[AT]gmail.com
//===========================================================================
Utilisation : Arrive a corrige le bug des mouvements irrationnel des unit lors d'une patrouille. Qui d'ailleurs ne bug pas tout le temps :S
Copyright : Comme vous voulez.
Remarques : Merci a Bantas pour son UnitCircleSlide. _________________
Dernière édition par Wareditor le 19/02/12 21:10; édité 19 fois
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: 02/02/12 20:42 Sujet du message:
Je ne suis pas persuadé que redonner l'ordre périodiquement suffit à atténuer la désynchronisation des patrol, d'ailleurs il me semble que Max avait déjà essayé un truc du genre.
As tu vraiment comparé avec cela, et sans, plusieurs fois ?
A propos du code en lui même :
Jass:
function UnitCustomPatrolStop takes unitcustompatrol_struct f returns nothing
call ReleaseTimer(f.BaseTimer)
call ReleaseTimer(f.TargetTimer)
call f.destroy()
endfunction
Les struct du vJass ne correspondent pas aux struct du C, elles sont plus que de simples structure de données, elles possèdent certains attributs de la POO.
Cela dit, le code jass résultant sera le même mais c'est bien plus agréable, voir lisible, d'utiliser des method que de recréer soit même cette possibilité.
D'ailleurs tu devrais même plutôt la nommer "destroy" et gérer la destruction (je t'invite à consulter la doc de jasshelper)
Jass:
if (whichUnit == null)
Ce type de check n'est pas suffisant, en effet une unité "ghost" ne sera pas considérée comme null (c'est une unité qui a été supprimée de la partie, mais la variable pointant dessus n'a pas été effacée).
Si je me rappelle bien tu peux utiliser GetUnitTypeId() qui renverra 0 pour toute unité non valide, mais c'est à vérifier.
Il y a aussi la possibilité d'utiliser le booléen de SaveUnitHandle, mais c'est plus lent et requiert l'utilisation d'une hashtable, or tu n'en n'as pas besoin ici.
Tu as oublié aussi de prendre en compte le cas de speed < 0 (oui je sais c'est absurde, mais le debug say trop fun) _________________
Je ne suis pas persuadé que redonner l'ordre périodiquement suffit à atténuer la désynchronisation des patrol, d'ailleurs il me semble que Max avait déjà essayé un truc du genre.
As tu vraiment comparé avec cela, et sans, plusieurs fois ?
C'est full' qui m'a dit que Max utiliser cette méthode donc j'ai penser que sa devais marcher. Mais après test cela ne marche pas si bien que sa. Comme je l'explique dans les commentaires l'unit change comme même de "ligne". C'est comme si elle avait pas un angle de 180 mais 179 et c est que vers la fin qu'elle corrige sa trajectoire.
J'ai aussi penser a un MoveUnitX mais se serai plus complexe et moins esthétique a mettre en place. Mais j'y réfléchirai.
Je ne connais pas le C ni le POO mais j'ai compris ce que tu voulais me dire.
J'ai donc renommé la method : "onDestroy" comme indiquer dans le manuel.
J'ai pris en compte tes autres remarques, je pense que le check de l'unit est suffisant maintenant même si peut être pas 100% fiable.
PS : Bien sur le code a été mis a jour _________________
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: 02/02/12 21:29 Sujet du message:
POO n'est pas un langage, c'est un concept de programmation, Programmation Orientée Objet.
Jass:
if (whichUnit == null and GetUnitTypeId(whichUnit) == 0)
Ca ne résout en rien le problème des ghost unit car la première condition restera fausse.
Je voulais dire cela :
Citation:
if GetUnitTypeId(whichUnit) == 0 then
Je suis certain que sur une unité null c'est egal à 0, mais j'ai jamais testé sur une ghost unit.
Faudrait que tu testes cela (le code peut comporter des erreurs, je l'ai écrit directement ici) :
Jass:
library Test initializer init
globals
private unit U
endglobals
private function init takes nothing returns nothing
set U = CreateUnit(Player(0),'hpea',0,0,0)
call RemoveUnit(U)
call TriggerSleepAction(0)
call BJDebugMsg(I2S(GetUnitTypeId(U)))
endfunction
endlibrary
Honnêtement, la method onDestroy ne sert pas à grand chose, autant utiliser la method destroy (et à l'intérieur de celle ci la method deallocate).
De même à la place de UnitCustomPatrol, tu pourrais utiliser la static method create (et à l'intérieur de celle ci la method allocate).
Enfin tu pourrais simplement nommer ta struct CustomPatrol, puisqu'avec ces dernières modifications, l'utilisateur utilise pleinement la struct sans fonctions annexes.
Faut pas écouter fulldragon sans avoir testé (ce n'est pas un troll de ma part), mais il raconte souvent n'importe quoi (pas à escient), un peu comme Vladadamn, mais pas pour les mêmes raisons. _________________
J'ai pris en compte toutes tes remarques
Mais bon je pense que cette technique n'est pas très réussie. Je vais donc pouvoir la convertir pour faire qu'une unit s’arrête après x aller-retour ou bien je pourrais essayer de redonner l'ordre tout les secondes.
ou bien partir sur mon MoveUnitX ? _________________
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: 02/02/12 21:52 Sujet du message:
La seule méthode viable semble être de gérer les déplacements périodiquement avec un offset (timer + SetUnitX/Y).
J'ai moi même pensé de prime abord que le résultat visuel serait moche (quand l'unité arrivée à une extrémité doit tourner pour faire demi tour).
Je pensais devoir utiliser un evil SetUnitFacing.
Mais comme SetUnitX/Y n'est pas censé interrompre les ordres, on peut ordonner à l'unité de faire demi-tour au moment voulu.
Certes, l'unité continuera à vouloir avancer, mais si la période du timer est suffisamment petite, cela ne devrait pas être perceptible.
Si jamais c'est trop perceptible, on peut s'arranger pour stopper l'ordre, une fois la rotation de l'unité accomplie, tout en jouant l'animation walk.
Maintenant j'ignore si c'est faisable avec "beaucoup" d'unités, en terme de performance.
Mais avec un seul timer qui gère tous les déplacement et une structure appropriée (surtout pas un group, à cause du ForGroup lent) tel qu'une liste doublement chainée, ou même un simple unit array (bien que cela rendrait les opérations de suppression, voir d'insertion d'unité bien plus coûteux, tout est question du nombre d'unités et de la fréquence de ces ajouts/suppression), le résultat devrait être suffisant.
HS : Epic fail, refresh de mon post = perte de ma prose, j'ai du tout retaper >< _________________
Tu veux dire rajouter un MoveUnitX/Y en addition a ce systeme ?
Serait il possible qu'en corrigeant la trajectoire de l'unit tout les X secondes via une formule simple on pourrait avoir des lignes droites ?
Sinon je pense que si je ne trouve pas d'autres solutions je vais utiliser cette méthode.
Sinon j'ai quelque-chose d'assez bizarre : J'ai essayer de tester mon systeme en ligne vertical. Le résultat est assez troublant. Quand l'unit "monte" elle se décalé toujours mais quand elle "descend" elle reste parfaitement droite ! _________________
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: 02/02/12 22:13 Sujet du message:
Jass:
local CustomPatrol f
->
Jass:
local thistype this
Ca ne change rien au code final, mais c'est une meilleure convention.
Je parle de "complètement" remplacer le système de déplacement natif de wc3, hormis que l'on laisse wc3 gérer la rotation de l'unité quand elle fait demi tour, pour que cela reste "naturel".
Comme on gère la position de l'unité soi même par déclencheur, c'est forcément synchronisé. _________________
Mise a jour du code.
Est ce que je devrais transformer les callback des timers en methods ? ou est ce que ce n'est pas possible/intéressant ?
Tu veux dire un systeme qui se declanche lors d'une patrol ?
Donc quelque-chose de complétement automatique ? Cela complique la tache :S. Il faudrait stocker chaque unit dans une struct puis les retirer des que l'ordre est interrompue... Cela devient plus complexe que je ne le penser x)
Et tu veux qu'on y travaille ensemble ou tu me laisse ? _________________
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: 02/02/12 22:38 Sujet du message:
Wareditor a écrit:
Est ce que je devrais transformer les callback des timers en methods ? ou est ce que ce n'est pas possible/intéressant ?
Pour conserver la sacro sainte encapsulation de données, il vaudrait mieux en effet utiliser des static method pour les callbacks de timers, et donner le statut "private" aux membres de la struct (les variables).
Citation:
Tu veux dire un systeme qui se declanche lors d'une patrol ?
Donc quelque-chose de complétement automatique ? Cela complique la tache :S. Il faudrait stocker chaque unit dans une struct puis les retirer des que l'ordre est interrompue... Cela devient plus complexe que je ne le penser x)
Et tu veux qu'on y travaille ensemble ou tu me laisse ?
En fait non, car on peut imaginer que toutes les patrol n'ont pas besoin d'être synchronisés, sans oublier les patrols qui ne sont pas linéaires.
C'est à l'utilisateur de définir quels patrols il veut synchroniser.
La théorie de ce que j'ai exposé semble valable, reste à voir ce que ça donne en pratique.
Je ne compte pas le faire avec toi, tout simplement parce que cela me prendrait plus de temps de t'expliquer comment le faire, que de le faire moi même.
Mais j'ai pas envie de le faire non plus.
Faudrait demander à Max s'il a déjà fait quelque chose du genre, je pense qu'il serait intéressé, du moins à le faire tout seul. _________________
Il me détecte une erreur si mon callback est une method, mais sa doit surement être moi, je corrigerais donc sa demain.
Tu utilisait des "on" dans la phrases donc il me semblais que tu voulais le faire ensemble. c'est tout.
Je pense me débrouiller tout seul _________________
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: 02/02/12 23:11 Sujet du message:
Ca doit être une static method (takes nothing) returns nothing.
Je t'ai juste expliqué l'algorithme théorique, à toi de le tester et le mettre en pratique.
Dernière chose, tu peux utiliser "thistype" à la place de chaque CustomPatrol, hormis bien entendu pour le nom de la struct.
L'intérêt peut paraître limité, mais par exemple si tu décides de renommer le nom de la struct tu n'auras pas à éditer le code (sauf si tu l'utilisais déjà ailleurs bien entendu).
Sa réelle utilité prend tout son sens dans les module (même si la dernière mode complètement fugly est d'utiliser les module comme textmacro, mais c'est une autre histoire ...)
PS : On c'est un con, j'aurais plutôt utiliser nous ^^ _________________
Posté le: 04/02/12 11:14 Sujet du message: Re: [vJass] UnitCustomPatrol
Précédente version :
Secret:
Wareditor a écrit:
Nom de la fonction : UnitCustomPatrol Créateur : wareditor
Fonctions requises : Librairie TimerUtils par Vexorian
Code :
Secret:
Jass:
library UnitCustomPatrol requires TimerUtils
//===========================================================================
// UNIT CUSTOM PATROL v 1.11 By wareditor
//===========================================================================
//
//FUNCTIONS
//call CustomPatrol.create(whichUnit, speed, Xtarget, Ytarget)
//
//COMMENTARY
//It was created to debug the irrational movements of patroling unit.
//If a unit patrol on a long distance, on a straight line you will be able to
//see that it going upper than the line.
//I heard that doing that System could correct this.
//After some test i can say that it still here even with this sytstem, however
//this system decrease the bug.
private function MoveToTarget takes nothing returns nothing
local CustomPatrol f = GetTimerData(GetExpiredTimer())
call IssuePointOrder(f.whichUnit,"move",f.Xtarget,f.Ytarget)
endfunction
private function MoveToBase takes nothing returns nothing
local CustomPatrol f = GetTimerData(GetExpiredTimer())
call IssuePointOrder(f.whichUnit,"move",f.Xbase,f.Ybase)
endfunction
unit whichUnit //Which unit is being moved ?
timer BaseTimer
timer TargetTimer
real Xbase//The Unit Position
real Ybase
real Xtarget//The Target Postion
real Ytarget
real duration//The Time of one travel
static method create takes unit whichUnit, real speed, real Xtarget, real Ytarget returns CustomPatrol
local thistype this
local real Xb = GetUnitX(whichUnit)
local real Yb = GetUnitY(whichUnit)
local real distance = DistanceBetweenPointsEx(Xb,Yb,Xtarget,Ytarget)
//If the user fails
if (GetUnitTypeId(whichUnit) == 0) then //No null unit ( work even with ghost unit )
debug call BJDebugMsg("Warning: UnitCustomPatrol has been given a null unit. Movement cancelled.")
return null
endif
//If Speed <= 0 , it will be the unit base mvs
if(speed <= 0)then
set speed = GetUnitMoveSpeed(whichUnit)
endif
//Setting struct
set this = CustomPatrol.allocate()
set this.whichUnit = whichUnit
set this.BaseTimer = NewTimer()
set this.TargetTimer = NewTimer()
set this.Xbase = Xb
set this.Ybase = Yb
set this.Xtarget = Xtarget
set this.Ytarget = Ytarget
set this.duration = distance / speed//t=d/v
Utilisation : Permet de reduir l'effet du bug qu'on les patrouilles sur les mouvements d'une unit. tout fois j’aimerais améliorer le code pour arriver a effacer ce bug.
Copyright : Comme vous voulez.
Remarques : Si jamais vous avez une idée ou des ameliorations sur le systeme je serais toujours la pour vous entendre x). Aussi, merci a Bantas pour son UnitCircleSlide.
Mise a jour :
La Lib' s’appelle maintenant LinearPatrol.
Le bug est corrige mais le script est loin d’être parfait, j'attends des commentaires pour améliorer. _________________
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: 04/02/12 12:12 Sujet du message:
Jass:
set this.freq = this.duration/(distance/100)
La parenthèse est superflue.
Y'a de l'idée, mais un seul timer avec une faible période, du genre 1/50 de seconde serait préférable, avec une structure (tel que UnitLL :p) pour gérer toutes les unités quand le timer expire.
TimerUtils deviendrait inutile.
Indente mieux ton code, c'est très important pour la lisibilité.
Jass:
private static method SetUnitPos...
Car l’utilisateur n'a pas à appeler cette method.
Jass:
static method create takes unit whichUnit, real speed, real Xtarget, real Ytarget returns thistype
DistanceBetweenPointsEx est une fonction non déclarée. _________________
Toutes les heures sont au format GMT + 1 Heure Aller à la page 1, 2, 3, 4, 5, 6Suivante
Page 1 sur 6
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