Установка фонового изображения в рамках установленной анимационной рамки Tkinter - PullRequest
0 голосов
/ 23 апреля 2019

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

К вашему сведению: я работаю в Python 2.7.

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

def run(width=300, height=300):
    def redrawAllWrapper(canvas, data):
        canvas.delete(ALL)
        canvas.create_rectangle(0, 0, data.width, data.height,
                                fill='white', width=0)
        redrawAll(canvas, data)
        canvas.update()    

    def mousePressedWrapper(event, canvas, data):
        mousePressed(event, data)
        redrawAllWrapper(canvas, data)

    def keyPressedWrapper(event, canvas, data):
        keyPressed(event, data)
        redrawAllWrapper(canvas, data)

    def timerFiredWrapper(canvas, data):
        timerFired(data)
        redrawAllWrapper(canvas, data)
        # pause, then call timerFired again
        canvas.after(data.timerDelay, timerFiredWrapper, canvas, data)
    # Set up data and call init
    class Struct(object): pass
    data = Struct()
    data.width = width
    data.height = height
    data.timerDelay = 10 # milliseconds
    root = Tk()
    root.resizable(width=False, height=False) # prevents resizing window

    init(data)
    # create the root and the canvas
    canvas = Canvas(root, width=data.width, height=data.height)
    canvas.configure(bd=0, highlightthickness=0)
    canvas.pack()
    # set up events
    root.bind("<Button-1>", lambda event:
                            mousePressedWrapper(event, canvas, data))
    root.bind("<Key>", lambda event:
                            keyPressedWrapper(event, canvas, data))
    timerFiredWrapper(canvas, data)
    # and launch the app
    root.mainloop()  # blocks until window is closed
    print("bye!")

run(1200, 700)

с моей текущей структурой, я пишу весь необходимый код в функциях init, timerFired, redrawAll, keyPressed и mousePressed над этой функцией запуска.

С моей текущей реализацией фона. Я использую PhotoImage для файла размером 1200 x 700 gif и рисую изображение на весь экран в функции redrawAll (которая вызывается каждые 10 миллисекунд). Без рисования этого одного изображения моя игра работает очень гладко, однако при рисовании изображения в redrawAll игра значительно отстает, поэтому я знаю, что источником задержки является фоновое изображение.

Вот строка кода, которая рисует ее в redrawAll:

canvas.create_image (data.width // 2, data.height // 2, image = data.background)

Это только потому, что я делаю это в redrawAll, который непрерывно рисует изображение каждый раз, когда вызывается функция, замедляя ее? Неужели просто иметь такое большое изображение в Tkinter? Каков источник?

Это способ просто нарисовать изображение один раз на фоне, и оно никогда не изменится? Или есть ли способ не иметь лаг? Я просто нахожу это странным. Опять же, это в Python 2.7 на Mac.

Спасибо!

1 Ответ

1 голос
/ 23 апреля 2019

Вам не нужно удалять и снова добавлять все элементы для обновления экрана. Вы можете перемещать элементы, и холст нарисует их правильно

Этот код создает 1000 маленьких прямоугольников и случайным образом перемещает их на фоне.

Протестировано с Python 3.7, но на 2.7 тоже должно работать.

С 5_000 прямоугольниками он замедляется, но все равно работает хорошо (но не идеально). С 10_000 он слишком сильно замедляется.

from Tkinter import *
from PIL import Image, ImageTk
import random

IMAGE_PATH = 'background.jpg'

class Struct(object):
    pass

def run(width=300, height=300):

    def init(data):
        # create 1000 rectangles in random position
        for _ in range(1000):
            x = random.randint(0, data.width)
            y = random.randint(0, data.height)
            data.data.append(canvas.create_rectangle(x, y, x+10, y+10, fill='red'))

    def mousePressedWrapper(event, canvas, data):
        #mousePressed(event, data)
        pass 

    def keyPressedWrapper(event, canvas, data):
        #keyPressed(event, data)
        pass

    def timerFiredWrapper(canvas, data):
        # move objects
        for rect_id in data.data:
            x = random.randint(-10, 10)
            y = random.randint(-10, 10)
            canvas.move(rect_id, x, y)

        # pause, then call timerFired again
        canvas.after(data.timerDelay, timerFiredWrapper, canvas, data)

    # Set up data and call init
    data = Struct()
    data.width = width
    data.height = height
    data.timerDelay = 10 # milliseconds
    data.data = [] # place for small red rectangles

    root = Tk()
    root.resizable(width=False, height=False) # prevents resizing window

    # create the root and the canvas
    canvas = Canvas(root, width=data.width, height=data.height)
    canvas.configure(bd=0, highlightthickness=0)
    canvas.pack()

    #canvas.create_rectangle(0, 0, data.width, data.height, fill='white', width=0)
    img = Image.open(IMAGE_PATH)
    img = img.resize((data.width, data.height))
    photo = ImageTk.PhotoImage(img)
    canvas.create_image(0, 0, image=photo, anchor='nw')

    init(data) # init after creating canvas because it create rectangles on canvas

    # set up events
    root.bind("<Button-1>", lambda event:
                            mousePressedWrapper(event, canvas, data))
    root.bind("<Key>", lambda event:
                            keyPressedWrapper(event, canvas, data))
    timerFiredWrapper(canvas, data)

    # and launch the app
    root.mainloop()  # blocks until window is closed
    print("bye!")

run(1200, 700)
...