Pong : mouvement des 2 raquettes

Résolu/Fermé
Phil_1857 Messages postés 1883 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 - 16 déc. 2022 à 13:43
yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024 - 18 déc. 2022 à 10:31

Bonjour,

Je me suis amusé à programmer le fameux jeu de Pong (nostalgie, quand tu nous tiens :-) )

Il fonctionne bien, les 2 raquettes montent et descendent avec l'appui sur 4 touches du clavier

Un seul problème: en jouant seul, je déplace les raquettes l'une après l'autre, suivant la direction de la balle,

en jouant à 2, il arrive que l'un des joueurs bloque le mouvement de l'autre en appuyant sur ses

touches en même temps que l'autre

C'est normal, j'ai lié ma fenêtre à l'évènement appui sur une touche:

main_win.bind('<Key>', get_key_cb)

et la fonction récupère donc la touche et déplace en fonction l'une ou l'autre raquette avec une

suite de tests:

if(key_p != None):
    if(key_p == 'i'): r_bat.y -= r_bat.vy
    if(key_p == 'n'): r_bat.y += r_bat.vy
    if(key_p == 'a'): l_bat.y -= l_bat.vy
    if(key_p == 'w'): l_bat.y += l_bat.vy

Comment éviter ce problème ?

L'utilisation de threads pour séparer les 2 évènements (les 2 raquettes) serait-elle la solution ?

Merci d'avance


Windows / Edge 108.0.1462.46

A voir également:

5 réponses

Whismeril Messages postés 19020 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 15 avril 2024 928
16 déc. 2022 à 14:12

Salut Phil,

comme tu les sais mon niveau de python ne vole pas très haut, mais sur le principe oui, un thread par joueur serait une solution, le seul "point dur" est de pouvoir récupérer les appuis touches depuis ces threads sans se servir de l'événement de la fenêtre.

En c#, je serais te montrer mais pas en python


0
yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024 1 471
16 déc. 2022 à 14:58

bonjour,

Quel module de Python utilises-tu?  tkinter?

Je ne pense pas que travailler avec des threads (ni avec du multiprocessing) t'aiderait.

As-tu essayé avec notepad ou un autre programme similaire?  Je pense que tu verras que c'est l'OS qui ne "consomme" pas les touches indépendamment les unes des autres.

Peut-être faudrait-il décourager le joueur de presser trop fréquemment sur ses touches, en le pénalisant quand il n'y a pas un délai suffisant entre deux entrées de touches du même joueur.

0
yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024 1 471
16 déc. 2022 à 15:26

tkinter est multithread par lui-même, et les touches pressées sont consommées dans l'ordre où elles sont pressées.

C'est visible avec le code:

import tkinter
import time
win=tkinter.Tk()
def gk(k):
    print(k.char,end="")
    win.update()
    time.sleep(1)
    print("_",end="")
win.bind('<Key>', gk)

win.mainloop()
0
yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024 1 471 > yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024
16 déc. 2022 à 15:30

Le code partagé en #3 donne un résultat tel que:

d_d_ddd___d_dd__k_kk__k_kkkk__mdsmckdsmlkcmdlsk_cmdkml____________qmlkdckdmlc_______________________

Ce qui montre bien que plusieurs instances de la fonction gk() sont exécutées simultanément.

0
Phil_1857 Messages postés 1883 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 178
16 déc. 2022 à 16:23

Merci pour vos réponses, je me doutais un peu que le multithreading ne m'aiderait pas,

je suis bien sur tkinter

J'ai testé ton code, effectivement, c'est parlant

Je vais essayer le test de temps entre 2 appuis de touches ...

0
yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024 1 471
16 déc. 2022 à 16:27

En testant mon code, tu constates également qu'un joueur "empêche" l'autre de jouer?  Moi je ne constate pas cela.

Est-il possible que ton code prenne "trop" de temps pour traiter une commande?

0
Phil_1857 Messages postés 1883 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 178
16 déc. 2022 à 16:57

Peut-être oui ...

En tout cas, j'ai réglé le problème en gérant les appuis de touches des 2 joueurs

0
yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024 1 471
16 déc. 2022 à 18:48

Que veux-tu dire par "gérer les appuis"?

0
Phil_1857 Messages postés 1883 Date d'inscription lundi 23 mars 2020 Statut Membre Dernière intervention 28 février 2024 178 > yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024
17 déc. 2022 à 10:23

Bah, avec la méthode que tu m'as indiquée..

0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question

Bonsoir, on fait cela en enregistrant les touches pressées dans un itérables avec tkinter.

Exemple basique affichant les touches appuyées.

import tkinter as tk

keys_pressed = set()

def on_keypress(evt):
    keys_pressed.add(evt.keysym)

def on_keyrelease(evt):
    try:
        keys_pressed.remove(evt.keysym)
    except KeyError:
        pass

def keys_pressed_show(widget):
    if keys_pressed:
        print(''.join(keys_pressed))
    widget.after(50, keys_pressed_show, widget)


window = tk.Tk()
window.bind('<KeyPress>', on_keypress)
window.bind('<KeyRelease>', on_keyrelease)
keys_pressed_show(window)
window.mainloop()
0
yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024 1 471
17 déc. 2022 à 14:43

Est-ce bien utile de détecter qu'une touche est relâchée?  On risque de louper les touches relâchées très rapidement.

import tkinter as tk

keys_pressed = set()

def on_keypress(evt):
    keys_pressed.add(evt.keysym)


def keys_pressed_show(widget):
    global keys_pressed
    if keys_pressed:
        kp=keys_pressed
        keys_pressed = set()
        print(''.join(kp))
    widget.after(100, keys_pressed_show, widget)


window = tk.Tk()
window.bind('<KeyPress>', on_keypress)
keys_pressed_show(window)
window.mainloop()
0
hufy > yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024
17 déc. 2022 à 21:00

Bonsoir, oui cela est nécessaire, car en procédant comme tu le montres, on ne peut agir à la fois sur plusieurs touches simultanément.  En reprenant le pong et 2 raquettes, cela ne fonctionnera pas :

import tkinter as tk

keys_pressed = set()


def on_keypress(evt):
    keys_pressed.add(evt.keysym)


def keys_manager(board):
    for key in keys_pressed:
        if key == "Up" and board.coords(paddle_right)[1] > 0:
            board.move(paddle_right, 0, -20)
        elif key == "Down" and board.coords(paddle_right)[3] < 400:
            board.move(paddle_right, 0, 20)
        if key == "z" and board.coords(paddle_left)[1] > 0:
            board.move(paddle_left, 0, -20)
        elif key == "q" and board.coords(paddle_left)[3] < 400:
            board.move(paddle_left, 0, 20)
    keys_pressed.clear()
    board.after(20, keys_manager, board)


game = tk.Tk()
game_board = tk.Canvas(game, width=600, height=400, bg="#fff")
game_board.grid()
game_board.bind("<KeyPress>", on_keypress)
paddle_left = game_board.create_rectangle(10, 160, 16, 240, fill="#00f")
paddle_right = game_board.create_rectangle(584, 160, 590, 240, fill="#00f")
keys_manager(game_board)
game_board.focus_set()
game.mainloop()

Tandis qu'en gérant les touches relâchées, on arrive à gérer le mouvement des paddles distinctement sans qu'il y ait interférence tout en étant relativement fluide.

import tkinter as tk

keys_pressed = set()


def on_keypress(evt):
    keys_pressed.add(evt.keysym)


def on_keyrelease(evt):
    try:
        keys_pressed.remove(evt.keysym)
    except KeyError:
        pass


def keys_manager(board):
    for key in keys_pressed:
        if key == "Up" and board.coords(paddle_right)[1] > 0:
            board.move(paddle_right, 0, -20)
        elif key == "Down" and board.coords(paddle_right)[3] < 400:
            board.move(paddle_right, 0, 20)
        if key == "z" and board.coords(paddle_left)[1] > 0:
            board.move(paddle_left, 0, -20)
        elif key == "q" and board.coords(paddle_left)[3] < 400:
            board.move(paddle_left, 0, 20)
    board.after(20, keys_manager, board)


game = tk.Tk()
game_board = tk.Canvas(game, width=600, height=400, bg="#fff")
game_board.grid()
game_board.bind("<KeyPress>", on_keypress)
game_board.bind("<KeyRelease>", on_keyrelease)
paddle_left = game_board.create_rectangle(10, 160, 16, 240, fill="#00f")
paddle_right = game_board.create_rectangle(584, 160, 590, 240, fill="#00f")
keys_manager(game_board)
game_board.focus_set()
game.mainloop()
0
yg_be Messages postés 22692 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 avril 2024 1 471 > hufy
18 déc. 2022 à 10:31

Ah oui, je comprends, tu souhaites permettre aux joueurs de garder une touche enfoncée.  Bonne idée, à condition que le délai soit assez court (20 msec est parfait).

J'ai parfois une petite perturbation quand la touche "shift lock" est pressée pendant qu'une autre touche est enfoncée, il est sans doute préférable de faire "evt.keysym.lower()".

0