Обработка потоков Python: «Ошибка выполнения: поток.__init__() не вызван»

#python #python-3.x #pycharm #python-multithreading #turtle-graphics

#python #python-3.x #pycharm #python-многопоточность #черепаха-графика

Вопрос:

Я делаю игру в пинг-понг с черепахой. Однако назначение заключается в том, что код должен иметь многопоточность. Я не смог правильно применить многопоточность.

Код не показывает ошибки в редакторе, но он не работает. Как мы можем исправить эту ошибку во время выполнения? Так сложно найти ошибку, когда в редакторе нет ошибки.

 import turtle
from threading import *
from time import sleep

wn = turtle.Screen()
wn.title("Ping pong by Cagatay em")
wn.bgcolor("blue")
wn.setup(width=900, height=600)
wn.tracer(0)  #oyunu hizlandirir silersen cok yavaslar 

class PaddleFirst(Thread):
    def __init__(self):
        self.pen = turtle.Turtle()
        self.pen.penup()
        self.pen.speed(0)
        self.pen.shape("square")
        self.pen.shapesize(stretch_wid=5, stretch_len=1)
        self.pen.penup()
        self.pen.goto(-350, 0)

    def run(self):
        y = self.pen.ycor()
        y  = 20
        self.pen.sety(y)
        k = self.pen.ycor()
        k -= 20
        self.pen.sety(k)


class PaddleSecond(Thread):
    def __init__(self):
        self.pen = turtle.Turtle()
        self.pen.penup()
        self.pen.speed(0)
        self.pen.shape("square")
        self.pen.shapesize(stretch_wid=5, stretch_len=1)
        self.pen.penup()
        self.pen.goto(350, 0)

    def run(self):
        y = self.pen.ycor()
        y  = 20
        self.pen.sety(y)
        k = self.pen.ycor()
        k -= 20
        self.pen.sety(k)



class Ball(Thread):
    def __init__(self):

        self.pen = turtle.Turtle()
        self.pen.penup()
        self.pen.speed(0)
        self.pen.shape("circle")
        self.pen.color("red")
        self.pen.penup()
        self.pen.goto(0, 0)
        self.pen.dx = 00.1
        self.pen.dy = 00.1

    def run(self):
        self.pen.setx(self.pen.xcor()   self.pen.dx)
        self.pen.sety(self.pen.ycor()   self.pen.dy)
        if self.pen.ycor() > 290:
            self.pen.sety(290)
            self.pen.dy *= -1

        if self.pen.ycor() < -290:
            self.pen.sety(-290)
            self.pen.dy *= -1

        if self.pen.xcor() > 390:
            self.pen.goto(0, 0)
            self.pen.dx *= -1

        if self.pen.xcor() < -390:
            self.pen.goto(0, 0)
            self.pen.dx *= -1


class Wall(Thread):
   def run(self):
        if ball.pen.xcor() > 340 and (ball.pen.ycor() < paddle2.pen.ycor()   40 and ball.pen.ycor() > paddle2.pen.ycor() - 40):
           ball.pen.dx *= -1
        if ball.pen.xcor() < -340 and (ball.pen.ycor() < paddle1.pen.ycor()   40 and ball.pen.ycor() > paddle1.pen.ycor() - 40):
            ball.pen.dx *= -1


paddle1 = PaddleFirst()

paddle2 = PaddleSecond()

ball = Ball()

wall = Wall()


wn.listen()
wn.onkeypress(paddle1.run, "w")
wn.onkeypress(paddle1.run(), "s")
wn.onkeypress(paddle2.run(), "Up")
wn.onkeypress(paddle2.run, "Down")



while True:
    wn.update() # everytime uptades the screen
    ball.start()
    sleep(0.2)
    wall.start()
    sleep(0.2)
    paddle1.start()
    sleep(0.2)
    paddle2.start()
  

Ответ №1:

Я предполагаю, что сообщение об ошибке, которое вы получили, связано с тем, что вы не вызываете __init__() метод суперкласса в вашем подклассе Thread .

Так сложно найти ошибку, когда в редакторе нет ошибки.

Вам нужно научиться искусству отладки.

я не смог правильно применить многопоточность.

Я думаю, что здесь есть две проблемы. Во-первых, чтобы использовать потоковую обработку с turtle, которая встроена поверх tkinter, вам необходимо, чтобы все графические команды были перенаправлены через основной поток — вторичные потоки не должны пытаться напрямую изменять экран.

Во-вторых, ваш код в беспорядке. Помимо потоковой обработки, неясно, что вы понимаете в объектном программировании, поскольку у вас есть два идентичных класса, за исключением координаты X. Это должен быть один класс с аргументом для его инициализатора. Неясно, что вы понимаете turtle, поскольку wn.onkeypress(paddle1.run(), "s") никогда не будет работать. Вероятно, вам не следует возиться с tracer() и update() , пока ваш код не заработает. И у вас не должно быть while True: в основном потоке turtle.

Я разобрал ваш код на части и собрал его обратно ниже. Только ball является отдельным потоком, от которого теперь наследуется (одиночный) класс paddle Turtle . Основной поток обрабатывает графические команды из потока ball, а также стандартные события turtle:

 from turtle import Screen, Turtle
from threading import Thread, active_count
from queue import Queue

QUEUE_SIZE = 1

class Paddle(Turtle):
    def __init__(self, xcor):
        super().__init__(shape='square')

        self.shapesize(stretch_wid=5, stretch_len=1)
        self.speed('fastest')
        self.penup()
        self.setx(xcor)
        self.dy = 10

    def down(self):
        y = self.ycor() - self.dy

        if y > -250:
            self.sety(y)

    def up(self):
        y = self.ycor()   self.dy

        if y < 250:
            self.sety(y)

class Ball(Thread):
    def __init__(self):
        super().__init__(daemon=True)

        self.pen = Turtle('circle')
        self.pen.speed('fastest')
        self.pen.color('red')
        self.pen.penup()
        self.dx = 1
        self.dy = 1

    def run(self):
        x, y = self.pen.position()

        while True:
            x  = self.dx
            y  = self.dy

            if x > 330 and (paddle2.ycor() - 60 < y < paddle2.ycor()   60):
                self.dx *= -1
            elif x < -330 and (paddle1.ycor() - 60 < y < paddle1.ycor()   60):
                self.dx *= -1

            if y > 290:
                y = 290
                self.dy *= -1
            elif y < -290:
                y = -290
                self.dy *= -1
            elif not -440 < x < 440:
                x, y = 0, 0
                self.dx *= -1

            actions.put((self.pen.setposition, x, y))

def process_queue():
    while not actions.empty():
        action, *arguments = actions.get()
        action(*arguments)

    if active_count() > 1:
        screen.ontimer(process_queue, 100)

screen = Screen()
screen.title("Ping pong rework by cdlane")
screen.bgcolor('blue')
screen.setup(width=900, height=600)

actions = Queue(QUEUE_SIZE)

paddle1 = Paddle(-350)
paddle2 = Paddle(350)
ball = Ball()

screen.onkeypress(paddle1.up, 'w')
screen.onkeypress(paddle1.down, 's')
screen.onkeypress(paddle2.up, 'Up')
screen.onkeypress(paddle2.down, 'Down')
screen.listen()

ball.start()

process_queue()

screen.mainloop()
  

Код все еще неполон и слегка глючит (например, не завершается чисто) — над чем вам нужно поработать. Но в основном он играет в игру разумным образом.

Комментарии:

1. Как я могу сделать эту игру таким образом, чтобы 2 игрока могли играть одновременно? я хочу иметь возможность одновременно удерживать кнопки «w» и «вверх».

2. @RodionRaskolnikov, хотя для этого может потребоваться создание потоков paddles, я предполагаю, что этого будет недостаточно. Доступ высокого уровня, который вы получаете к клавиатуре по умолчанию, вряд ли будет быстро обрабатывать несколько клавиш одновременно. Для этого вам, вероятно, понадобится интерфейс более низкого уровня с клавиатурой, такой как pynput или что-то подобное. В качестве альтернативы, подумайте о том, чтобы выставить одного игрока против компьютера.