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

Tkinter Python Discussion :

Jeu de labyrinthe - Animation d'une balle.


Sujet :

Tkinter Python

  1. #21
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par FatP0ney Voir le message
    C'est ce que je pensais... Ca ne marcherait pas?
    Si si, c'est parfaitement juste, mais pourquoi ne pas le dire tout simplement : "je fais mon test dans move()".

    Oubliez les tests que vous avez faits jusqu'à maintenant : il existe une solution largement plus simple qui tient en UNE SEULE LIGNE de test.

    Je vous donne des indices :

    Dans la documentation Tkinter :

    http://infohost.nmt.edu/tcc/help/pub...s-methods.html

    intéressez-vous à la méthode canvas.find_overlapping() dans un premier temps puis à canvas.bbox() ensuite.

    Que font ces méthodes ?

    Lisez bien ce qui y est consigné et essayez d'imaginer comment vous pourriez construire un test avec ces ingrédients.

  2. #22
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par tarball69 Voir le message
    Oubliez les tests que vous avez faits jusqu'à maintenant : il existe une solution largement plus simple qui tient en UNE SEULE LIGNE de test.
    Une ligne ! hu?!? Je veux voir ;-)

    L'exemple suivant affiche des rectangles (rangés en une sorte de labyrinthe mais c'est juste pour le fun: on peut les poser n'importe comment). Lorsqu'on clique, çà affiche un carré et les rectangles qui contiennent un des côtés jusqu'à ce qu'on relache. Si un des côtés est à l'extérieur, çà n'affiche rien.
    J'ai délibérément évité de crééer côté Python des varables pour stocker la position du "carré": on interroge Tk un peu trop.

    Pour le reste, j'ai deux problèmes:
    1 - faire faire par Tk évite de calculer et modéliser côté Python le contour du labyrinthe, c'est quand même dommage car çà pourrait illustrer ce que ces terminales ont appris en maths.
    2 - d'un point de vue informatique, un labyrinthe est un graphe et si on utilise "graphe" comme "modèle", la partie Tk n'a pas besoin de s'appuyer sur "find_overlapping" et autres bbox.
    - W

    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
     
    '''tk flavor:
    use moderately Python variables.
    '''
     
    import tkinter as tk
    from tkinter.constants import *
    import random
     
    def get_bbox_center():
        x0, y0, x1, y1 = canvas.bbox('bbox')
        return (x0+x1) // 2, (y0+y1) // 2
     
    show_bbox = lambda: canvas.itemconfigure('bbox', state=NORMAL)   
    hide_bbox = lambda: canvas.itemconfigure('bbox', state=HIDDEN) 
     
    def show_bbox_at(x, y):
        show_bbox()
        u, v = get_bbox_center()
        dx = x - u
        dy = y - v
        canvas.move('bbox', dx, dy)
     
     
    def set_items_white(items):
        for iid in items:
            canvas.itemconfigure(iid, fill='white')
            canvas.addtag_withtag('white', iid)
     
    def clear_white_items():
        for iid in canvas.find_withtag('white'):
            canvas.itemconfigure(iid, fill='grey50')
            canvas.dtag(iid, 'white')
     
    def on_b1_press(x, y):
     
        show_bbox_at(x, y)
        x0, y0, x1, y1 = canvas.bbox('bbox')
        hide_bbox()
     
        x0, y0, x1, y1 = x0+1, y0+1, x1-1, y1-1
        samples = [ (x0, y0, x0, y0),
                    (x1, y0, x1, y0),
                    (x1, y1, x1, y1),
                    (x0, y1, x0, y1),              
                  ]
     
        items = set()
        for sample in samples:
            others = set(canvas.find_overlapping(*sample))
            if others:
                items = items.union(others)
            else:
                items = None
                break
     
        if items:        
            set_items_white(items)
        show_bbox()
     
    def on_b1_release():
        hide_bbox()
        clear_white_items()
     
    def create_laby(width):
     
        x0, y0 = 100, 100
        dx = 400
        dy = 300
        w = width
     
        bbox_list = [
            (x0, y0, x0+dx, y0+w),
            (x0, y0+w, x0+w, y0+dy+w),
            (x0, y0+dy, x0+(dx//2), y0+dy+w),
            (x0+(dx//2)+w, y0+w, x0+(dx//2)+2*w, y0+dy+w)
            ]
        for bbox in bbox_list:
            canvas.create_rectangle(bbox, fill='grey50', tag='items', activeoutline='red')
     
     
    width = height = 600    
    app = tk.Tk()
     
    canvas = tk.Canvas(app, width=width, height=height)
    # create items
    create_laby(width=50)
    # create bbox
    cx = cy = 0
    r = 30 // 2
    coords = cx - r, cy - r, cx + r, cy +r
    canvas.create_rectangle(coords, fill='white', tag='bbox')
     
    hide_bbox()
    canvas.bind('<ButtonPress-1>', lambda e: on_b1_press(e.x, e.y))
    canvas.bind('<ButtonRelease-1>', lambda e: on_b1_release())
     
    canvas.pack()
    app.mainloop()
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #23
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Une ligne ! hu?!? Je veux voir ;-)
    Voici, monseigneur

    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
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    from Tkinter import *
    from random import randrange
    #~ from partie1_coord_droite_finie import est_dans_polygone
     
    # procédure générale de déplacement :
     
    def move():
        global dep, sx, sy
        #~ if est_dans_polygone(XY,r, Droite1, Droite2) = False :
           #~ command=pause
        # voici la fameuse ligne unique :
        # la balle se retrouve-t-elle seule ?
        if len(can1.find_overlapping(*can1.bbox(cerc1))) < 2:
            game_over()
        # la balle est au moins sur un rail
        else:
            can1.move(cerc1, sx*dep, sy*dep)
            can1.after(100, move)
     
     
    def game_over():
        # la partie est finie !
        left = can1.winfo_reqwidth() // 2
        top = can1.winfo_reqheight() // 2
        can1.create_text(
            left, top - 40,
            text="GAME OVER!",
            font="sans 24 bold",
            fill="gold",
        )
     
     
    # gestionnaires d'évènements:
    def dep1_gauche(event=None):
        global sx, sy
        sx = -1
        sy = 0
     
    def dep1_droite(event=None):
        global sx, sy
        sx = 1
        sy = 0
     
    def dep1_haut(event=None):
        global sy, sx
        sy = -1
        sx = 0
     
    def dep1_bas(event=None):
        global sy, sx
        sy = 1
        sx = 0
     
    def start_it():
        "démarrage de l'animation"
        global flag
        flag = not flag
        move()
     
    def pause() :
        #nous servira quand on touchera le mur
         "arret de l'animation"
         global flag
         flag =0
     
     
    # Programme principal
     
    # les variables suivantes seront utilisées de manière globale:
    dep = 5   # valeur de deplacement
    X, Y = 90, 65 #coordonnées initiales
    sx, sy = 1, 0
    r = 20
    flag =0   #commutateur
     
    # Création du widget principal ("maître"):
    fen1 = Tk()
    fen1.title("Super Ball")
     
    # création des widgets "esclaves":
    can1 = Canvas (fen1, bg='white', height=500, width=500)
    cerc1 = can1.create_oval(X, Y, X + r, Y + r,fill = 'grey')
    can1.pack(side=LEFT)
    can1.create_rectangle(50,50,100,100) #dessine un rectangle
    can1.create_rectangle(120,280,170,335)
    polygone1 = [100,65,420,65], [100,85,400,85]
    can1.create_line(tuple(polygone1[0]),fill='red',width=4)#ligne 1
    can1.create_line(tuple(polygone1[1]),fill='red',width=4)#ligne 2
    can1.create_line(400,84,400,300,fill='red',width=4)#ligne 3
    can1.create_line(420,65,420,320,fill='red',width=4)#ligne 4
    can1.create_line(170,320,420,320,fill='red',width=4)#ligne 5
    can1.create_line(170,300,400,300,fill='red',width=4)#ligne 5
     
    # passer la balle au premier plan
     
    can1.tag_raise(cerc1, ALL)
     
    Button(fen1, text='Démarrer', command=start_it).pack(side=BOTTOM)
    Button(fen1, text='Quitter', command=fen1.destroy).pack(side=BOTTOM)
    Button(fen1, text='Gauche',command=dep1_gauche).pack()
    Button(fen1, text='Droite', command=dep1_droite).pack()
    Button(fen1, text='Haut', command=dep1_haut).pack()
    Button(fen1, text='Bas', command=dep1_bas).pack()
    Button(fen1, text='Accélère!', command=start_it).pack(side=BOTTOM)
    can1.bind("<z>", dep1_haut)
    can1.bind("<s>", dep1_bas)
    can1.bind("<d>", dep1_droite)
    can1.bind("<q>", dep1_gauche)
     
    # démarrage du réceptionnaire d'évènements (boucle principale):
    fen1.mainloop()
    Pour le reste, j'ai deux problèmes:
    1 - faire faire par Tk évite de calculer et modéliser côté Python le contour du labyrinthe, c'est quand même dommage car çà pourrait illustrer ce que ces terminales ont appris en maths.
    2 - d'un point de vue informatique, un labyrinthe est un graphe et si on utilise "graphe" comme "modèle", la partie Tk n'a pas besoin de s'appuyer sur "find_overlapping" et autres bbox.
    - W
    C'est clair, je ne fais pas dans la dentelle de la belle théorie MVC, mais je m'efforce de rendre les choses les plus simples possibles pour fatponey et ses collègues, du moins, dans un premier temps.

    Mais c'est sûr que ce n'est pas une démonstration très scolaire ce que je propose ici, je le reconnais bien volontiers.

    Et toi -W, comment procéderais-tu ?

  4. #24
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par tarball69 Voir le message
    C'est clair, je ne fais pas dans la dentelle de la belle théorie MVC, mais je m'efforce de rendre les choses les plus simples possibles pour fatponey et ses collègues, du moins, dans un premier temps.
    find_overlapping retourne tous les items qui ont une intersection non vide avec la bbox passée en paramètre. C'est assez différent de "à l’intérieur". Après si on veut un truc qui se contente de marchoter "visuellement", pourquoi pas!

    Et toi -W, comment procéderais-tu ?
    Je prendrais le temps de regarder comment ont déjà été modélisés des problèmes semblables.
    Et avec Internet, c'est pas si difficile à trouver.

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

  5. #25
    Nouveau membre du Club
    Homme Profil pro
    Travail
    Inscrit en
    Avril 2014
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Travail

    Informations forums :
    Inscription : Avril 2014
    Messages : 45
    Points : 34
    Points
    34
    Par défaut
    Bonjour je découvre ce que vous avez réalisé c'est vraiment top ! Merci!
    En grand boulet je n'avais pas vu qu'il y avait une seconde page et je croyais que vous m'aviez laissé à mes petits soucis :p

    Néanmoins j'aimerais bien comprendre si possible ce que vous avez fait :
    Je ne comprends pas du tout ce que vous utilisez pour la fonction move et game over serait il possible de vous demander encore une fois de l'aide par rapport à tous les éléments que vous utilisez? J'ai lu la documentation que vous m'aviez suggéré et si j'ai bien compris on procède par présence ou non de la balle dans un carré à l'extérieur du parcours?

    Néanmoins je pense aussi continuer un peu sur les test que nous avions déja commencé, car comme le dit W, cela permet d'exprimer le contours du polygone en python ce qui relatif au programme de terminale. J'avais d'ailleurs une question à vous poser sur ce thème :
    - dans le fichier est_dans_polygone , notre professeur à utilié "XY" et nous avons donc besoin de le définir mais je ne comprends pas comment on pourrait le faire?

    Merci encore!

  6. #26
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par FatP0ney Voir le message
    Bonjour je découvre ce que vous avez réalisé c'est vraiment top ! Merci!
    En grand boulet je n'avais pas vu qu'il y avait une seconde page et je croyais que vous m'aviez laissé à mes petits soucis :p

    Néanmoins j'aimerais bien comprendre si possible ce que vous avez fait :
    Je ne comprends pas du tout ce que vous utilisez pour la fonction move et game over serait il possible de vous demander encore une fois de l'aide par rapport à tous les éléments que vous utilisez? J'ai lu la documentation que vous m'aviez suggéré et si j'ai bien compris on procède par présence ou non de la balle dans un carré à l'extérieur du parcours?
    Bonjour,

    J'essayais de vous faire voir que l'on pouvait "penser autrement" que par la théorie pure et dure.

    C'est vrai que ce n'est pas très scolaire et -W a parfaitement raison de m'en faire le reproche, mais je ne suis pas partisan de l'application aveugle de la théorie , car cela empêche à force de s'ouvrir à d'autres possibles et c'est bien dommage de se priver d'une vision plus large de ce qui est possible de faire dans la vie, quitte à bidouiller (moi, perso, j'aime bien bidouiller).

    Ceci dit, voici le raisonnement que j'ai mené : dans le cas très particulier de ce jeu, je n'ai pas jugé utile de détecter autre chose que la logique "la balle est-elle seule ?" au lieu de tester la logique "la balle est-elle à l'intérieur des rails (polygones) ?"

    En effet, dès lors que la logique "la balle est seule" est détectée, on sait implicitement que la balle n'est plus sur des rails et donc que la partie est terminée.

    D'où le test dans move() qui aboutit à l'appel de la fonction game_over().

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def move():
        global dep, sx, sy
     
        # la balle se retrouve-t-elle seule ?
     
        if len(can1.find_overlapping(*can1.bbox(cerc1))) < 2:
     
            game_over()
     
        # la balle est au moins sur un rail
        else:
            can1.move(cerc1, sx*dep, sy*dep)
            can1.after(100, move)
    La méthode canvas.find_overlapping(x0, y0, x1, y1) permet de recenser tous les items de canevas ayant au moins une intersection avec le rectangle de coordonnées (x0, y0, x1, y1), coordonnées que j'extrais dans la foulée grâce à canvas.bbox(cerc1) (bbox = bounding box, rectangle des limites extérieures d'un objet, ici cerc1, la balle).

    canvas.bbox(cerc1) retourne ici les coordonnées (x0, y0, x1, y1) du rectangle abstrait qui "entoure" la balle cerc1, cela permet de définir concrètement les limites extérieures de la balle et de s'en servir pour justement détecter si la balle se retrouve seule ou non.

    J'ai utilisé find_overlapping() plutôt que find_enclosed() du fait que les rails sont supposés être toujours plus longs que la balle elle-même et donc qu'ils ne seraient jamais compris à l'intérieur (enclosed) du rectangle de limites bbox() de la balle.

    Néanmoins je pense aussi continuer un peu sur les test que nous avions déja commencé, car comme le dit W, cela permet d'exprimer le contours du polygone en python ce qui relatif au programme de terminale. J'avais d'ailleurs une question à vous poser sur ce thème :
    - dans le fichier est_dans_polygone , notre professeur à utilié "XY" et nous avons donc besoin de le définir mais je ne comprends pas comment on pourrait le faire?

    Merci encore!
    Oui, je suppose qu'il faut gérer tout cela de façon "scolaire".

    J'ai lu vite fait le code mentionné et il me semble comprendre que dans la fonction est_dans_polygone(), XY est le tuple (x, y) des coordonnées du centre de la balle, r le rayon de la balle et Droite1, Droite2 les coordonnées des segments de droites correspondant aux rails de part et d'autre.

    Vous pouvez extraire les coordonnées (x, y) de XY ainsi que le rayon r à partir de canvas.bbox(cerc1) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    x0, y0, x1, y1 = can1.bbox(cerc1)
    # ici bbox() est un carré, on peut donc se permettre:
    r = (x1 - x0) / 2
    x = x0 + r
    y = y0 + r
    XY = (x, y)
    @+

  7. #27
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par FatP0ney Voir le message
    Néanmoins je pense aussi continuer un peu sur les test que nous avions déja commencé, car comme le dit W, cela permet d'exprimer le contours du polygone en python ce qui relatif au programme de terminale. J'avais d'ailleurs une question à vous poser sur ce thème :
    - dans le fichier est_dans_polygone , notre professeur à utilié "XY" et nous avons donc besoin de le définir mais je ne comprends pas comment on pourrait le faire?
    Je dirais "nous non plus" ;-(

    En fait, tout dépend de la représentation du labyrinthe. Si c'est un polygone du genre présenté plus haut, il sera défini par un ensemble de segments (les traits qui permettent de le dessiner) *et* un peu de topologie pour savoir si un point sera intérieur ou extérieur au "polygone". Voir l'article sur Wikipedia.
    Si votre code doit coller à ce genre de représentation, essayer de comprendre les méthodes/fonctions .find_overlapping and C° ne vous aidera pas beaucoup.

    De fait, par rapport à un "problème", il y a toujours plusieurs "design" (les différentes représentations et algorithmes associées) et plusieurs façon de "coder" chaque design.

    L'intérêt d'un exercice "scolaire" est de vous contraindre à utiliser un design particulier (utiliser les connaissances acquises voire, suivre une progression dans les difficultés) qui dépend des objectifs "pédagogiques" recherchés - et seuls vos enseignants savent ce qu'ils veulent voir comme design/code.

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

  8. #28
    Nouveau membre du Club
    Homme Profil pro
    Travail
    Inscrit en
    Avril 2014
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Travail

    Informations forums :
    Inscription : Avril 2014
    Messages : 45
    Points : 34
    Points
    34
    Par défaut
    Bonjour ,
    Merci pour vos explications j'ai pu comprendre ce que vous avez fait!!
    J'avais deux questions qui persistaient néanmoins :

    - que siginifie le "< 2:" dans la fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if len(can1.find_overlapping(*can1.bbox(cerc1))) < 2:
    -lorsque je continue mon travail sur l'ancienne méthode en me servant de ce que vous avez écrit pour les variable , j'obtiens une erreur (invalid syntax) au niveau du rayon , deplus je ne sais pas ce que siginifie le /2 dans cette meme ligne . Pourriez vous m'éclairer su rce point?

    Merci encore!!

    Ps (EDIT) : je viens de remarquer la présence de "can1.tag_raise(cerc1, ALL)" , en cherchant sur internet je crois comprendre que cela permet de changer le plan des actions (pas sur d'être très clair) est-ce bien cela?

  9. #29
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par FatP0ney Voir le message
    Bonjour ,
    Merci pour vos explications j'ai pu comprendre ce que vous avez fait!!
    J'avais deux questions qui persistaient néanmoins :

    - que siginifie le "< 2:" dans la fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if len(can1.find_overlapping(*can1.bbox(cerc1))) < 2:
    la méthode canvas.find_overlapping() retourne une liste Python genre [a, b, c, ...] contenant tous les identifiants des items de canvas qui sont trouvés par cette méthode.

    canvas.find_overlapping() --> [canvasItemId1, canvasItemId2, ..., canvasItemIdN]

    la logique "la balle est seule" sera détectée lorsque find_overlapping() ne retournera plus que l'ID de la balle elle-même (canvasItemId1 = cerc1) dans sa liste, d'où le len(...) < 2 de la condition if.

    Note : len(iterable) compte le nombre d'éléments dans une liste et "< 2" signifie "strictement inférieur à deux", donc si la liste obtenue compte moins de deux éléments, c'est que la balle est seule.

    -lorsque je continue mon travail sur l'ancienne méthode en me servant de ce que vous avez écrit pour les variable , j'obtiens une erreur (invalid syntax) au niveau du rayon , deplus je ne sais pas ce que siginifie le /2 dans cette meme ligne . Pourriez vous m'éclairer su rce point?

    Merci encore!!
    SVP, publiez la portion de votre code qui provoque le syntax error pour qu'on y voie plus clair, merci.

    Note : r = (x1 - x0) / 2 --> le "/ 2" signifie tout bêtement "divisé par deux" (ce sont des maths appliquées à l'informatique, quoi).

    Généralement en informatique, on utilise le symbole "slash" / pour diviser (e.g. a / b --> a divisé par b) et le symbole "star" (ou "étoile") * pour multiplier (e.g. a * b --> a multiplié par b).

    Dans Python, on a aussi la division entière x // y (x double-slash y) qui équivaut à int( x / y ).

    @+.

  10. #30
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par FatP0ney Voir le message
    Ps (EDIT) : je viens de remarquer la présence de "can1.tag_raise(cerc1, ALL)" , en cherchant sur internet je crois comprendre que cela permet de changer le plan des actions (pas sur d'être très clair) est-ce bien cela?
    Un canevas graphique permet d'empiler ses items depuis l'arrière-plan jusqu'au premier plan d'affichage (un peu comme les calques de GIMP ou de Photoshop, pour ceux qui connaissent).

    Ici, can1.tag_raise(cerc1, ALL) demande simplement au canevas de s'assurer que la balle d'identifiant cerc1 soit bien affichée au PREMIER PLAN, au-dessus des rails et de tout le reste (en somme, on demande au canevas : "please, raise cerc1 above ALL other items" in english dans le texte).

    @+.

  11. #31
    Nouveau membre du Club
    Homme Profil pro
    Travail
    Inscrit en
    Avril 2014
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Travail

    Informations forums :
    Inscription : Avril 2014
    Messages : 45
    Points : 34
    Points
    34
    Par défaut
    Okay!! Merci beaucoup pour vos précisions

    Néanmoins je ne comprends pas comment faire marcher ce principe par la suite étant donné que si nous diminuons la taille de la balle, nous aurons un souci puisque cette dernière ne toucherais pas les bords...

    J'ai donc pensé à quelque chose mais je ne sais pas si ca serait top :

    1ère idée :

    -on diminue la taille de la balle
    -on crée une ligne (blanche) située entre les deux premières lignes de manière à ce qu'elle soit toujours au milieux des deux autres et qu'au moment ou la balle est le plus éloignée du trait du milieu, elle entre en contact avec le trait du haut/bas.
    -si la bille reste en contact avec 1 des cotés, on considère que le jeu continue qu'en pensez vous?

    2nd idée :

    -on crée une seconde balle à l'intérieure de la première de diamètre plus petit de manière à ce que le jeux soit visuellement plus agréable et on met la première (celle qui suite les contrainte du parcours au second plan)... Je me demande si ce que je dis est réalisable ou absolument pas...

  12. #32
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par FatP0ney Voir le message
    Okay!! Merci beaucoup pour vos précisions

    Néanmoins je ne comprends pas comment faire marcher ce principe par la suite étant donné que si nous diminuons la taille de la balle, nous aurons un souci puisque cette dernière ne toucherais pas les bords...

    J'ai donc pensé à quelque chose mais je ne sais pas si ca serait top :

    -on diminue la taille de la balle
    -on crée une ligne (blanche) située entre les deux premières lignes de manière à ce qu'elle soit toujours au milieux des deux autres et qu'au moment ou la balle est le plus éloignée du trait du milieu, elle entre en contact avec le trait du haut/bas.
    -si la bille reste en contact avec 1 des cotés, on considère que le jeu continue qu'en pensez vous?
    Euh dans quel contexte ?

    Vous travaillez avec la fonction est_dans_polygone() ou vous travaillez avec find_overlapping() ?

    Avec est_dans_polygone() vous avez tout ce qu'il faut pour y arriver sans rien ajouter, théoriquement.

    Avec find_overlapping() vous pouvez élargir le rayon de détection en incluant une tolérance à bbox().

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    x0, y0, x1, y1 = can1.bbox(cerc1)
    # on ajoute une tolérance
    halo = 10
    # on refait le test avec la tolérance
    if len(can1.find_overlapping(x0 - halo, y0 - halo, x1 + halo, y1 + halo)) < 2:
        game_over()
    else:
    ...etc...
    Il est clair que si vous ne cherchez pas un certain réalisme dans votre programme, c'est la théorie qui l'emporte avec la fonction est_dans_polygone().

    En effet, dans la réalité, je vois mal comment vous allez faire tenir une balle de 20 cm de diamètre sur des rails écartés de 30 cm alors qu'à l'origine, vous aviez prévu d'y faire rouler une balle de 35 cm de diamètre, mais que vous avez préféré entretemps réduire son diamètre ?

    Vous voyez ce que je veux dire ? La théorie peut faire abstraction de la réalité, mais est-ce réellement toujours pertinent ?

    Je n'en jurerais pas...

  13. #33
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Citation Envoyé par tarball69 Voir le message
    En effet, dans la réalité, je vois mal comment vous allez faire tenir une balle de 20 cm de diamètre sur des rails écartés de 30 cm alors qu'à l'origine, vous aviez prévu d'y faire rouler une balle de 35 cm de diamètre, mais que vous avez préféré entretemps réduire son diamètre ?
    Un disque qui se balade dans un labyrinthe, c'est pas un train qui roule sur des rails.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  14. #34
    Nouveau membre du Club
    Homme Profil pro
    Travail
    Inscrit en
    Avril 2014
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Travail

    Informations forums :
    Inscription : Avril 2014
    Messages : 45
    Points : 34
    Points
    34
    Par défaut
    Oui vous avez bien raison je crois avoir été un tout pitit peut rêveur sur ce coup

    Du coup si je comprends bien , il n'est pas possible de réduire le diamètre de la balle? Car avec une tolérance comme vous le proposez , cela permet seulement d'élargir les limites du polygone et donc d'élargir si l'on le voulait la balle non?

    Si j'en reviens à est_dans-polygone , j'ai réussi à résoudre mon erreur précédente mais il m'affiche avec la portion de code que vous m'avez envoyé que can 1 n'est pas défini alors qu'il me semble qu'il l'est quelques lignes plus tard..

    Code :

    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
    # Programme principal
    x0, y0, x1, y1 = can1.bbox(cerc1)
     
    r = (x1 - x0) / 2
    x = x0 + r
    y = y0 + r
    XY = (x, y) 
     
    # Création du widget principal ("maître"):
    fen1 = Tk()
    fen1.title("Super Ball")
     
    # création des widgets "esclaves":
    can1 = Canvas (fen1, bg='white', height=500, width=500)
    cerc1 = can1.create_oval(X, Y, X + r, Y + r,fill = 'grey')
    can1.pack(side=LEFT)
    can1.create_rectangle(50,50,100,100) #dessine un rectangle
    can1.create_rectangle(120,280,170,335)
    polygone1 = [100,65,420,65], [100,85,400,85]
    polygone2 = [400,84,400,300], [420,65,420,320]
    polygone3 = [170,320,420,320], [170,300,400,300]
    Droite1 = [100, 65, 420, 65]
    Droite2 = [200, 75, 410, 75]
    can1.create_line(tuple(polygone1[0]),fill='red',width=4)#ligne 1
    can1.create_line(tuple(polygone1[1]),fill='red',width=4)#ligne 2
    can1.create_line(tuple(polygone2[0]),fill='red',width=4)#ligne 3
    can1.create_line(tuple(polygone2[1]),fill='red',width=4)#ligne 4
    can1.create_line(tuple(polygone3[0]),fill='red',width=4)#ligne 5
    can1.create_line(tuple(polygone3[1]),fill='red',width=4)#ligne 5
    Button(fen1, text='Démarrer', command=start_it).pack(side=BOTTOM)
    Button(fen1, text='Quitter', command=fen1.destroy).pack(side=BOTTOM)
    Button(fen1, text='Gauche',command=dep1_gauche).pack()
    Button(fen1, text='Droite', command=dep1_droite).pack()
    Button(fen1, text='Haut', command=dep1_haut).pack()
    Button(fen1, text='Bas', command=dep1_bas).pack()
    Button(fen1, text='Accélère!', command=start_it).pack(side=BOTTOM)
    can1.bind("<z>", dep1_haut)
    can1.bind("<s>", dep1_bas)
    can1.bind("<d>", dep1_droite)
    can1.bind("<q>", dep1_gauche)
     
     
    # démarrage du réceptionnaire d'évènements (boucle principale):
    fen1.mainloop()

  15. #35
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Un disque qui se balade dans un labyrinthe, c'est pas un train qui roule sur des rails.
    - W
    Okay, dans ce cas, il faudrait m'indiquer dans quel cas la partie se termine : si la balle est dans un labyrinthe, la partie doit-elle se terminer si la balle heurte une paroi ou si la balle traverse la paroi comme un passe-muraille ?

    Si on ne m'indique pas dans quel cas la partie se termine, je peux naviguer à vue indéfiniment.

    Maintenant, si on considère que la partie se termine si la balle heurte une paroi ou une autre, alors il suffit de considérer le test quand la balle n'est pas seule :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if len(can1.find_overlapping(*can1.bbox(cerc1))) > 1:
        game_over()
    else:
        ...etc...
    Pour moi, l'argument de la théorie triomphant de tout reste encore et toujours discutable, je suis désolé.

    En même temps, on chipote, là, étant donné que j'applique la théorie à 99% des cas.

    Il n'y a que pour certains cas que je m'amuse à prospecter des voies nouvelles.

    Mais bon, le débat, ça occupe.

  16. #36
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par FatP0ney Voir le message
    Oui vous avez bien raison je crois avoir été un tout pitit peut rêveur sur ce coup

    Du coup si je comprends bien , il n'est pas possible de réduire le diamètre de la balle? Car avec une tolérance comme vous le proposez , cela permet seulement d'élargir les limites du polygone et donc d'élargir si l'on le voulait la balle non?
    Dites-moi plutôt clairement l'énoncé du problème tel que votre prof vous l'a demandé : est-ce que c'est le jeu de la balle qui roule sur des rails et qui ne doit pas tomber ou est-ce que c'est un jeu où une balle plus petite est enfermée dans un labyrinthe et qui ne doit pas heurter les parois ?

    Dans quel cas la partie se termine-t-elle ? Quand la balle roule puis tombe à l'extérieur des rails ? Quand la balle se déplace à l'intérieur d'un couloir et heurte une paroi ou l'autre ?

    Précisez-moi, que je sache dans quelle direction je dois aller, svp.

    Si j'en reviens à est_dans-polygone , j'ai réussi à résoudre mon erreur précédente mais il m'affiche avec la portion de code que vous m'avez envoyé que can 1 n'est pas défini alors qu'il me semble qu'il l'est quelques lignes plus tard..

    Code :

    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
    # Programme principal
    x0, y0, x1, y1 = can1.bbox(cerc1)
     
    r = (x1 - x0) / 2
    x = x0 + r
    y = y0 + r
    XY = (x, y) 
     
    # Création du widget principal ("maître"):
    fen1 = Tk()
    fen1.title("Super Ball")
     
    # création des widgets "esclaves":
    can1 = Canvas (fen1, bg='white', height=500, width=500)
    cerc1 = can1.create_oval(X, Y, X + r, Y + r,fill = 'grey')
    can1.pack(side=LEFT)
    can1.create_rectangle(50,50,100,100) #dessine un rectangle
    can1.create_rectangle(120,280,170,335)
    polygone1 = [100,65,420,65], [100,85,400,85]
    polygone2 = [400,84,400,300], [420,65,420,320]
    polygone3 = [170,320,420,320], [170,300,400,300]
    Droite1 = [100, 65, 420, 65]
    Droite2 = [200, 75, 410, 75]
    can1.create_line(tuple(polygone1[0]),fill='red',width=4)#ligne 1
    can1.create_line(tuple(polygone1[1]),fill='red',width=4)#ligne 2
    can1.create_line(tuple(polygone2[0]),fill='red',width=4)#ligne 3
    can1.create_line(tuple(polygone2[1]),fill='red',width=4)#ligne 4
    can1.create_line(tuple(polygone3[0]),fill='red',width=4)#ligne 5
    can1.create_line(tuple(polygone3[1]),fill='red',width=4)#ligne 5
    Button(fen1, text='Démarrer', command=start_it).pack(side=BOTTOM)
    Button(fen1, text='Quitter', command=fen1.destroy).pack(side=BOTTOM)
    Button(fen1, text='Gauche',command=dep1_gauche).pack()
    Button(fen1, text='Droite', command=dep1_droite).pack()
    Button(fen1, text='Haut', command=dep1_haut).pack()
    Button(fen1, text='Bas', command=dep1_bas).pack()
    Button(fen1, text='Accélère!', command=start_it).pack(side=BOTTOM)
    can1.bind("<z>", dep1_haut)
    can1.bind("<s>", dep1_bas)
    can1.bind("<d>", dep1_droite)
    can1.bind("<q>", dep1_gauche)
     
     
    # démarrage du réceptionnaire d'évènements (boucle principale):
    fen1.mainloop()
    Pourriez-vous publier la totalité du fichier, SVP ?

    je crois que le problème se situe plus haut dans le code (et je soupçonne aussi un problème d'indentation).

    parce que tel que présenté là, votre code semble absurde.

    Merci.

  17. #37
    Nouveau membre du Club
    Homme Profil pro
    Travail
    Inscrit en
    Avril 2014
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Travail

    Informations forums :
    Inscription : Avril 2014
    Messages : 45
    Points : 34
    Points
    34
    Par défaut
    Alors nous cherchons en fait à faire une sorte que la petite bille soit à l'intérieur des rails (et non dessus) et que la partie s'achève dès que cette dernière rentre en contact avec un des cotés :

    Code :

    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
     
     
     
    #!/usr/bin/python
    # -*- coding: utf8 -*-
     
    from Tkinter import *
    from random import randrange
    from partie1_coord_droite_finie import est_dans_polygone
    # procédure générale de déplacement :
    def move():
        global dep, sx, sy, r, command, polygone1, polygone2, Polygone3, X, Y
        if est_dans_polygone([X,Y],r, polygone1[0], polygone1[1]) or X-r<=100:
            X = X + sx*dep
            Y =  Y + sy*dep
            can1.move(cerc1, sx*dep, sy*dep)
            can1.after(100, move)
    # gestionnaires d'évènements:
    def dep1_gauche(event):
        global sx, sy
        sx = -1
        sy = 0
     
    def dep1_droite(event):
        global sx, sy
        sx = 1
        sy = 0
     
    def dep1_haut(event):
        global sy, sx
        sy = -1 
        sx = 0 
     
    def dep1_bas(event):
        global sy, sx  
        sy = 1 
        sx = 0
     
    def start_it():
        "démarrage de l'animation"
        global flag
        flag = not flag
        move()
     
    def pause() :
        #nous servira quand on touchera le mur
         "arret de l'animation"
         global flag    
         flag =0
     
    # Programme principal
    x0, y0, x1, y1 =can1.bbox(cerc1)
     
    r = (x1 - x0) / 2
    x = x0 + r
    y = y0 + r
    XY = (x, y) 
     
    # Création du widget principal ("maître"):
    fen1 = Tk()
    fen1.title("Super Ball")
     
    # création des widgets "esclaves":
    can1 = Canvas (fen1, bg='white', height=500, width=500)
    cerc1 = can1.create_oval(X, Y, X + r, Y + r,fill = 'grey')
    can1.pack(side=LEFT)
    can1.create_rectangle(50,50,100,100) #dessine un rectangle
    can1.create_rectangle(120,280,170,335)
    polygone1 = [100,65,420,65], [100,85,400,85]
    polygone2 = [400,84,400,300], [420,65,420,320]
    polygone3 = [170,320,420,320], [170,300,400,300]
    Droite1 = [100, 65, 420, 65]
    Droite2 = [200, 75, 410, 75]
    can1.create_line(tuple(polygone1[0]),fill='red',width=4)#ligne 1
    can1.create_line(tuple(polygone1[1]),fill='red',width=4)#ligne 2
    can1.create_line(tuple(polygone2[0]),fill='red',width=4)#ligne 3
    can1.create_line(tuple(polygone2[1]),fill='red',width=4)#ligne 4
    can1.create_line(tuple(polygone3[0]),fill='red',width=4)#ligne 5
    can1.create_line(tuple(polygone3[1]),fill='red',width=4)#ligne 5
    Button(fen1, text='Démarrer', command=start_it).pack(side=BOTTOM)
    Button(fen1, text='Quitter', command=fen1.destroy).pack(side=BOTTOM)
    Button(fen1, text='Gauche',command=dep1_gauche).pack()
    Button(fen1, text='Droite', command=dep1_droite).pack()
    Button(fen1, text='Haut', command=dep1_haut).pack()
    Button(fen1, text='Bas', command=dep1_bas).pack()
    Button(fen1, text='Accélère!', command=start_it).pack(side=BOTTOM)
    can1.bind("<z>", dep1_haut)
    can1.bind("<s>", dep1_bas)
    can1.bind("<d>", dep1_droite)
    can1.bind("<q>", dep1_gauche)
     
     
    # démarrage du réceptionnaire d'évènements (boucle principale):
    fen1.mainloop()

    Code de la partie gérant la présence dans les polygones :

    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
     
    # Fonctions
     
    ###########
     
    r = 10          # Dimension du cercle
     
     
    def est_au_dessus(XY,Droite):
     
        x, y = tuple(XY)
     
        xA, yA, xB, yB = tuple(Droite)
        # Le point ne peut être au dessus d'une droite verticale
        if xB == xA:
            return False
        a= (yB-yA)/(xB-xA)
     
        b= yA-a*xA
     
        valeur_a_retourner = y<a*x+b
     
        return valeur_a_retourner
     
     
     
    def est_en_dessous(XY,Droite):
     
        x, y = tuple(XY)
     
        xC, yC, xD, yD = tuple(Droite)
        if xC == xD:
            return False
             # Le point ne peut être au dessous d'une droite verticale
        a= (yD-yC)/(xD-xC)
     
        b= yC-a*xC
     
        valeur_a_retourner = y>a*x+b
     
        return valeur_a_retourner
     
     
     
     
     
    def est_a_gauche(XY,Droite):
     
        x, y = tuple(XY)
     
        xA, yA, xC, yC = tuple(Droite)
        if yA == yC:
            return False
            # Le point ne peut être à gauche d'une droite horizontale
     
        a= (xC-xA)/(yC-yA)
     
        b= xA-a*yA
     
        valeur_a_retourner=x<a*y+b
     
        return valeur_a_retourner
     
     
     
    def est_a_droite(XY,Droite):
     
        x, y = tuple(XY)
     
        xB, yB, xD, yD = tuple(Droite)
        if yB == yD:
            return False
           #Le point ne peut être à droite d'une droite horizontale
        a= (xD-xB)/(yD-yB)
     
        b= xB-a*yB
     
        valeur_a_retourner=x>a*y+b
     
        return valeur_a_retourner    
     
     
     
    def est_dans_polygone(XY,r, Droite1, Droite2):
     
        Droite3 = [Droite1[0], Droite1[1], Droite2[0], Droite2[1]]
     
        Droite4 = [Droite1[2], Droite1[3], Droite2[2], Droite2[3]]
     
        est_dans_poly1 = est_en_dessous([XY[0], XY[1] - r], Droite2) and \
                         est_au_dessus([XY[0],XY[1] + r], Droite1) and \
                         est_a_droite([XY[0] - r,XY[1]], Droite3) and \
                         est_a_gauche([XY[0] + r,XY[1]], Droite4)
     
     
        est_dans_poly2 = est_en_dessous([XY[0], XY[1] - r], Droite1) and \
                         est_au_dessus([XY[0],XY[1] + r], Droite2) and \
                         est_a_droite([XY[0] - r,XY[1]], Droite4) and \
                         est_a_gauche([XY[0] + r,XY[1]], Droite3)
     
     
        est_dans_poly3 = est_en_dessous([XY[0], XY[1] - r], Droite3) and \
                         est_au_dessus([XY[0],XY[1] + r], Droite4) and \
                         est_a_droite([XY[0] - r,XY[1]], Droite2) and \
                         est_a_gauche([XY[0] + r,XY[1]], Droite1)
     
     
        est_dans_poly4 = est_en_dessous([XY[0], XY[1] - r], Droite3) and \
                         est_au_dessus([XY[0],XY[1] + r], Droite4) and \
                         est_a_droite([XY[0] - r,XY[1]], Droite1) and \
                         est_a_gauche([XY[0] + r,XY[1]], Droite2)  
     
     
        est_dans_poly5 = est_en_dessous([XY[0], XY[1] - r], Droite4) and \
                         est_au_dessus([XY[0],XY[1] + r], Droite3) and \
                         est_a_droite([XY[0] - r,XY[1]], Droite2) and \
                         est_a_gauche([XY[0] + r,XY[1]], Droite1)
     
     
        est_dans_poly6 = est_en_dessous([XY[0], XY[1] - r], Droite4) and \
                         est_au_dessus([XY[0],XY[1] + r], Droite3) and \
                         est_a_droite([XY[0] - r,XY[1]], Droite1) and \
                         est_a_gauche([XY[0] + r,XY[1]], Droite2)
     
     
     
        return est_dans_poly1 or est_dans_poly2 or est_dans_poly3 or est_dans_poly4 or est_dans_poly5 or est_dans_poly6
     
     
     
     
    # Code:
     
    #######
     
    print(est_dans_polygone([3,0], 0.2, [2,5,3,3], [1,-1,5,-1]))

  18. #38
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par FatP0ney Voir le message
    Alors nous cherchons en fait à faire une sorte que la petite bille soit à l'intérieur des rails (et non dessus) et que la partie s'achève dès que cette dernière rentre en contact avec un des cotés :
    Okay, c'est nettement plus clair à présent.

    Donc la logique "la balle est-elle seule ?" devient "la balle heurte-t-elle une paroi ?", ce qui revient à dire dans le contexte de ce jeu "quand la balle n'est plus seule, la partie est terminée".

    Voici un exemple de code avec find_overlapping() réajusté aux nouvelles contraintes :

    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
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    from Tkinter import *
    from random import randrange
    #~ from partie1_coord_droite_finie import est_dans_polygone
     
    # procédure générale de déplacement :
     
    def move():
        global dep, sx, sy
        # la balle touche-t-elle une paroi (logique aveugle) ?
        if len(can1.find_overlapping(*can1.bbox(cerc1))) > 1:
            game_over()
        # la balle est seule
        else:
            can1.move(cerc1, sx*dep, sy*dep)
            can1.after(100, move)
     
     
    def game_over():
        # la partie est finie !
        left = can1.winfo_reqwidth() // 2
        top = can1.winfo_reqheight() // 2
        can1.create_text(
            left, top - 40,
            text="GAME OVER!",
            font="sans 24 bold",
            fill="gold",
        )
     
     
    # gestionnaires d'évènements:
    def dep1_gauche(event=None):
        global sx, sy
        sx = -1
        sy = 0
     
    def dep1_droite(event=None):
        global sx, sy
        sx = 1
        sy = 0
     
    def dep1_haut(event=None):
        global sy, sx
        sy = -1
        sx = 0
     
    def dep1_bas(event=None):
        global sy, sx
        sy = 1
        sx = 0
     
    def start_it():
        "démarrage de l'animation"
        global flag
        flag = not flag
        move()
     
    def pause() :
        #nous servira quand on touchera le mur
         "arret de l'animation"
         global flag
         flag =0
     
     
    # Programme principal
     
    # les variables suivantes seront utilisées de manière globale:
    dep = 5             # valeur de deplacement
    X, Y = 110, 70      # coordonnées initiales
    sx, sy = 1, 0
    r = 10
    flag = 0   # commutateur
     
    # Création du widget principal ("maître"):
    fen1 = Tk()
    fen1.title("Super Ball")
     
    # création des widgets "esclaves":
    can1 = Canvas (fen1, bg='white', height=500, width=500)
    cerc1 = can1.create_oval(X, Y, X + r, Y + r,fill = 'grey')
    can1.pack(side=LEFT)
    can1.create_rectangle(50,50,100,100) #dessine un rectangle
    can1.create_rectangle(120,280,170,335)
    polygone1 = [100,65,420,65], [100,85,400,85]
    can1.create_line(tuple(polygone1[0]),fill='red',width=4)#ligne 1
    can1.create_line(tuple(polygone1[1]),fill='red',width=4)#ligne 2
    can1.create_line(400,84,400,300,fill='red',width=4)#ligne 3
    can1.create_line(420,65,420,320,fill='red',width=4)#ligne 4
    can1.create_line(170,320,420,320,fill='red',width=4)#ligne 5
    can1.create_line(170,300,400,300,fill='red',width=4)#ligne 5
     
    # passer la balle au premier plan (affichage)
     
    can1.tag_raise(cerc1, ALL)
     
    Button(fen1, text='Démarrer', command=start_it).pack(side=BOTTOM)
    Button(fen1, text='Quitter', command=fen1.destroy).pack(side=BOTTOM)
    Button(fen1, text='Gauche',command=dep1_gauche).pack()
    Button(fen1, text='Droite', command=dep1_droite).pack()
    Button(fen1, text='Haut', command=dep1_haut).pack()
    Button(fen1, text='Bas', command=dep1_bas).pack()
    Button(fen1, text='Accélère!', command=start_it).pack(side=BOTTOM)
    can1.bind("<z>", dep1_haut)
    can1.bind("<s>", dep1_bas)
    can1.bind("<d>", dep1_droite)
    can1.bind("<q>", dep1_gauche)
     
    # démarrage du réceptionnaire d'évènements (boucle principale):
    fen1.mainloop()
    Par rapport au code précédent, je me suis contenté de remplacer if len(...) < 2 par if len(...) > 1, de réduire le rayon de la balle de r = 20 à r = 10 puis de placer la balle dans le labyrinthe pour tester le déroulement du programme.

    Bien que cette logique soit "aveugle" (la balle heurte quelque chose, on ne sait pas quoi), elle fonctionne néanmoins dans ce cadre-là.

    Pour le code avec est_dans_polygone(), vous n'avez pas compris où il fallait placer le code que je vous avais fourni, il est donc normal que ça plante.

    Voici quelque chose de plus cohérent, déjà :

    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
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    from Tkinter import *
    from random import randrange
    from partie1_coord_droite_finie import est_dans_polygone
     
    # procédure générale de déplacement :
     
    def move():
        # global n'est utile que si on MODIFIE une globale
        #~ global dep, sx, sy
        # on extrait XY, r avant d'effectuer le test
        x0, y0, x1, y1 = can1.bbox(cerc1)
        # calcul du rayon
        r = (x1 - x0) / 2
        # détermination de XY
        x = x0 + r
        y = y0 + r
        XY = (x, y)
        # debug: on vérifie dans la console
        print "XY:", XY, "rayon r:", r, "polygone1:", polygone1
        # on teste si la balle est dans le polygone
        if est_dans_polygone(XY, r, polygone1[0], polygone1[1]):
            # tout est OK on se déplace
            can1.move(cerc1, sx*dep, sy*dep)
            can1.after(100, move)
        # la balle est sortie
        else:
            # debug: on affiche dans la console
            print "la balle est sortie !"
            # la partie est terminée
            game_over()
     
     
    def game_over():
        # la partie est finie !
        left = can1.winfo_reqwidth() // 2
        top = can1.winfo_reqheight() // 2
        can1.create_text(
            left, top - 40,
            text="GAME OVER!",
            font="sans 24 bold",
            fill="gold",
        )
     
     
    # gestionnaires d'évènements:
     
    def dep1_gauche(event=None):
        global sx, sy
        sx = -1
        sy = 0
     
    def dep1_droite(event=None):
        global sx, sy
        sx = 1
        sy = 0
     
    def dep1_haut(event=None):
        global sy, sx
        sy = -1
        sx = 0
     
    def dep1_bas(event=None):
        global sy, sx
        sy = 1
        sx = 0
     
    def start_it():
        "démarrage de l'animation"
        global flag
        flag = not flag
        move()
     
    def pause() :
        "arret de l'animation"
        # nous servira quand on touchera le mur
        global flag
        flag = 0
     
     
    # Programme principal
     
    # les variables suivantes seront utilisées de manière globale:
     
    X, Y = 110, 70      # coordonnées initiales
    d = 10              # diamètre de la balle
    sx, sy = 1, 0       # sens de déplacement
    dep = 5             # quantité de déplacement (pixels)
    flag = 0            # commutateur
     
    # Création du widget principal ("maître"):
     
    # fenêtre principale
    fen1 = Tk()
    fen1.title("Super Ball")
     
    # création des widgets "esclaves":
     
    # composants
    can1 = Canvas(fen1, bg='white', height=500, width=500)
    cerc1 = can1.create_oval(X, Y, X + d, Y + d, fill='grey')
    can1.pack(side=LEFT)
     
    # tracés
    can1.create_rectangle(50,50,100,100)    # dessine un rectangle
    can1.create_rectangle(120,280,170,335)
    polygone1 = [100,65,420,65], [100,85,400,85]
    polygone2 = [400,84,400,300], [420,65,420,320]
    polygone3 = [170,320,420,320], [170,300,400,300]
    Droite1 = [100, 65, 420, 65]
    Droite2 = [200, 75, 410, 75]
    can1.create_line(tuple(polygone1[0]), fill='red', width=4)    # ligne 1
    can1.create_line(tuple(polygone1[1]), fill='red', width=4)    # ligne 2
    can1.create_line(tuple(polygone2[0]), fill='red', width=4)    # ligne 3
    can1.create_line(tuple(polygone2[1]), fill='red', width=4)    # ligne 4
    can1.create_line(tuple(polygone3[0]), fill='red', width=4)    # ligne 5
    can1.create_line(tuple(polygone3[1]), fill='red', width=4)    # ligne 5
     
    # composants (suite)
    Button(fen1, text='Gauche', command=dep1_gauche).pack()
    Button(fen1, text='Droite', command=dep1_droite).pack()
    Button(fen1, text='Haut', command=dep1_haut).pack()
    Button(fen1, text='Bas', command=dep1_bas).pack()
    Button(fen1, text='Quitter', command=fen1.quit).pack(side=BOTTOM)
    Button(fen1, text='Démarrer', command=start_it).pack(side=BOTTOM)
    #~ Button(fen1, text='Accélère!', command=start_it).pack(side=BOTTOM)
     
    # événements
    can1.bind("<z>", dep1_haut)
    can1.bind("<s>", dep1_bas)
    can1.bind("<d>", dep1_droite)
    can1.bind("<q>", dep1_gauche)
     
    # démarrage du réceptionnaire d'évènements (boucle principale):
    fen1.mainloop()
    Ne reste plus qu'à vérifier que la fonction est_dans_polygone() est parfaitement exacte d'un point de vue logique.

  19. #39
    Nouveau membre du Club
    Homme Profil pro
    Travail
    Inscrit en
    Avril 2014
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Travail

    Informations forums :
    Inscription : Avril 2014
    Messages : 45
    Points : 34
    Points
    34
    Par défaut
    Bonjour ,
    Merci pour vos conseils!
    J'avais néanmoins encore quelques questions :

    - à quoi correspond?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    left = can1.winfo_reqwidth() // 2
        top = can1.winfo_reqheight() // 2
    - vous m'aviez parlé de "*" en tant que multiplication dans vos post précédents mais je ne comprends pas à quoi elle correspondrait dans la parenthèse de la fonction (juste avant la bbox).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if len(can1.find_overlapping(*can1.bbox(cerc1))) < 2:
    -enfin je voulais faire en sorte que la bille commence dans la boite de départ et que l'on gagne lorsque cette dernière rentre dans la boite d'arrivée faut il faire cela avec les coordonnées des boites ou il a t'il un autre moyen plus généraliste?

    Merci!

  20. #40
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par FatP0ney Voir le message
    Bonjour ,
    Merci pour vos conseils!
    J'avais néanmoins encore quelques questions :

    - à quoi correspond?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        left = can1.winfo_reqwidth() // 2
        top = can1.winfo_reqheight() // 2
    Normalement, je devrais vous renvoyer sur la doc Tkinter, mais vous ne m'avez pas l'air très porté sur l'Anglais et en tant que défenseur de la langue française, je ne saurais vous en blâmer.

    Les méthodes universelles widget.winfo_reqwidth() et widget.winfo_reqheight() permettent de récupérer la largeur et la hauteur requises par le widget avant même qu'il ne soit dessiné à l'écran.

    C'est généralement les bonnes dimensions que le widget se réserve à l'avance, contrairement à widget.winfo_width() et widget.winfo_height() ou même à widget.cget("width") et widget.cget("height") qui ne vous retourneront de valeurs adéquates qu'une fois que le widget sera dessiné à l'écran ou actualisé avec un widget.update_idletasks().

    Un peu de lecture quand même (méthodes universelles des widgets Tkinter, s'appliquent à tous les widgets) :

    http://infohost.nmt.edu/tcc/help/pub...universal.html

    Note : le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        left = can1.winfo_reqwidth() // 2
        top = can1.winfo_reqheight() // 2
    correspond au calcul des coordonnées du point central du canevas can1 - il utilise en outre la division entière de Python (double-slash) parce qu'il n'y a pas besoin d'être super précis dans ce contexte.

    Mathématiquement, cela correspond à :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        x = largeur / 2
        y = hauteur / 2
    donc bien les coordonnées C(x, y) du point central C d'un rectangle quelconque, si l'on considère que le coin supérieur gauche de ce rectangle est le point d'origine O(0, 0) de notre repère géométrique orthonormé.


    - vous m'aviez parlé de "*" en tant que multiplication dans vos post précédents mais je ne comprends pas à quoi elle correspondrait dans la parenthèse de la fonction (juste avant la bbox).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if len(can1.find_overlapping(*can1.bbox(cerc1))) < 2:
    C'est une particularité du langage Python : ici le symbole étoile * signifie "expansion d'un tuple ou d'une liste en tant qu'arguments de fonction/méthode".

    Pour bien le comprendre, testez ce bout de code :

    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
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    def test(*arguments):
        """
            la fonction test() accepte 0, 1 ou n arguments quelconques
            passés en paramètre au moment de l'appel de cette fonction;
            les arguments peuvent être de n'importe quel type (y compris
            évidemment des tuples);
        """
        # on affiche dans la console
        print "Nombre d'arguments passés en paramètre :", len(arguments)
        # on boucle sur les arguments
        i = 1
        for argument in arguments:
            # on affiche dans la console
            print "Argument numéro {} : {}".format(i, argument)
            # màj compteur
            i += 1
        # end for
    # end def
     
    # tests simples
     
    print "\nTest 1 :"
     
    test()
     
    print "\nTest 2 :"
     
    test("bonjour")
     
    print "\nTest 3 :"
     
    test("il me reste", 3, "pommes")
     
    print "\nTest 4 :"
     
    test("coordonnées du point P :", (10, 20), " et autres données")
     
    print "\nTest 5 :"
     
    test(1, 2, 3, (4, 5, 6))
     
    # maintenant, je récupère un tuple :
     
    rectangle = (0, 0, 20, 30)
     
    # si je le passe tel quel...
     
    print "\nTest 6 :"
     
    test(rectangle)
     
    # ...je n'ai qu'un seul argument : un tuple.
     
    # mais si ma fonction attend 4 arguments en paramètre,
    # je dois faire une expansion de mon tuple pour qu'il devienne
    # 4 paramètres à part entière :
     
    print "\nTest 7 :"
     
    test(*rectangle)
     
    # vu la nuance ?
    ATTENTION : cette notation n'est valable que dans le cadre d'arguments de fonction et nulle part ailleurs.

    Ceci ne marchera pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    rectangle = (0, 0, 10, 20)
    autre = *rectangle    # syntax error

    -enfin je voulais faire en sorte que la bille commence dans la boite de départ et que l'on gagne lorsque cette dernière rentre dans la boite d'arrivée faut il faire cela avec les coordonnées des boites ou il a t'il un autre moyen plus généraliste?

    Merci!
    Les deux, mon capitaine.

    Généralement, dans les jeux de ce type, on fait une petite animation automatique lorsque le joueur clique sur "Démarrer le jeu", animation qui montre la balle roulant de son carré de départ vers le couloir du labyrinthe.

    Une fois dans le couloir du labyrinthe, l'animation prend fin et c'est la fonction move() qui prend le relais.

    En revanche, pour tester si la balle est bien arrivée dans le carré final, il vous faut ajouter un test dans move(), du style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if a_reussi(XY, r, carre_final[0], carre_final[1]):
        bravo()
    elif est_dans_polygone(XY, r, polygone1[0], polygone1[1]):
        can1.move(cerc1, sx*dep, sy*dep)
        can1.after(100, move)
    else:
        game_over()
    on peut aussi détecter l'ID du carré final avec un canvas.find_closest(), un canvas.find_overlapping() ou un canvas.find_enclosed(), mais ça, ça n'est pas scolaire et donc je suppose que ça n'est pas non plus à l'ordre du jour.

    Pensez à cliquer sur 'Résolu' si vos problèmes ont trouvé réponse. Merci.

    @+.

Discussions similaires

  1. Problème avec l'animation d'une balle
    Par Arkey24 dans le forum GUI
    Réponses: 1
    Dernier message: 15/04/2014, 15h21
  2. Réponses: 4
    Dernier message: 11/05/2007, 19h45
  3. Réponses: 6
    Dernier message: 21/03/2005, 13h22
  4. Réponses: 6
    Dernier message: 14/12/2004, 02h47
  5. [Composants][Animation] Lire une vidéo compressée
    Par femtosa dans le forum Composants VCL
    Réponses: 6
    Dernier message: 03/09/2002, 08h03

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