#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 или что-то подобное. В качестве альтернативы, подумайте о том, чтобы выставить одного игрока против компьютера.