Работают ли привязки клавиш "w" и "s" в Tkinter по-разному? - PullRequest
0 голосов
/ 20 июня 2019

Я работал над переводом версии игры «Понг», которую я создал для онлайн-класса Python с использованием CodeSkulptor, в «настольный» сценарий python с использованием Tkinter, чтобы научить себя, как использовать Tkinter , Мне удалось в значительной степени заставить работать всю игру, кроме левого (игрока 1) весла. Я думаю, что у меня правильная привязка клавиш, так как правое (игрок 2) весло работает, как и ожидалось, в том случае, когда вы удерживаете клавиши со стрелками «Вверх» или «Вниз», весло перемещается, пока не достигнет верхней или нижней границы холст или останавливается, когда любой ключ отпущен. Я передаю нажатия клавиш в обработчики нажатия клавиш и клавиш, где я проверяю, какая клавиша была нажата / отпущена, и действую соответственно. Что меня беспокоит, так это то, что, если я отображаю движение левого весла на разные клавиши (например, «a» или «d», или стрелки «вверх» или «вниз»), он работает как положено, но отказывается работать, когда у меня есть клавиши "w" и "s". Кто-нибудь знает, почему это может быть, или что я, возможно, сделал неправильно?

Код, который я привел ниже, является базовым примером, который я собрал, который демонстрирует эту проблему и движение весла, которого я пытаюсь достичь (это в значительной степени отражает мой проект Pong). Правая лопасть движется правильно, а левая - нет. Заранее спасибо за помощь!

from Tkinter import *
import random


WIDTH = 500
HEIGHT = 500
PAD_WIDTH = 10
PAD_HEIGHT = 80
HALF_PAD_WIDTH = PAD_WIDTH / 2
HALF_PAD_HEIGHT = PAD_HEIGHT / 2


class Example(Frame, object):
    def __init__(self, master):
        super(Example, self).__init__(master)

        self._paddle1_pos = 200
        self._paddle2_pos = 200
        self._paddle1_vel = 0
        self._paddle2_vel = 0

        self.initUI()

    def initUI(self):
        scn_cent_height = self.master.winfo_screenheight() // 2 - HEIGHT // 2
        scn_cent_width = self.master.winfo_screenwidth() // 2 - WIDTH // 2
        self.master.geometry("%sx%s+%s+%s" % (WIDTH, HEIGHT, scn_cent_width, scn_cent_height))
        self.master.minsize(WIDTH, HEIGHT)

        self.master.title("Example Pong Paddles")

        self._canvasFrame = Frame(self.master)
        self._canvasFrame.pack(expand=True, fill=BOTH)

        self._canvas = Canvas(self._canvasFrame, bg="black", highlightthickness=0, bd=0)
        self._canvas.pack(fill=BOTH, expand=True)
        self.update_idletasks()

        # Key handlers
        self.master.bind("<KeyPress>", self.keydown)
        self.master.bind("<KeyRelease>", self.keyup)

        while True:
            self._canvas.after(1)
            self._canvas.delete("all")
            self.draw()
            self._canvas.update()


    def draw(self):
        self._cheight = self._canvasFrame.winfo_height()
        self._cwidth = self._canvasFrame.winfo_width()

        # Draw mid line and gutters
        self._rline = self._canvas.create_line(self._cwidth / 2, 0, self._cwidth / 2, self._cheight, width=1, fill="White")
        self._mline = self._canvas.create_line(PAD_WIDTH, 0, PAD_WIDTH, self._cheight, width=1, fill="White")
        self._lline = self._canvas.create_line(self._cwidth - PAD_WIDTH, 0, self._cwidth - PAD_WIDTH, self._cheight, width=1, fill="White")

        # Update paddle's vertical position, keep paddle on the screen
        # Paddle 1 - Check height and update position
        if self._paddle1_pos + self._paddle1_vel >= HALF_PAD_HEIGHT and self._paddle1_pos + self._paddle1_vel <= HEIGHT - HALF_PAD_HEIGHT:
            self._paddle1_pos += self._paddle1_vel

        # Paddle 2 - Check height and update position
        if self._paddle2_pos + self._paddle2_vel >= HALF_PAD_HEIGHT and self._paddle2_pos + self._paddle2_vel <= HEIGHT - HALF_PAD_HEIGHT:
            self._paddle2_pos += self._paddle2_vel

        # Draw paddles
        self._p1paddle = self._canvas.create_line([HALF_PAD_WIDTH, self._paddle1_pos - HALF_PAD_HEIGHT],
                                                  [HALF_PAD_WIDTH, self._paddle1_pos + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")
        self._p2paddle = self._canvas.create_line([self._cwidth - HALF_PAD_WIDTH, self._paddle2_pos - HALF_PAD_HEIGHT],
                                                  [self._cwidth - HALF_PAD_WIDTH, self._paddle2_pos + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")


        # Draw paddles
        self._p1paddle = self._canvas.create_line([HALF_PAD_WIDTH, self._paddle1_pos - HALF_PAD_HEIGHT],
                                                  [HALF_PAD_WIDTH, self._paddle1_pos + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")
        self._p2paddle = self._canvas.create_line([self._cwidth - HALF_PAD_WIDTH, self._paddle2_pos - HALF_PAD_HEIGHT],
                                                  [self._cwidth - HALF_PAD_WIDTH, self._paddle2_pos + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")


    def keydown(self, key):
        key = key.keysym

        if key == "w":
            self._paddle1_vel = -10
        elif key == "s":
            self._paddle1_vel = 10
        elif key == "Up":
            self._paddle2_vel = -10
        elif key == "Down":
            self._paddle2_vel = 10


    def keyup(self, key):
        key = key.keysym

        if key == "w":
            self._paddle1_vel = 0
        elif key == "s":
            self._paddle1_vel = 0
        elif key == "Up":
            self._paddle2_vel = 0
        elif key == "Down":
            self._paddle2_vel = 0




def main():
    root = Tk()
    example = Example(root)
    root.mainloop()


if __name__ == '__main__':
    main()

Ответы [ 2 ]

0 голосов
/ 22 июня 2019

Я просто хотел добавить, в интересах всех, кто сталкивается с этой проблемой, что я смог отследить ее источник в своих виртуальных средах Anaconda (у меня есть по одному для Python 2 и Python 3). В ходе тестирования я смог воспроизвести эту проблему, когда конкретно использовал эти среды, но не смог воспроизвести ее при использовании Python 2 (сборка фреймворка Mac) или Python 3 (установлен через Brew) за пределами Anaconda. Я уничтожил обе виртуальные среды Anaconda на случай, если что-то там испортилось, и перестроил их обе (т.е. чистую установку обоих Python 2 и 3) и все еще смог воспроизвести эту проблему (без установки каких-либо дополнительных модулей). Я могу только предположить, что между питоном (-ами), которые установлены / установлены Anaconda, и теми, которые являются частью системной платформы или установлены отдельно, есть что-то другое.

Кроме того, чтобы отметить, что, когда я успешно провел тестирование на Python 3 в приведенном выше комментарии @ Novel, я случайно проверил систему Python 3, а не виртуальную среду Anaconda Python 3.

EDIT: Оказывается, эта проблема на самом деле связана с версией Tkinter (Tcl / Tk), которую использовали мои установки на python. Платформа python на моем ноутбуке использовала Tk 8.5.9, в то время как установки Anaconda используют 8.6.8. При тестировании я столкнулся с этой проблемой при запуске моего скрипта Pong на python 2.7.16 и 3.7.3 с Tk 8.6.8, но он отлично работал на тех же версиях python с Tk 8.5.9. Я не уверен, что это проблема с Tk, или какая-то несовместимость между Tk 8.6.8 и платформой MacOS (поскольку платформа изначально использует 8.5.9).

0 голосов
/ 20 июня 2019

Ваш код очень грязный и нуждается в рефакторинге, так что я сделал это. Некоторые заметки:

  • Самым большим примечанием является то, что вместо очистки экрана и перерисовки всего, он гораздо аккуратнее и работает намного лучше, если вы рисуете объекты один раз, а затем просто перемещаете их.
  • Использовать основной цикл tkinter; не создавайте свои собственные и обновляйте их вручную. Методы update() или update_idletasks() являются последним средством; нормальный код не имеет их. Вместо этого используйте основную петлю tkinter через after(). Это сделает ваше окно намного более реактивным.
  • Python2 Tkinter классы старого стиля, не заставляйте их быть новым, добавляя наследование объектов.
  • рамка холста бесполезна, поэтому я удалил ее.
  • хранение ключей в словаре освобождает много повторяющегося кода.
  • Префикс всех имен переменных с _ ничего не делает и затрудняет чтение и ввод текста; оставь это.

-

try:
    import tkinter as tk # python3 detected
except ImportError:
    import Tkinter as tk # python2 detected

WIDTH = 500
HEIGHT = 500
PAD_WIDTH = 10
PAD_HEIGHT = 80
VELOCITY = 10
HALF_PAD_WIDTH = PAD_WIDTH // 2
HALF_PAD_HEIGHT = PAD_HEIGHT // 2

P1_UP = 111 # Up arrow key
P1_DOWN = 116 # Down arrrow key
P2_UP = 25 # 'w' key
P2_DOWN = 39 # 's' key

class Example(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)

        self.keys = {}
        self.initUI()

        # Key handlers
        self.master.bind("<KeyPress>", self.keydown)
        self.master.bind("<KeyRelease>", self.keyup)

        self.draw() # add the game loop to the mainloop

    def initUI(self):
        scn_cent_height = self.master.winfo_screenheight() // 2 - HEIGHT // 2
        scn_cent_width = self.master.winfo_screenwidth() // 2 - WIDTH // 2
        self.master.geometry("%sx%s+%s+%s" % (WIDTH, HEIGHT, scn_cent_width, scn_cent_height))
        self.master.minsize(WIDTH, HEIGHT)

        self.master.title("Example Pong Paddles")

        self.canvas = tk.Canvas(self, bg="black", highlightthickness=0, bd=0, width=WIDTH, height=HEIGHT)
        self.canvas.pack(fill=tk.BOTH, expand=True)

        # Draw mid line and gutters
        self.rline = self.canvas.create_line(WIDTH//2, 0, WIDTH//2, HEIGHT, width=1, fill="White")
        self.mline = self.canvas.create_line(PAD_WIDTH, 0, PAD_WIDTH, HEIGHT, width=1, fill="White")
        self.lline = self.canvas.create_line(WIDTH - PAD_WIDTH, 0, WIDTH - PAD_WIDTH, HEIGHT, width=1, fill="White")

        # Draw paddles
        self.p1paddle = self.canvas.create_line([HALF_PAD_WIDTH, HEIGHT//2 - HALF_PAD_HEIGHT],
                                                  [HALF_PAD_WIDTH, HEIGHT//2 + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")
        self.p2paddle = self.canvas.create_line([WIDTH - HALF_PAD_WIDTH, HEIGHT//2 - HALF_PAD_HEIGHT],
                                                    [WIDTH - HALF_PAD_WIDTH, HEIGHT//2 + HALF_PAD_HEIGHT], width=PAD_WIDTH, fill="White")

    def draw(self):
        if self.keys.get(P2_UP) and self.canvas.coords(self.p1paddle)[1] > 0:
            self.canvas.move(self.p1paddle, 0, -VELOCITY)
        if self.keys.get(P2_DOWN) and self.canvas.coords(self.p1paddle)[3] < HEIGHT:
            self.canvas.move(self.p1paddle, 0, VELOCITY)
        if self.keys.get(P1_UP) and self.canvas.coords(self.p2paddle)[1] > 0:
            self.canvas.move(self.p2paddle, 0, -VELOCITY)
        if self.keys.get(P1_DOWN) and self.canvas.coords(self.p2paddle)[3] < HEIGHT:
            self.canvas.move(self.p2paddle, 0, VELOCITY)

        self.after(10, self.draw)

    def keydown(self, key):
        self.keys[key.keycode] = True

    def keyup(self, key):
        self.keys[key.keycode] = False

def main():
    root = tk.Tk()
    example = Example(root)
    example.pack()
    root.mainloop()

if __name__ == '__main__':
    main()

Возможно, какое-то улучшение там тоже исправит вашу исходную проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...