Получите плавное движение, используя многопоточную графику черепах Python - PullRequest
0 голосов
/ 31 октября 2018

Это мой первый вопрос!

Я закончил создание простой игры с космическими захватчиками в графике черепах Python и заметил досадную проблему: чем больше объектов у меня на экране, тем медленнее работает программа.

Мой друг сказал мне, что мне нужно использовать многопоточность, чтобы все команды выполнялись одновременно, и, таким образом, игра будет работать гладко.

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

С этим кодом враги время от времени застревают на своем месте на пару миллисекунд. Это очень заметно, что мне делать?

one_enemy = turtle.Turtle()
one_enemy.shape("Invader.gif")
one_enemy.penup()
one_enemy.speed(0)
x = random.randint(-200, 200)
y = random.randint(100, 200)
one_enemy.setposition(x, y)

two_enemy = turtle.Turtle()
two_enemy.shape("Invader.gif")
two_enemy.penup()
two_enemy.speed(0)
x = random.randint(-200, 200)
y = random.randint(100, 200)
two_enemy.setposition(x, y)

def move_enemy_horizontally(enemy, direction):
    while True:
        while direction == "right":
            x = enemy.xcor()
            x += enemyspeed
            enemy.setx(x)
            if enemy.xcor() > 288:
                y = enemy.ycor()
                y -= 50
                enemy.sety(y)
                direction = "left"
        while direction == "left":
            x = enemy.xcor()
            x -= enemyspeed
            enemy.setx(x)
            if enemy.xcor() < -288:
                y = enemy.ycor()
                y -= 50
                enemy.sety(y)
                direction = "right"

t = threading.Thread(target=move_enemy_horizontally, args=(one_enemy, direction))
t.start()
t2 = threading.Thread(target=move_enemy_horizontally, args=(two_enemy, direction))
t2.start()

1 Ответ

0 голосов
/ 01 ноября 2018

Я удивлен, что ваш код работает вообще - когда я заканчиваю и запускаю его, движется только одна черепаха. Возможно, это разница между Windows и Unix или чем-то подобным. Несмотря на это, я считаю, что вы не можете создавать графику tkinter / turtle ни в одной теме, кроме основной. Итак, я разработал этот подход, который позволяет вторичным потокам вычислять вещи об их черепахе, но в конечном итоге передать графическую команду первичному потоку:

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

QUEUE_SIZE = 1
ENEMY_SPEED = 3

def move_enemy_horizontally(enemy, direction):
    x, y = enemy.position()

    while True:
        while direction == "right":

            if x > 288:
                y -= 50
                actions.put((enemy.sety, y))
                direction = "left"
            else:
                x += ENEMY_SPEED
                actions.put((enemy.setx, x))

        while direction == "left":
            if x < -288:
                y -= 50
                actions.put((enemy.sety, y))
                direction = "right"
            else:
                x -= ENEMY_SPEED
                actions.put((enemy.setx, x))

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

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

actions = Queue(QUEUE_SIZE)

x, y = randint(-200, 200), randint(100, 200)

direction = "right"

for dy in range(2):
    for dx in range(2):
        enemy = Turtle("turtle", visible=False)
        enemy.speed('fastest')
        enemy.setheading(270)
        enemy.penup()
        enemy.setposition(x + dx * 60, y + dy * 100)
        enemy.showturtle()

        Thread(target=move_enemy_horizontally, args=(enemy, direction), daemon=True).start()

    direction = ["left", "right"][direction == "left"]

screen = Screen()

process_queue()

screen.mainloop()

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

...