IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Programmation multimédia/Jeux Python Discussion :

Probleme d'arret de mouvement sur objet


Sujet :

Programmation multimédia/Jeux Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Mai 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 54
    Points : 28
    Points
    28
    Par défaut Probleme d'arret de mouvement sur objet
    Bonjour à tous,

    Je commence en programmation et j'essaie de créé un petit jeu très simple pour me faire la main.

    Le but étant de lancer des projectiles vers des météorites afin de les détruire avant qu'elle ne touche la terre.

    Bon pour l'instant, j'ai réussi a créé le "pion" du joueur qui se déplace dans la fenêtre de gauche a droite, et j'ai aussi réussi a faire tirer les projectiles à partir de se même pion.

    Mon problème c'est que je ne peu pas tirer plusieurs projectile en même temps. Si je le fais, le projectile précédent s'arrête et en plus j'ai une erreur d'indentation lorsque j'essaie d'effacer le projectile qui atteint le haut de ma fenêtre...

    Je vous met mon code source: (soyer indulgent je commence en programmation et j'avoue ne pas avoir tout saisi de la programmation orienté objet )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
     
     
    # -*- coding:Latin-1 -*-
     
    from tkinter import *
    from random import randrange
     
    class Joueur(object):
        """ Crée un joueur """
     
        def __init__(self, can, posX, posY):
     
            self.can = can
            self.posX = posX #Utile pour définir
            self.posY = posY #l'emplacement selon le canvas
     
            # Création d'un rectangle de 20 * 20
            self.joueur = self.can.create_rectangle(self.posX, self.posY,
                                                     self.posX+20, self.posY+20,
                                                     fill = "red")
     
            # Gestion des évènements
            self.can.bind("<Motion>", self.move)
            self.can.bind("<Button-1>", self.tire, add = "+")
     
        def move(self, event):
            " Fais bouger le joueur selon la souri "
     
            # Récupère la position de la souri
            self.mouseX = event.x-10
            self.mouseY = event.y+10
     
            self.can.coords(self.joueur, self.mouseX, self.posY,
                            self.mouseX+20, self.posY+20)
     
     
        def tire(self, event):
            " Crée un projectile "
     
            self.lazer = self.can.create_line(self.mouseX+10, self.posY
                                              , self.mouseX+10, self.posY+30,
                                              fill = "blue")
     
            self.deplacetire()
     
        def deplacetire(self):
            " Déplace le projectile jusqu'en haut du canvas "
     
            # Récupère la position du projectile
            self.posLazer = self.can.coords(self.lazer)
            self.posLazerY = self.posLazer[1]
     
            if self.posLazerY > 0:
                self.can.move(self.lazer, 0, -10)
                self.can.after(30, self.deplacetire)
            else:
                self.can.delete(self.lazer)
     
    class App(object):
        """ Application principal """
     
        def __init__(self, larg = 200, haut = 200):
     
            self.larg = larg
            self.haut = haut
     
            # Fenetre principal
            self.root = Tk()
     
            # Canvas de la fenetre principal
            self.can = Canvas(self.root, width = self.larg,
                              height = self.haut, bg = "black")
            self.can.pack(side = TOP)
     
            # Bouton pour quitter qui s'ajuste à la largeur
            # de la fenêtre d'où le "int(larg/7)"
            Button(self.root, text="Quitter", bg="dark grey",
                   width = int(larg/7), command =
                   self.root.quit).pack(side = BOTTOM)
     
            # Appel la classe qui créera le joueur et le
            # positionne au centre
            Joueur(self.can, self.larg/2, self.haut-20)
     
        def mainloop(self):
            "Methode qui referme la fenetre"
            self.root.mainloop()
            self.root.destroy()
     
    if __name__ == "__main__":
     
        play = App(600, 600)
        play.mainloop()

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 285
    Points : 36 773
    Points
    36 773
    Par défaut
    Salut,
    Lorsque le joueur il tire, l'attribut "lazer" de l'instance de Joueur sera initialisé à un item "line" du le canvas. Comme il n'y a qu'un Joueur, tirer plusieurs fois écrase l'attribut laser: l'ancien item n'avance plus et on a perdu son identifiant.

    Honnêtement je ne vois pas trop pourquoi vous vous êtes acharné à vouloir créer des classes pour App et Joueur: pour l'instant, vous ne fabriquez pas plusieurs instances de ces classes là. Par contre, si vous voulez avoir plusieurs tirs de laser qui volent en même temps...

    Dommage! c'est peut être le seul objet qui mérite d'avoir une "class" pour pouvoir en fabriquer plusieurs durant la vie de l'application (ou de la partie).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Mai 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 54
    Points : 28
    Points
    28
    Par défaut
    Hahaha, j'ai eu le flash en prennent ma douche

    J'avais pas compris qu'il fallais créé un objet pour le projectile... Comme je vous disais je commence et j'ai pas tout compris encore

    Voici le nouveau code qui marche pour ceux que sa l'intéresse:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
     
    # -*- coding:Latin-1 -*-
     
    from tkinter import *
    from random import randrange
     
    class Tire(object):
        """ Crée un projectile """
        def __init__(self, can, posJoueur):
     
            self.can = can
            # Récupère la position du joueur en X et Y
            self.posJoueur = posJoueur
            self.posXJ = self.posJoueur[0]
            self.posYJ = self.posJoueur[1]
     
            self.lazer = self.can.create_line(self.posXJ+10, self.posYJ
                                              , self.posXJ+10, self.posYJ+30,
                                              fill = "blue")
     
            self.deplaceTire()
     
        def deplaceTire(self):
            " Déplace le projectile jusqu'en haut du canvas "
     
            # Récupère la position du projectile
            self.posLazer = self.can.coords(self.lazer)
            self.posLazerY = self.posLazer[1]
     
            if self.posLazerY > 0:
                self.can.move(self.lazer, 0, -10)
                self.can.after(30, self.deplaceTire)
            else:
                self.can.delete(self.lazer)
     
    class Joueur(object):
        """ Crée un joueur """
     
        def __init__(self, can, posX, posY):
     
            self.can = can
            self.posX = posX #Utile pour définir
            self.posY = posY #l'emplacement selon le canvas
     
            # Création d'un rectangle de 20 * 20
            self.joueur = self.can.create_rectangle(self.posX, self.posY,
                                                     self.posX+20, self.posY+20,
                                                     fill = "red")
     
            # Gestion des évènements
            self.can.bind("<Motion>", self.move)
            self.can.bind("<Button-1>", self.tire, add = "+")
     
        def move(self, event):
            " Fais bouger le joueur selon la souri "
     
            # Récupère la position de la souri
            self.mouseX = event.x-10
            self.mouseY = event.y+10
     
            self.can.coords(self.joueur, self.mouseX, self.posY,
                            self.mouseX+20, self.posY+20)
     
     
        def tire(self, event):
            " Crée un projectile "
     
            # Récupere la position du joueur
            self.posJoueur = self.can.coords(self.joueur)
     
            Tire(self.can, self.posJoueur)
     
    class App(object):
        """ Application principal """
     
        def __init__(self, larg = 200, haut = 200):
     
            self.larg = larg
            self.haut = haut
     
            # Fenetre principal
            self.root = Tk()
     
            # Canvas de la fenetre principal
            self.can = Canvas(self.root, width = self.larg,
                              height = self.haut, bg = "black")
            self.can.pack(side = TOP)
     
            # Bouton pour quitter qui s'ajuste à la largeur
            # de la fenêtre d'où le "int(larg/7)"
            Button(self.root, text="Quitter", bg="dark grey",
                   width = int(larg/7), command =
                   self.root.quit).pack(side = BOTTOM)
     
            # Appel la classe qui créera le joueur et le
            # positionne au centre
            Joueur(self.can, self.larg/2, self.haut-20)
     
        def mainloop(self):
            "Methode qui referme la fenetre"
            self.root.mainloop()
            self.root.destroy()
     
    if __name__ == "__main__":
     
        play = App(600, 600)
        play.mainloop()

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Mai 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 54
    Points : 28
    Points
    28
    Par défaut
    Citation Envoyé par wiztricks Voir le message

    Honnêtement je ne vois pas trop pourquoi vous vous êtes acharné à vouloir créer des classes pour App et Joueur: pour l'instant, vous ne fabriquez pas plusieurs instances de ces classes là.

    - W
    Et bien en faite je ne sais pas trop pourquoi moi non plus, j'ai suivi plusieurs tuto ici et la et pas mal tout le monde fessais sa comme sa...

    Je me suis donc pas trop posé de question

    J'avoue que je pourrais éliminer la class App... mais pour la class joueur je vois pas trop comment l'enlever, je dois créé un objet Joueur pour pouvoir faire bouger mon pion non?

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 285
    Points : 36 773
    Points
    36 773
    Par défaut
    Citation Envoyé par PascalStl Voir le message
    J'avoue que je pourrais éliminer la class App... mais pour la class joueur je vois pas trop comment l'enlever, je dois créé un objet Joueur pour pouvoir faire bouger mon pion non?
    Hmmm.
    Pour bouger l'item qui représente le Joueur sur le canvas, on peut mémoriser l'iid de l'objet (ce que vous faites dans self.joueur) ou demander à Tk de lui coller votre identifiant via un tag 'joueur' par exemple. Après, pour tirer il faut récupérer la position du joueur. On peut le faire via canvas.bbox('joueur') ou éviter l'appel à Tk en gérant des cx, cy globaux ou associés à une instance de Joueur.

    Pour le fun, j'ai ré-écrit votre code en supprimant Application, en gardant Joueur et en construisant d'autres objets pour les tirs. L'idée étant de séparer le timer du "tir".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    # -*- coding:utf-8 -*-
     
    import tkinter as tk
    from random import randrange
     
    class Joueur:
        dx = 10
        def __init__(self, canvas, x0, y0):
            x1, y1 = x0 + 20, y0 + 20
            self.iid = canvas.create_rectangle(x0, y0, x1, y1, fill = "red")
            self.cx = (x0 + x1) // 2
            self.cy = (y0 + y1) // 2
            self.canvas = canvas
     
     
        def move(self, x):
            " Fais bouger le joueur selon la souri "
            dx = x - self.cx
            self.canvas.move(self.iid, dx, 0)
            self.cx = x
     
     
     
    callbacks = []
    def eventloop(app, delta=50):
     
        def do_callbacks():
            cb_copy = callbacks[:]
            [ cb() for cb in cb_copy ]
            app.after(delta, do_callbacks)
     
        app.after(delta, do_callbacks)
     
     
     
    def tirer(canvas, joueur):
        global callbacks # note
     
        cx = joueur.cx
        y0 = joueur.cy - 5
        y1 = joueur.cy - 30
        dy = 10
        iid = canvas.create_line(cx, y0, cx, y1, fill = "blue")
     
        def move():
            nonlocal y0
            if y0 > 0:
                canvas.move(iid, 0, -dy)
                y0 -= dy
            else:
                canvas.delete(iid)
                callbacks.remove(move)
     
        callbacks.append(move)
     
     
    if __name__ == "__main__":
     
        app = tk.Tk()
     
        width = height = 600
        canvas = tk.Canvas(app, width=width, height=height)
        canvas.pack(side='top')
     
        tk.Button(app, text='Quit', bg="dark grey", command=app.quit
                  ).pack(fill='x', side='bottom')
     
        joueur = Joueur(canvas, width // 2, height - 20)
     
        canvas.bind('<Motion>', lambda e: joueur.move(e.x))
        canvas.bind('<1>', lambda e: tirer(e.widget, joueur))
     
        eventloop(app)
     
        tk.mainloop()
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Mai 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 54
    Points : 28
    Points
    28
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Hmmm.

    Pour le fun, j'ai ré-écrit votre code en supprimant Application, en gardant Joueur et en construisant d'autres objets pour les tirs. L'idée étant de séparer le timer du "tir".

    - W
    Beaucoup plus cour comme code , mais il doit m'en rester beaucoup à apprendre car j'y comprend rien hahaha

    N’empêche que la j'ai un autre problême, c'est peu être du à m'a logique de programmation...

    J'ai créé des Météorites qui tombes du ciel, mais comment faire pour dire à l'ordinateur qu'il doit les détruire lorsqu'ils rencontre un de mes tirs???

    Voici où j'en suis rendu: (peu être je devrais revoir tout mon code et m'orienter plus dans la direction du tien)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
     
    # -*- coding:Latin-1 -*-
     
    from tkinter import *
    from random import randrange
     
    class Meteor(object):
        """ Crée un météorite """
        def __init__(self, can):
     
            self.can = can
     
            # Récupère la taille du canvas
            self.tailleCanX = int(self.can.cget("width"))
            self.tailleCanY = int(self.can.cget("height"))
     
            # Génère une position X aléatoire
            self.posMX = randrange(5, self.tailleCanX-5)
     
            self.meteor = self.can.create_rectangle(self.posMX,
                                                    0,self.posMX+20, 20, fill = "white")
     
            self.deplaceMeteor()
            # Génére un nouveau météor
            self.can.after(1000, self.repete)
     
        def repete(self):
            """ Réappelle un Meteor """
            Meteor(self.can)
     
        def deplaceMeteor(self):
            """ Déplace le météor vers le bas du canvas """
     
            # Récupère la position du météor
            self.posM = self.can.coords(self.meteor)
            self.posMY = self.posM[1]
     
            # détruit le météor s'il sort du canvas
            if self.posMY < self.tailleCanY:
                self.can.move(self.meteor, 0, +
                              10)
                self.can.after(30, self.deplaceMeteor)
            else:
                self.can.delete(self.meteor)
     
    class Tire(object):
        """ Crée un projectile """
        def __init__(self, can, posJoueur):
     
            self.can = can
            # Récupère la position du joueur en X et Y
            self.posJoueur = posJoueur
            self.posXJ = self.posJoueur[0]
            self.posYJ = self.posJoueur[1]
     
            self.lazer = self.can.create_line(self.posXJ+10, self.posYJ
                                              , self.posXJ+10, self.posYJ+30,
                                              fill = "blue")
     
            self.deplaceTire()
     
        def deplaceTire(self):
            " Déplace le projectile jusqu'en haut du canvas "
     
            # Récupère la position du projectile
            self.posLazer = self.can.coords(self.lazer)
            self.posLazerY = self.posLazer[1]
     
            # Détruit le lazer s'il sort du canvas
            if self.posLazerY > 0:
                self.can.move(self.lazer, 0, -10)
                self.can.after(30, self.deplaceTire)
            else:
                self.can.delete(self.lazer)
     
    class Joueur(object):
        """ Crée un joueur """
     
        def __init__(self, can, posX, posY):
     
            self.can = can
            self.posX = posX #Utile pour définir
            self.posY = posY #l'emplacement selon le canvas
     
            # Création d'un rectangle de 20 * 20
            self.joueur = self.can.create_rectangle(self.posX, self.posY,
                                                     self.posX+20, self.posY+20,
                                                     fill = "red")
     
            # Gestion des évènements
            self.can.bind("<Motion>", self.move)
            self.can.bind("<Button-1>", self.tire, add = "+")
     
        def move(self, event):
            " Fais bouger le joueur selon la souri "
     
            # Récupère la position de la souri
            self.mouseX = event.x-10
            self.mouseY = event.y+10
     
            self.can.coords(self.joueur, self.mouseX, self.posY,
                            self.mouseX+20, self.posY+20)
     
     
        def tire(self, event):
            " Crée un projectile "
     
            # Récupere la position du joueur
            self.posJoueur = self.can.coords(self.joueur)
     
            # Appel d'un projectile
            Tire(self.can, self.posJoueur)
     
    class App(object):
        """ Application principal """
     
        def __init__(self, larg = 200, haut = 200):
     
            self.larg = larg
            self.haut = haut
     
            # Fenetre principal
            self.root = Tk()
     
            # Canvas de la fenetre principal
            self.can = Canvas(self.root, width = self.larg,
                              height = self.haut, bg = "black")
            self.can.pack(side = TOP)
     
            # Bouton pour quitter qui s'ajuste à la largeur
            # de la fenêtre d'où le "int(larg/7)"
            Button(self.root, text="Quitter", bg="dark grey",
                   width = int(larg/7), command =
                   self.root.quit).pack(side = BOTTOM)
     
            # Appel la classe qui créera le joueur et le
            # positionne au centre
            Joueur(self.can, self.larg/2, self.haut-20)
            # Appel la classe qui va créé un météor
            Meteor(self.can)
     
        def mainloop(self):
            "Methode qui referme la fenetre"
            self.root.mainloop()
            self.root.destroy()
     
    if __name__ == "__main__":
     
        play = App(600, 600)
        play.mainloop()

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Mai 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 54
    Points : 28
    Points
    28
    Par défaut
    J'ai réécris mon code afin de lui enlever la class App, qui étais vraiment inutile comme tu m'avais dit, mais je reste toujours avec mon problème que je ne sais pas comment dire a l'ordi d'effacer les météorites quand il croise un projectiles

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
     
    # -*- coding:Latin-1 -*-
     
    from tkinter import *
    from random import randrange
     
    class Meteor(object):
        """ Crée un météorite """
        def __init__(self, can):
     
            self.can = can
     
            # Récupère la taille du canvas
            self.tailleCanX = int(self.can.cget("width"))
            self.tailleCanY = int(self.can.cget("height"))
     
            # Génère une position X aléatoire
            self.posMX = randrange(5, self.tailleCanX-5)
     
            self.meteor = self.can.create_oval(self.posMX,
                                                    0,self.posMX+20, 20, fill = "white")
     
            self.deplaceMeteor()
            # Génére un nouveau météor
            self.can.after(1000, self.repete)
     
        def repete(self):
            """ Réappelle un Meteor """
            Meteor(self.can)
     
        def deplaceMeteor(self):
            """ Déplace le météor vers le bas du canvas """
     
            # Récupère la position du météor
            self.posM = self.can.coords(self.meteor)
            self.posMY = self.posM[1]
     
            # détruit le météor s'il sort du canvas
            if self.posMY < self.tailleCanY:
                self.can.move(self.meteor, 0, +
                              10)
                self.can.after(30, self.deplaceMeteor)
            else:
                self.can.delete(self.meteor)
     
    class Tire(object):
        """ Crée un projectile et le deplace """
        def __init__(self, can, posJoueur):
     
            self.can = can
     
            # Récupère la position du joueur
            self.posJoueur = posJoueur
            self.posJX = self.posJoueur[0]
            self.posJY = self.posJoueur[1]
     
            # Crée le projectile
            self.lazer = self.can.create_oval(self.posJX+5, self.posJY-10,
                                              self.posJX+15, self.posJY,
                                              fill = "blue")
     
            # Appel de la fonction qui deplace le projectile
            self.deplaceTire()
     
        def deplaceTire(self):
            " Déplace le projectile jusqu'en haut du canvas "
     
            # Récupère la position du projectile
            self.posLazer = self.can.coords(self.lazer)
            self.posLazerY = self.posLazer[1]
     
            # Détruit le lazer s'il sort du canvas
            if self.posLazerY > 0:
                self.can.move(self.lazer, 0, -10)
                self.can.after(30, self.deplaceTire)
            else:
                self.can.delete(self.lazer)
     
    class Joueur(object):
     
        def __init__(self, can):
     
            self.can = can
     
            # Récupère la taille du canvas
            self.canWidth = self.can.cget("width")
            self.canHeight = self.can.cget("height")
     
            # Converti la taille en chiffre (int) et positionne
            # player en centre du canvas
            self.posX = int(self.canWidth) / 2 - 10
            self.posY = int(self.canHeight) - 20
     
            self.player = self.can.create_rectangle(self.posX,
                                                    self.posY, self.posX+20,
                                                    self.posY+20, fill = "red")
     
            # Détection d'évènement
            self.can.bind("<Motion>", self.deplaceJoueur)
            self.can.bind("<1>", self.tire)
     
        def deplaceJoueur(self, event):
     
            # Récupère la position en X de la souri
            self.mouseX = event.x - 10 # -10 pour se centrer
     
            # Déplace player selon la souri
            self.can.coords(self.player, self.mouseX, self.posY,
                            self.mouseX+20, self.posY+20)
     
        def tire(self, event):
     
            # Récupère la position du joueur
            self.posJ = self.can.coords(self.player)
     
            # Appel de la class Tire avec position joueur
            Tire(self.can, self.posJ)
     
     
    if __name__ == "__main__":
     
        root = Tk()
     
        can = Canvas(root, width = 600, height = 600, bg = "black")
        can.pack()
     
        Button(root, text = "Quit", bg = "dark grey", command = root.quit,
               width = 600//7).pack(side = BOTTOM)
     
        Joueur(can)
        Meteor(can)
     
        root.mainloop()
        root.destroy()

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Mai 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 54
    Points : 28
    Points
    28
    Par défaut
    Après plusieurs heures de recherche dans tout les sens,

    j'en n'ai conclu que vue que j'ai plusieurs météorites et plusieurs projectiles et que je dois comparer la position en x et y de chaque projectiles avec chaque météorite, de plus, je doit éliminer le projectile et le météorite qui se sont toucher, je ferais mieux de mettre chaque projectile et météorite dans une liste avec leur coordonnée.

    Est-ce que sa du sens se que je dis? si oui, et bien il me reste à trouver une façon de faire sa... Y a t'il des trucs de programmeur pour arriver a sa car je suis un peu perdu là?

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 285
    Points : 36 773
    Points
    36 773
    Par défaut
    Salut,

    Pour l'instant ce n n'est pas une question de code, mais de design i.e. comment faire un rendu visuel pas trop dégueux avec un minimum de code.

    L'idée sur laquelle il faudrait peut être bosser, c'est:
    Lorsque le player tire, le shoot du laser sera définit par les coordonnées (cx, y0, y1) construites à partir de la position du player lorsque qu'il génère l'événement '<1>'.
    Le shoot 'monte' à la vitesse du / delay

    Les meteors sont définis par les coordonnées (x0, y0, x1, y1): le rectangle qui englobe l'item sur le canvas.
    Les meteors tombent à la vitesse dv / delay.

    Côté détection d'une collision entre un shoot S et un meteor, on peut simplifier en posant qu'elle a eu lieu lorsque la condition C(M, S):
    M.x0 <= S.cx <= M.x1 *et* M.y1 >= S.y0
    est vraie.

    Reste à traiter la multiplicité des shoots et des meteors.
    Quelque part à l'instant t, nous avons un ensemble active_shoots et un ensemble active_meteors qui ne vérifient pas C (et d'autres conditions).
    A t+delta, il faut mettre à jour ces ensembles après avoir éliminés ceux qui vérifient C.

    J'ai essayé d'écrire en:
    • bold: les objets de "conception",
    • italique: les objets de la réalisation (liés au choix de Tk).


    Un objet "conception" pourra être représenté dans le "code" de différentes façons. On pourra choisir de les représenter avec des instances de "class", construire plusieurs listes de..., utiliser les informations stockées dans les items du canvas ou fabriquer une copie "locale" dans le code Python,...
    Les motivations du choix seront:
    • "arbitraires": vous vous imposer des règles et vous les appliquez,
    • "circonstanciées": le choix le plus adapté en fonction de critères non fonctionnels genre: le moins de lignes de code, le plus performant côté CPU, le plus maintenable,...
      note: au moins on saura "mesurer", "quantifier" au plus il y aura débat entre les options possibles.


    On fait ce qu'on veut mais si le design du code s'éloigne du design de la conception, il va falloir expliquer "comment" la réalisation respecte bien la conception. Ce sont des relations de traçabilité entre ces objets.

    J'adore Python car il permet de faire des prototypes ou on peut réaliser un code proche du "design de conception". Il ne sera pas "optimisé" mais si l'idée qu'on essaie de traduire en code ne fonctionne pas, le temps passé à essayer de l'optimiser ne sert à rien.

    A vous de voir ce que vous pouvez faire avec tout çà.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 285
    Points : 36 773
    Points
    36 773
    Par défaut
    Pour le fun, j'ai codé cela en essayant d'utiliser raisonnablement les fonctionnalités Tk. La gestion des informations pour traiter les collisions est "bourrin" de chez "bourrin".
    Ca donne une chose comme çà:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    # -*- coding:utf-8 -*-
     
    import tkinter as tk
    from random import randrange
     
    def player_create():
        x0 = WIDTH // 2
        y0 = HEIGHT - 30
        x1, y1 = x0 + 20, y0 + 20
        return canvas.create_rectangle(x0, y0, x1, y1, fill='red', tag='player')
     
    def player_move(x):
        x0, _, x1, _ = canvas.bbox('player')
        cx = (x0 + x1) // 2
        dx = x - cx
        canvas.move('player', dx, 0)
     
    SHOOT_DV = 10
    def shoot_create():
        x0, y, x1, _ = canvas.bbox('player')
        cx = (x0 + x1) // 2
        canvas.create_line(cx, y-30, cx, y, fill='blue', tag='shoot')
     
    def shoot_move(iid):
        _, y0, _, _ = canvas.bbox(iid)
        if y0 > 0:
            canvas.move(iid, 0, -SHOOT_DV)
        else:
            canvas.delete(iid)
     
    active_shoots = lambda: canvas.find_withtag('shoot')
     
    METEOR_DV = 5
    def meteor_create(cx, cy):
        canvas.create_rectangle(
            cx - 10, cy - 10, cx + 10, cy + 10, fill='blue', tag='meteor')
     
    def meteor_move(iid):
        _, _, _, y1 = canvas.bbox(iid)
        if y1 < HEIGHT:
            canvas.move(iid, 0, METEOR_DV)
        else:
            canvas.delete(iid)
     
    active_meteors = lambda: canvas.find_withtag('meteor')
     
    def eventloop(delta=50):
     
        def launch_meteor():
            cx = randrange(10, WIDTH - 10)
            meteor_create(cx, 5)
            canvas.after(1000, launch_meteor)
     
        def do_move():
     
            [ shoot_move(iid) for iid in active_shoots() ]
            [ meteor_move(iid) for iid in active_meteors() ]  
            canvas.update()
     
        def handle_collisions():
            shoots = active_shoots()
            meteors = list(active_meteors())
            for s in shoots:
                x0, s_y0, x1, _ = canvas.bbox(s)
                s_cx = (x0 + x1) // 2
                for m in meteors:
                    m_x0, _, m_x1, m_y1 = canvas.bbox(m)
                    if m_x0 <= s_cx <= m_x1 and m_y1 >= s_y0:
                        canvas.delete(s)
                        canvas.delete(m)
                        meteors.remove(m)
     
        def do_updates():
            do_move()
            handle_collisions()
            app.after(delta, do_updates)
     
        app.after(delta, do_updates)
        app.after(500, launch_meteor)
     
    if __name__ == "__main__":
     
        WIDTH = HEIGHT = 600
     
        app = tk.Tk()
        tk.Button(app, text='Quit', bg="dark grey", command=app.quit
                  ).pack(fill='x', side='bottom')
     
        canvas = tk.Canvas(app, width=WIDTH, height=HEIGHT)
        player_create()
        canvas.pack(side='top')
        canvas.bind('<Motion>', lambda e: player_move(e.x))
        canvas.bind('<1>', lambda e: shoot_create())
     
        eventloop()   
        tk.mainloop()
    J'utilise sans scrupule quelques variables globales: app, canvas,... pour alléger le nombre de paramètres à passer aux fonctions appelées.
    Le canvas permettant d'associer un tag aux items crées, j'utilise cela pour catégoriser les différents items: 'joueur', 'shoot', 'meteor'.
    Ca évite de "catégoriser" via la création de "class" Python.

    Bonne lecture.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Mai 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 54
    Points : 28
    Points
    28
    Par défaut
    Super votre code, je suis presque j'alloue, en plus vous avez l'aire d'avoir programmer sa en deux minutes sur le coin d'une table en mangeant un muffin tellement sa vous apparait simple

    J'ai commencé à suivre le programme pas à pas afin de comprendre tout sa, je me suis amusé à renommer les variables en des noms plus évocateur pour m'aider à tout comprendre, et j'avoue avoir bûcher sur les expressions lambda, surtout le (e.x) je comprenais pas d'où sa venais, mais en changeant tout sa pour un event et event.x j'en n'ai conclu que le "e.x" étais pareil à "event.x", je n'avais pas compris le return à la function player_create je l'ai donc enlevé et sa la rien changé... Est-ce normal?

    Mais là, je ne comprend pas du tout la fonction eventloop() surtout ce bout là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
        def do_move():
     
            [ shoot_move(iid) for iid in active_shoots() ]
            [ meteor_move(iid) for iid in active_meteors() ]  
            can.update()
    je ne comprend pas les crochets (est-ce que c'est une genre de liste?), et le iid (je suppose que c'est le nom ou l'adresse du shoots ou du meteors, mais je comprend pas comment sa marche)

    Loin de moi l'idée de vous demandez un cour sur python, mais pourriez-vous m'éclairer sur ces points?

    P.S. Je me suis permis en jouant dans le code d'amiliorer l'aspect visuel du jeu, voici où j'en suis pour les interresser:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
     
    # -*- coding:utf-8 -*-
     
    from tkinter import *
    from random import randrange
     
    def creeJoueur():
        """ Créé un joueur et le centre dans l'écran """
     
        posX1, posY1 = larg // 2, haut - 30
     
        can.create_rectangle(posX1, posY1, posX1+20,
                             posY1+20, fill="yellow", tag="joueur")
     
    def deplaceJoueur(event):
        """ Déplacement du joueur """
     
        posXSouri = event.x
        posX1, _, posX2, _ = can.bbox("joueur") # Crée une Boite autour de l'objet en tag
                                                # sous la forme d'une liste [x, y, x1, y1]
        posXCentrer = (posX1 + posX2) // 2
        posXJoueur = posXSouri - posXCentrer
     
        can.move("joueur", posXJoueur, 0)
     
    SHOOT_DV = 10
    def creeLazer(event):
        """ Crée un projectile """
        posX1, posY1, posX2, _ = can.bbox("joueur") # Crée une Boite autour de l'objet en tag
                                                    # sous la forme d'une liste [x, y, x1, y1]
        posXCentrer = (posX1 + posX2) // 2
        can.create_oval(posXCentrer-5, posY1-30, posXCentrer+5,
                        posY1-40, fill="red", tag="lazer")
     
    def shoot_move(iid):
        _, y0, _, _ = can.bbox(iid)
        if y0 > 0:
            can.move(iid, 0, -SHOOT_DV)
        else:
            can.delete(iid)
     
    active_shoots = lambda: can.find_withtag('lazer')
     
    METEOR_DV = 5
    def meteor_create(cx, cy):
        can.create_oval(
            cx - 10, cy - 10, cx + 10, cy + 10, fill="dark orange", tag='meteor')
     
    def meteor_move(iid):
        _, _, _, y1 = can.bbox(iid)
        if y1 < haut:
            can.move(iid, 0, METEOR_DV)
        else:
            can.delete(iid)
     
    active_meteors = lambda: can.find_withtag('meteor')
     
    def eventloop(vitesseAnim = 50):
     
        def launch_meteor():
            cx = randrange(10, larg - 10)
            meteor_create(cx, 5)
            can.after(1000, launch_meteor)
     
        def do_move():
     
            [ shoot_move(iid) for iid in active_shoots() ]
            [ meteor_move(iid) for iid in active_meteors() ]  
            can.update()
     
        def handle_collisions():
            shoots = active_shoots()
            meteors = list(active_meteors())
            for s in shoots:
                x0, s_y0, x1, _ = can.bbox(s)
                s_cx = (x0 + x1) // 2
                for m in meteors:
                    m_x0, _, m_x1, m_y1 = can.bbox(m)
                    if m_x0 <= s_cx <= m_x1 and m_y1 >= s_y0:
                        can.delete(s)
                        can.delete(m)
                        meteors.remove(m)
     
        def do_updates():
            do_move()
            handle_collisions()
            root.after(vitesseAnim, do_updates)
     
        root.after(vitesseAnim, do_updates)
        root.after(500, launch_meteor)
     
    if __name__ == "__main__":
     
        larg, haut = 800, 600
     
        # Fenêtre principal
        root = Tk()
     
        # Bouton quitter
        Button(root, text="Quit", bg="dark grey", command=root.quit
                  ).pack(fill = "x", side= BOTTOM)                      # fill "x" ajuste le bouton à la taille
                                                                        # de la fenêtre en X
        # Canvas principal de l'animation
        can = Canvas(root, width=larg, height=haut, bg = "black")
        can.pack()
     
        can.create_rectangle(0, haut-10, larg, haut,                    # Crée un rectangle qui représente    
                             fill = "dark green")                       # le sol
     
        # ----- Moteur du jeu ----- #
        creeJoueur()
     
        # Détection des évènements
        can.bind('<Motion>', deplaceJoueur)
        can.bind('<1>', creeLazer)
     
        eventloop()
     
        root.mainloop()
        root.destroy()

  12. #12
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 285
    Points : 36 773
    Points
    36 773
    Par défaut
    Citation Envoyé par PascalStl Voir le message
    Super votre code, je suis presque j'alloue, en plus vous avez l'aire d'avoir programmer sa en deux minutes sur le coin d'une table en mangeant un muffin tellement sa vous apparait simple
    Coder n'est pas un soucis lorsqu'on sait ce qu'on veut _et_ qu'on a acquis une expérience Python, Tk,... Le débutant est embêté s'il sait ce qu'il veut, il doit "découvrir" comment exprimer cela en programmant. In fine, le code fonctionne mais les idées sont noyées dans les tâtonnements de la mise au point. C'est normal: les gamins de 3 ans qui écrivent des poésies ou des symphonies sont rares. La plupart se révèlent après avoir appris à parler, jouer d'un instrument,...

    L'exercice ici c'est comme si on disait "écrire un poème en alexandrin", un "bouquin sans utiliser de voyelles":
    • aligner le code avec la conception,
    • utiliser les informations maintenues par Tk (plutôt que de les gérer côté Python),
    • éviter l'utilisation de "class"
    • optimiser "plus tard"


    J'ai commencé à suivre le programme pas à pas afin de comprendre tout sa, je me suis amusé à renommer les variables en des noms plus évocateur pour m'aider à tout comprendre, et j'avoue avoir bûcher sur les expressions lambda, surtout le (e.x)
    Il est généralement plus simple de commencer par écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    def on_motion(event):
         player_move(event.x)
    canvas.bind('<Motion>', on_motion)
    Lorsqu'il n'y a pas plus d'action à déclencher dans le "on_...", on peut s'amuser à supprimer le on_motion pour le remplacer par un équivalent "lamdba".

    je n'avais pas compris le return à la function player_create je l'ai donc enlevé et sa la rien changé... Est-ce normal?
    C'est un gribouillage du à mon indécision sur traiter ou pas player comme meteor et shoot. Comme il n'y a qu'une instance de player, l'identifiant de l'item passé dans une variable globale "player" ou "player" chaine de caractère pour récupérer l'item?
    Comme quoi les gribouillis se voient.

    Mais là, je ne comprend pas du tout la fonction eventloop() surtout ce bout là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
        def do_move():
     
            [ shoot_move(iid) for iid in active_shoots() ]
            [ meteor_move(iid) for iid in active_meteors() ]  
            can.update()
    Littéralement,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [ shoot_move(iid) for iid in active_shoots() ]
    s'appelle "compréhension de liste". C'est équivalent à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for iid in active_shoots():
        shoot_move(iid)
    C'est parce que j'ai passé trop de temps sur handle_collisions que je trouve assez dégueux mais comme j'ai posé "optimiser après". On pourrait dire que les lambda sont aussi des "optimisations" prématurées et les virer.
    Je posterai une mise à jour tantôt si j'ai du temps.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Mai 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 54
    Points : 28
    Points
    28
    Par défaut
    J'ai tout réécris sa cette nuit (je décroche pas facilement hahah), je me suis basé sur votre logique et maintenant je comprend beaucoup mieux, c'est bien d'avoir pu comparer deux codes différent qui font la même chose au final celà ma permis d'y voir plus clair. Voici le nouveau code avec commentaire et quelque modification (je crois qu'il ne reste qu'à optimiser rendu là):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
     
    # -*- coding:utf-8 -*-
     
    from tkinter import *
    from random import randrange
     
    def creeJoueur():
        """ Créé un joueur et le centre dans l'écran """
     
        posX1, posY1 = larg // 2, haut - 30
     
        can.create_rectangle(posX1, posY1, posX1+20,
                             posY1+20, fill="yellow", tag="joueur")
     
    def deplaceJoueur(event):
        """ Déplacement du joueur """
     
        posXSouri = event.x
        posX1, _, posX2, _ = can.bbox("joueur") # Crée une Boite autour de l'objet en tag
                                                # sous la forme d'une liste [x, y, x1, y1]
        posXCentrer = (posX1 + posX2) // 2
        posXJoueur = posXSouri - posXCentrer
     
        can.move("joueur", posXJoueur, 0)
     
     
    def creeLazer(event):
        """ Crée un projectile """
     
        posX1, posY1, posX2, _ = can.bbox("joueur") # Crée une Boite autour de l'objet en tag
                                                    # sous la forme d'une liste [x, y, x1, y1]
        posXCentrer = (posX1 + posX2) // 2
        can.create_oval(posXCentrer-5, posY1-30, posXCentrer+5,
                        posY1-40, fill="red", tag="lazer")
     
    def deplaceLazer(nbIdent):
        """ Deplace l'objet Lazer selon son numéro d'identification """
     
        _, posY1, _, _ = can.bbox(nbIdent)
        if posY1 > 0:
            can.move(nbIdent, 0, vitesse_Lazer)
        else:
            can.delete(nbIdent)
     
    def activeLazer():
        """ Returne le numéro d'identification de chaque Lazer """
     
        return can.find_withtag("lazer")
     
    def creeMeteor():
        """ Crée un météor selon un emplacement en X aléatoire """
        posX = randrange(10, larg - 10)
        can.create_oval(posX - 10, -5, posX + 10,
                        15, fill="dark orange", tag='meteor')
     
        can.after(vitesse_Gen_Meteor, creeMeteor)
     
    def deplaceMeteor(nbIdent):
        """ Déplace le météor selon son numéro d'identification """
     
        _, _, _, posY2 = can.bbox(nbIdent)
        if posY2 < haut:
            can.move(nbIdent, 0, vitesse_Meteor)
        else:
            can.delete(nbIdent)
     
    def activeMeteor():
        """ Returne le numéro d'identification de chaque Lazer """
     
        return can.find_withtag("meteor")
     
    def deplacement():
        """ Appel le déplacement pour chaque numéro d'identification """
     
        for nbIdent in activeLazer():
            deplaceLazer(nbIdent)
            can.update()
     
        for nbIdent in activeMeteor():
            deplaceMeteor(nbIdent)
            can.update()
     
    def collision():
        """ Vérifie s'il y a une collision entre Lazer et Météor """
     
        lazerActif = activeLazer()
        meteor = list(activeMeteor())
     
        for s in lazerActif:
            x0, s_y0, x1, _ = can.bbox(s)
            s_cx = (x0 + x1) // 2
            for m in meteor:
                m_x0, _, m_x1, m_y1 = can.bbox(m)
                if m_x0 <= s_cx <= m_x1 and m_y1 >= s_y0:
                    can.delete(s)
                    can.delete(m)
                    meteor.remove(m)
     
    def animation():
        """ Horloge du jeu """
     
        deplacement()
        collision()
     
        # Détection des événements
        can.bind('<Motion>', deplaceJoueur)
        can.bind('<1>', creeLazer)
     
        root.after(vitesse_Anim, animation) # Cadence la vitesse du jeu
     
    def demarrer():
        """ Démarrage du jeu """
        global start
     
        if start == 0:
            creeJoueur()
            animation()
            root.after(2000, creeMeteor) # Les météors commence à tombe apres le délais
            start = 1
     
    if __name__ == "__main__":
     
        # Option d'ajustement du jeu
        larg, haut = 800, 600       #Dimension de la fenêtre
        vitesse_Anim = 50           #Horloge du jeu
        vitesse_Meteor = 5          #Vitesse de descente des météors
        vitesse_Lazer = -10         #Vitesse de monter des projectiles
        vitesse_Gen_Meteor = 1000   #Nombre de météors générer par millisecondes
     
        start = 0   #Variable global lier au bouton demarrer et à demarrer() sert
                    #à avoir une utilisation unique du bouton
     
        # Fenêtre principal
        root = Tk()
     
        # Canvas principal de l'animation
        can = Canvas(root, width=larg, height=haut, bg = "black")
        can.pack()
     
        can.create_rectangle(0, haut-10, larg, haut,                    # Crée un rectangle qui représente    
                             fill = "dark green")                       # le sol
     
        # Commande du jeu
        Button(root, text="Quit", bg="dark grey", command=root.quit
                  ).pack(fill = "x", side = BOTTOM)                     # fill "x" ajuste le bouton à la taille
                                                                        # de la fenêtre en X
        Button(root, text="Demarrer", bg="dark grey", command=demarrer
               ).pack(fill = "x", side = BOTTOM)
     
        root.mainloop()
        root.destroy()

  14. #14
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 285
    Points : 36 773
    Points
    36 773
    Par défaut
    Salut,
    Dommage qu'on ne puisse pas mettre a jour les vieux messages.
    Dans les explications, il faut ajouter des explications sur eventloop.
    A priori, la persistance visuelle permet de créer une illusion de mouvement en mettant a jour l'affichage tous les 20iemes de secondes. C'est comme au cinéma.
    eventloop soumet do_updates dès que possible et do_updates se re-soumet après avoir traité les collisions et modifié la position des items. Il n'est pas utile d'empiler tous les changements en attendant que do_updates les execute.
    Mais c'est l'idee.
    Par exemple, il n'est pas utile de mettre a jour la position de player a chaque déplacement de souris. L'illusion de mouvement permet d'attendre. Mais l'ajout de fonctionnalités = ajout de code... On voit que la construction commence a faire désordre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    import tkinter as tk
    from random import randrange
     
    def player_create():
        global player
        x0 = WIDTH // 2
        y0 = HEIGHT - 30
        x1, y1 = x0 + 20, y0 + 20
        player = canvas.create_rectangle(x0, y0, x1, y1, fill='red')
     
    def player_move(x):
        x0, _, x1, _ = canvas.bbox(player)
        cx = (x0 + x1) // 2
        dx = x - cx
        canvas.move(player, dx, 0)
     
    SHOOT_DV = 10
    def shoot_create():
        _, y, _, _ = canvas.bbox(player)
        cx = player_lastcx
        canvas.create_line(cx, y-30, cx, y, fill='blue', tag='shoot')
     
     
    def shoot_move(iid):
        _, y0, _, _ = canvas.bbox(iid)
        if y0 > 0:
            canvas.move(iid, 0, -SHOOT_DV)
        else:
            canvas.delete(iid)
     
     
    METEOR_DV = 5
    def meteor_create(cx, cy):
        canvas.create_rectangle(
            cx - 10, cy - 10, cx + 10, cy + 10, fill='blue', tag='meteor')
     
    def meteor_move(iid):
        _, _, _, y1 = canvas.bbox(iid)
        if y1 < HEIGHT:
            canvas.move(iid, 0, METEOR_DV)
        else:
            canvas.delete(iid)
     
     
    import time
     
    def eventloop(delta=50):
     
        active_shoots = lambda: canvas.find_withtag('shoot')
        active_meteors = lambda: canvas.find_withtag('meteor')
     
        count = 10
     
        def do_updates():
            nonlocal count
     
            tstart = time.clock()
     
            player_move(player_lastcx)
     
            # handle collisions
            shoots = list(active_shoots())
            meteors = list(active_meteors())
            for s in shoots:
                x0, s_y0, x1, _ = canvas.bbox(s)
                s_cx = (x0 + x1) // 2
                for m in meteors:
                    m_x0, _, m_x1, m_y1 = canvas.bbox(m)
                    if m_x0 <= s_cx <= m_x1 and m_y1 >= s_y0:
                        canvas.delete(s)
                        shoots.remove(s)
                        canvas.delete(m)
                        meteors.remove(m)
     
            # move objects
            for iid in active_shoots():
                shoot_move(iid)
            for iid in active_meteors():
                meteor_move(iid)
     
            # launch_meteor?
            if count <= 0:
                count = 1000 // delta
                cx = randrange(10, WIDTH - 10)
                meteor_create(cx, 5)
            else:
                count -= 1
     
            # ensure computations were fast enough
            duration = (time.clock() - tstart) * 1000
            delay = delta - duration
            assert delay > 5
     
            app.after(int(delay), do_updates)
     
        app.after_idle(do_updates)
     
     
     
    if __name__ == "__main__":
     
        WIDTH = HEIGHT = 600
     
        app = tk.Tk()
        app['menu'] = menu = tk.Menu()
     
        menu.add_command(label='Quit', command=app.quit)
        #+ setup canvas
        canvas = tk.Canvas(app, width=WIDTH, height=HEIGHT)
     
        player_lastcx = 0                             
        def on_motion(event):
            global player_lastcx
            player_lastcx = event.x
     
        def on_b1_click(event):
            shoot_create()
     
        canvas.bind('<Motion>', on_motion)
        canvas.bind('<1>', on_b1_click)
        #- setup canvas
     
        canvas.pack(side='top')
        player_create()
     
        eventloop()
        tk.mainloop()
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 285
    Points : 36 773
    Points
    36 773
    Par défaut
    Citation Envoyé par PascalStl Voir le message
    Voici le nouveau code avec commentaire et quelque modification (je crois qu'il ne reste qu'à optimiser rendu là):
    Personnellement, j’évite d'utiliser des nom français pour mes variables. Ca aboutit a des bouts de phrase qui posent question: creeJoueur s'impose a
    joueur_creer. Mais faire que ce qui touche a Jouer commence par "joueur" permettra de regrouper l'ensemble des fonctions qui... grâce a l'ordre alphabétique sans passer par la boite "class".

    Il est plus simple de massacrer l'anglais et écrire player_create au lieu de joueur_creer. L'autre raison est qu'il n'y a pas loin entre player_create et player.create. Si on veut pousser la définition de ces fonctions dans un module ou une classe, les changements a faire dans le code seront plus simple.

    Déclarer des fonctions dans des fonctions est une façon de regrouper des fonctions qui travaillent sur un même ensemble de variables (autre que modules et classes).
    Sinon, écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def deplacement():
        """ Appel le déplacement pour chaque numéro d'identification """
     
        for nbIdent in activeLazer():
            deplaceLazer(nbIdent)
            can.update()
     
        for nbIdent in activeMeteor():
            deplaceMeteor(nbIdent)
            can.update()
    can.update va mettre a jour l'affichage après la mise a jour de chaque item. Une seule fois a la fin suffit.

    nota, dans le dernier code que j'ai commis, les collisions sont traitées avant les déplacements. On affiche un truc faux pendant un 20ieme de seconde, mais on évite deux appels a active_xxx et canvas.update se fera après. Ce n'est pas une optimisation, c'est juste une implication de l'utilisation de la vitesse de rafraîchissement pour effectuer les mises a jours. Il faut essayer d’être cohérent.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 05/05/2009, 17h57
  2. probleme d'affichage sur objet TPaintBox
    Par Nephi dans le forum C++Builder
    Réponses: 2
    Dernier message: 04/07/2008, 11h41
  3. probleme sur objet excel application
    Par micka180 dans le forum VBScript
    Réponses: 3
    Dernier message: 04/10/2007, 10h54
  4. suivre un objet en mouvement sur image
    Par jlf dans le forum Traitement du signal
    Réponses: 24
    Dernier message: 09/05/2005, 13h46
  5. [UDP][Socket] perte de paquets et arret d'ecoute sur port
    Par Guismo1979 dans le forum Développement
    Réponses: 6
    Dernier message: 02/01/2003, 12h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo