Worldedit
  Worldedit
Le site sur l'éditeur de warcraft 3 !
 
  FAQFAQ   RechercherRechercher   Liste des MembresListe des Membres    Groupes d'utilisateursGroupes d'utilisateurs   medals.php?sid=8ebb90338b11ca5e69e12bc0824ff171Médailles   S'enregistrerS'enregistrer 
 ProfilProfil   Se connecter pour vérifier ses messages privésSe connecter pour vérifier ses messages privés   ConnexionConnexion 
  FAQFAQ World Editor   UploadUploader une map ou une image    UploadAjouter sa map à l'annuaire   UploadConsulter l'annuaire

Problème de Dynamic Indexing [VJASS]

 
Poster un nouveau sujet   Répondre au sujet    Worldedit Index du Forum -> Aide sur les déclencheurs
Voir le sujet précédent :: Voir le sujet suivant  
Auteur Message
 Ectelion
Membre reconnu


Inscrit le: 12 Nov 2011
Messages: 1062
Sujets: 107
Spécialité en worldedit: Inactif(Enfin presque)
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 16/04/16 17:18    Sujet du message: Problème de Dynamic Indexing [VJASS] Citer

Contexte: J'ai fait une bibliothèque qui gère la création et le déplacement de projectile qui partent en ligne droite puis reviennent vers leur utilisateur, infligeant des dégâts à toute unité touchée.

Problème: Lorsqu'on crée une instance et qu'une autre est déjà en cours, la première se fige et l'autre voit son paramètre de vitesse augmenté.

Infos: J'ai droit à un "Attempt to destroy a null struct of type:" Chaque fois qu'une instance(même quand y'a qu'une seule) se termine

Le code:
Secret:

Jass:
library Disc uses CONSTANTS

    globals
        private timer TIMER = CreateTimer()
    endglobals

    struct Disc
        private unit dummy
        private unit caster
        private unit pointer
        private real target_x
        private real target_y
        private real dummy_x
        private real dummy_y
        private real angle
        private boolean comeback
        private real speed
        private real distance
        private player owner
        private real damage
        private static integer count = -1
        private static Disc array Instance
       
        private static method loop_disc takes nothing returns nothing
            local integer i = 0
            local real x = 0.00
            local real y = 0.00
            loop
                if Instance[i].comeback == FALSE then
                    if Instance[i].distance >= 0.00 then
                        set Instance[i].dummy_x = Instance[i].dummy_x + Instance[i].speed * Cos(Instance[i].angle)
                        set Instance[i].dummy_y = Instance[i].dummy_y + Instance[i].speed * Sin(Instance[i].angle)
                        set Instance[i].distance = Instance[i].distance - Instance[i].speed
                        call SetUnitX(Instance[i].dummy, Instance[i].dummy_x)
                        call SetUnitY(Instance[i].dummy, Instance[i].dummy_y)
                        if TRAINING == TRUE then
                            call SetUnitX(Instance[i].pointer, Instance[i].dummy_x)
                            call SetUnitY(Instance[i].pointer, Instance[i].dummy_y)
                        endif
                    else
                        set Instance[i].comeback = TRUE
                    endif
                else
                    set Instance[i].target_x = GetUnitX(Instance[i].caster)
                    set Instance[i].target_y = GetUnitY(Instance[i].caster)
                    set x = Instance[i].target_x - Instance[i].dummy_x
                    set y = Instance[i].target_y - Instance[i].dummy_y
                    if SquareRoot(x * x + y * y ) > CST_AREA_MEDIUM then
                        set Instance[i].angle = Atan2(y, x)
                        set Instance[i].dummy_x = Instance[i].dummy_x + Instance[i].speed * Cos(Instance[i].angle)
                        set Instance[i].dummy_y = Instance[i].dummy_y + Instance[i].speed * Sin(Instance[i].angle)
                        call SetUnitX(Instance[i].dummy, Instance[i].dummy_x)
                        call SetUnitY(Instance[i].dummy, Instance[i].dummy_y)
                        if TRAINING == TRUE then
                            call SetUnitX(Instance[i].pointer, Instance[i].dummy_x)
                            call SetUnitY(Instance[i].pointer, Instance[i].dummy_y)
                        endif
                    else
                        call KillUnit(Instance[i].dummy)
                        if TRAINING == TRUE then
                            call RemoveUnit(Instance[i].pointer)
                        endif
                        if i < count then
                            set Instance[i].dummy = Instance[count].dummy
                            set Instance[i].caster = Instance[count].caster
                            set Instance[i].distance = Instance[count].distance
                            set Instance[i].owner = Instance[count].owner
                            set Instance[i].speed = Instance[count].speed
                            set Instance[i].dummy_x = Instance[count].dummy_x
                            set Instance[i].dummy_y = Instance[count].dummy_y
                            set Instance[i].target_x = Instance[count].target_x
                            set Instance[i].target_y = Instance[count].target_y
                            set Instance[i].angle = Instance[count].angle
                            set Instance[i].comeback = Instance[count].comeback
                            set Instance[i].damage = Instance[count].damage
                            if TRAINING == TRUE then
                                set Instance[i].pointer = Instance[count].pointer
                            endif
                            set Instance[count].dummy = null
                            set Instance[count].caster = null
                            set Instance[count].owner = null
                            call Instance[count].deallocate()
                        else
                            set Instance[i].dummy = null
                            set Instance[i].caster = null
                            set Instance[i].owner = null
                            call Instance[i].deallocate()
                        endif
                        set count = count - 1
                        if count == -1 then
                            call PauseTimer(TIMER)
                        endif
                    endif
                endif
                set i = i + 1
                exitwhen i > count
            endloop
        endmethod
       
        static method create_disc takes unit c, integer id, player o, real tx, real ty, real s, real d returns nothing
            local real cx = GetUnitX(c)
            local real cy = GetUnitY(c)
            local real dx = 0.00
            local real dy = 0.00
            local real a = Atan2(ty - cy, tx - cx)
            set count = count + 1
            call Instance[count].allocate()
            set Instance[count].caster = c
            set Instance[count].dummy_x = cx + 60.00 * Cos(a)
            set Instance[count].dummy_y = cy + 60.00 * Sin(a)
            set Instance[count].dummy = CreateUnit(o, id, Instance[count].dummy_x, Instance[count].dummy_y, a)
            if TRAINING == TRUE then
                set Instance[count].pointer = CreateUnit(o, CST_POINTER_MEDIUM_ID, Instance[count].dummy_x, Instance[count].dummy_y, a)
            endif
            set Instance[count].angle = a
            set dx = tx - Instance[count].dummy_x
            set dy = ty - Instance[count].dummy_y
            set Instance[count].speed = s
            set Instance[count].comeback = FALSE
            set Instance[count].owner = o
            set Instance[count].distance = SquareRoot(dx * dx + dy * dy )
            set Instance[count].damage = d
            if count == 0 then
                call TimerStart( TIMER, CST_TIME, true, function Disc.loop_disc )
            endif
        endmethod
       
    endstruct
   
endlibrary



Notes: J'utilise dans la map une autre bibliothèque qui gère les Knockbacks, comme elles sont codées sur la même base, je la met aussi, on sait jamais.

Secret:

Jass:
library Knockback

    globals
        private timer TIMER = CreateTimer()
        constant real CST_KNOCKBACK_DISTANCE_RATIO = 30.00
        constant real CST_KNOCKBACK_SPEED_RATIO = 1.25
    endglobals

    struct Knockback
        private static integer count = -1
        private static Knockback array Instance
        private unit target
        private real speed
        private real distance
        private real target_x
        private real target_y
        private real angle
        private string model
       
        static method loop_knockback takes nothing returns nothing
            local integer i = 0
            loop
                exitwhen i > count
                if Instance[i].distance > 0 then
                set Instance[i].distance = Instance[i].distance - Instance[i].speed
                call DestroyEffect(AddSpecialEffect(Instance[i].model, Instance[i].target_x, Instance[i].target_y) )
                set Instance[i].target_x = Instance[i].target_x + Instance[i].speed * Cos(Instance[i].angle)
                set Instance[i].target_y = Instance[i].target_y + Instance[i].speed * Sin(Instance[i].angle)
                if GetLocationZ(Location(Instance[i].target_x, Instance[i].target_y)) == GetLocationZ(Location(GetUnitX(Instance[i].target), GetUnitY(Instance[i].target) ) ) then
                    call SetUnitX( Instance[i].target, Instance[i].target_x )
                    call SetUnitY( Instance[i].target, Instance[i].target_y )
                endif
                else
                    if i < count then
                        set Instance[i].target = Instance[count].target
                        set Instance[i].distance = Instance[count].distance
                        set Instance[i].speed = Instance[count].speed
                        set Instance[i].angle = Instance[count].angle
                        set Instance[i].target_x = Instance[count].target_x
                        set Instance[i].target_y = Instance[count].target_y
                        set Instance[i].model = Instance[count].model
                        call Instance[count].deallocate()
                    else
                        call Instance[count].deallocate()
                    endif
                    set count = count - 1
                    if count == -1 then
                        call PauseTimer(TIMER)
                    endif
                endif
                set i = i + 1
            endloop
        endmethod
       
        static method create_knockback takes unit t, real s, real d, real x, real y, real x2, real y2, string m returns nothing
            local real a = Atan2(y2 - y, x2 - x)
            set count = count + 1
            set Instance[count] = Instance[count].allocate()
            set Instance[count].target = t
            set Instance[count].speed = s
            set Instance[count].angle = a
            set Instance[count].target_x = x2
            set Instance[count].target_y = y2
            set Instance[count].distance = d
            set Instance[count].model = m
            if count == 0 then
                call TimerStart( TIMER, CST_TIME, true, function Knockback.loop_knockback )
            endif
        endmethod
       
    endstruct
   
endlibrary


_________________
Inactif(Enfn presque)
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Wareditor
The Master of Nothing


Inscrit le: 22 Déc 2008
Messages: 1638
Sujets: 88
Spécialité en worldedit: Effacer


MessagePosté le: 16/04/16 18:23    Sujet du message: Citer

Après un rapide coup d'oeil :

*Renomme toutes les méthodes create_ en create (ce n'est pas qu'esthétique).

*Dans la librairie Knockback
Jass:
set Instance[count] = Instance[count].allocate()

doit être
Jass:
set Instance[count] = thistype.allocate()

allocate est une static method et non une method. De plus tu peux utiliser thistype pour indiquer le nom de ta struct (ce que tu devrais faire quand tu définis Instance).
D'ailleurs, les appellation thistype. sont optionnels à l'intérieur de la struct. tu peux directement écrire : set Instance[count] = allocate(). De même pour les variables static (ce que tu fais pour count d'ailleurs).

*Dans la librairie Disc
Jass:
call Instance[count].allocate()

doit être
Jass:
set Instance[count] = thistype.allocate()

Je ne sais pas pourquoi tu ne reprends pas la syntaxe de Knockback. Tu ne sauvegardes jamais l'instance dans Instance[count] en faisant ainsi.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Ectelion
Membre reconnu


Inscrit le: 12 Nov 2011
Messages: 1062
Sujets: 107
Spécialité en worldedit: Inactif(Enfin presque)
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 17/04/16 14:07    Sujet du message: Citer

@Wareditor:
-Je les nomme create_bidule et pas create parce que la method create renvoie le type auquel elle est liée, ce qui en fait une right-value potentielle. Or, je préfère m'assurer qu'on ne puisse pas récupérer les instances autre part que dans la librairie donc mon choix n'est pas qu'esthétique.(Après si y'a un moyen de passer outre ce détail, je peux évidemment renommer en create.)
-Pour ce qui est de Disc, j'avais en tête que les deux syntaxes produisaient le même résultat du coup j'avais pas pensé que l'erreur pouvait venir de là.
-En ce qui concerne le changement vers thistype, c'est fait.
_________________
Inactif(Enfn presque)
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Wareditor
The Master of Nothing


Inscrit le: 22 Déc 2008
Messages: 1638
Sujets: 88
Spécialité en worldedit: Effacer


MessagePosté le: 17/04/16 18:47    Sujet du message: Citer

Du coup, ca marche ?

Avec le contenu des librairies actuelles, même si on pourrait récupère l'instance d'une struct on ne peut rien faire avec (toutes les variables sont private et il n'y a aucune méthodes non static). Si tu introduit des méthodes que tu ne veux pas qu'un utilisateur utilise il suffit de les rendre private (ce que tu devrais faire pour ta fonction boucle).

Sinon la manière dont tu enlève les instances achevées me semble imparfaite. J'ai l'impression que avec ta méthode (je parle pour Knockback mais j'assume que la méthode est similaire pour Disc) à chaque fois qu'une instance arrive à sa fin, tu n'appliques pas de changement à la précédemment dernière instance. Puisque la jadis dernière instance prend la place de l'instance supprimée et se fait donc ignorer dans cette itération (car jamais atteinte).

D'ailleurs aucune utilité à remplace toutes les variables de Instance[i] par les variables de Instance[count]. Tu peux directement faire Instance[i]=Instance[count] (cela ne corrigera pas l'imperfection mentionnée plus haut).
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Ectelion
Membre reconnu


Inscrit le: 12 Nov 2011
Messages: 1062
Sujets: 107
Spécialité en worldedit: Inactif(Enfin presque)
Médailles: 1 (En savoir plus...)
Créateur d'unité (Quantité : 1)

MessagePosté le: 17/04/16 21:51    Sujet du message: Citer

J'ai test et ça marche correctement.

J'ai effectivement pas fait de Get/Set et autres car pour l'instant c'est juste des bibliothèques de base dont la seule method que l'utilisateur a le droit d'appeler est create_ (c'est pour ça qu'elle n'est pas private)

Les instances achevées sont enlevées de manière imparfaite ? Pourtant je nullifie les handles(quand y'en a), stocke les valeurs de l'instance la plus haute dans l'instance qui se termine comme ça je n'ai pas d'élément vide dans ma boucle et libère l'espace alloué en faisant un deallocate.

Pour le Instance[i] = Instance[count], si j'ai pas fait ça c'est parce que j'ai plus le fonctionnement du C++(à base de pointeurs ofc) que celui du vJASS en tête en ce moment et que du coup, j'avais en tête que j'allais les faire pointer vers les même valeurs d'attributs et qu'avec le deallocate du coup ils pointeraient sur rien.

Je changerais ça demain/dans la semaine.

Sujet résolu du coup. (même si la discussion n'est pas close pour autant à mon avis)

P.S: Tiens d'ailleurs y'a pas de pointeurs en vJASS ?(sauf si je me trompe)
_________________
Inactif(Enfn presque)
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


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...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 18/04/16 16:10    Sujet du message: Citer

Non en effet pas de pointeur en vJass, on ne peut utiliser des variables que par valeur, pas par référence.
Mais ca pourrait se faire dans le préprocesseur (du moins avec les variables globales, portée de la variable toussa toussa)
_________________
Le violet, c'est moche.
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Wareditor
The Master of Nothing


Inscrit le: 22 Déc 2008
Messages: 1638
Sujets: 88
Spécialité en worldedit: Effacer


MessagePosté le: 18/04/16 20:24    Sujet du message: Citer

Le problème vient du fait que tu stocke les valeurs de l'instance la plus haute dans celle qui se fait remplacée. La boucle actuelle n'atteindra donc jamais l'instance la plus haute (car count est diminué) et l'objet de l'instance la plus haute ne subira aucune transformation dans cette occurence de loop_knockback.

Je visualise ça comme cela :
Code:
Cas d'une boucle avec 4 instances
*Début de la boucle
**applique des transformations à l'objet de l'instance 1
**applique des transformations à l'objet de l'instance 2
->l'instance 2 est terminée
->l'instance 4 devient l'instance 2 et le nombre total d'instance passe à 3
**applique des transformations à l'objet de l'instance 3
*Fin de la boucle


Sinon, je ne suis plus sur si nullifier toutes les variables à la main est redondant ou non. Je ne sais plus si la static destroy ne le fait pas déjà. Il faudrait que quelqu'un de plus connaisseur s'exprime la dessus.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
Montrer les messages depuis:   
Poster un nouveau sujet   Répondre au sujet    Worldedit Index du Forum -> Aide sur les déclencheurs Toutes les heures sont au format GMT + 1 Heure
Page 1 sur 1

 
Sauter vers:  
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


Powered by phpBB © 2001, 2005 phpBB Group
Traduction par : phpBB-fr.com