Как заставить анимацию на Tkinter появляться каждый раз, когда вы нажимаете пробел? - PullRequest
0 голосов
/ 10 февраля 2020

Я пытаюсь создать "Баскетбольную игру", используя python и tkinter, и мне не удается заставить мою анимацию работать. Когда я нажимаю пробел, появляется баскетбольный мяч, но не вверх go. Я попытался поместить self.status.shoot == Status.shoot в нескольких областях, но анимация не запускается, когда я нажимаю пробел, вместо этого изображение баскетбола просто появляется без движения. Есть мысли?

Вот мой код:

model.py

import enum,math,random,time


# sizes of each images (pixels)
from Projects.MVC import controller

backboard1_height = 150
backboard1_width = 150
backboard2_height = 150
backboard2_width = 150
backboard3_height = 150
backboard3_width = 150
bg_height = 750
bg_width = 1000
floor_height = 180
floor_width = 1000
player_height = 250
player_width = 250
ball_height = 50
ball_width = 50

class Status(enum.Enum):
    run = 1
    pause = 2
    game_over = 3
    terminate = 4
    shoot = 5


class HorizontalDirection(enum.IntEnum):
    left = -1
    none = 0
    right = 1


class VerticalDirection(enum.IntEnum):
    up = -1
    none = 0
    down = 1


class ImgDirection(enum.Enum):
    left = -1
    right = 1


class GameModel:
    def __init__(self):
        self.status = Status.pause

        self.elements = []
        self.next_time = time.time()  # when we try drop a ball




        # create elements
        self.bg = Background(bg_width / 2, bg_height / 2)
        self.floor = Floor(bg_width / 2, bg_height - (floor_height / 2))
        self.backboard1 = Backboard1(bg_width / 2, player_height / 2)
        self.backboard2 = Backboard2(bg_width / 10, player_height / 2)
        self.backboard3 = Backboard3((bg_width / 2) + 400, player_height / 2)
        self.player = Player(bg_width / 2, bg_height - floor_height )
        self.text = TextInfo(80, 30)
        self.init_elements()


    def init_elements(self):                # layer images on top of each other in order for every thing to be seen
        self.elements = []
        self.elements.append(self.bg)
        self.elements.append(self.floor)
        self.elements.append(self.backboard1)
        self.elements.append(self.backboard2)
        self.elements.append(self.backboard3)
        self.elements.append(self.player)
        self.elements.append(self.text)

    def add_ball(self):
        ball = Ball(self.player.x, self.player.y-125)
        print("first self.player.y: {}".format(self.player.y))
        #if self.status == Status.shoot:
        self.elements.append(ball)

    def random_ball_drop(self):  
       # if self.status == Status.shoot:
        if self.next_time - time.time() < -2:
          #  if self.status == Status.shoot:
            self.next_time = time.time() + 2
            self.add_ball()
            print("First time: {}".format(time.time()))
            print("first Add.ball: {}".format(self.add_ball()))
        #if self.status == Status.shoot:
        elif self.next_time - time.time() < 0:
            if random.uniform(0, 1) < 0.01:
                self.next_time = time.time() + 2
                self.add_ball()
                print("Second time: {}".format(time.time()))


    def check_status(self, element):
        if type(element) is Ball:
            dist = math.sqrt((element.x - self.backboard1.x) ** 2 + (element.y - self.backboard1.y) ** 2)
            if dist < self.backboard1.catch_radius:
                self.text.score += 1
                return False
            elif element.y >= bg_height:
                self.text.lives -= 1
                print("Text.lives: {}".format(self.text.lives))
                return False
        return True

    def remove_ball(self):
        self.elements = [e for e in self.elements if self.check_status(e)]
        #print("self.element: {}".format(self.elements))

    def update(self):
       # if self.status == Status.shoot:
        for element in self.elements:
            element.update()
                #print("first element.update: {}".format(element.update()))
         #   if  self.status == Status.shoot:
        self.random_ball_drop()
        self.remove_ball()
        print("Random_ball_drop from update block: {}".format(self.random_ball_drop()))
        print("remove_ball: {}".format(self.remove_ball()))

    def change_to_initial_state(self):
        self.init_elements()
        for e in self.elements:
            e.change_to_initial_position()






class GameElement:
    def __init__(self, x, y, direction_x, direction_y, speed):
        self.initial_x = x
        self.initial_y = y
        self.x = x
        self.y = y
        self.direction_x = direction_x
        self.direction_y = direction_y
        self.speed = speed

    def change_to_initial_position(self):
        self.x = self.initial_x
        self.y = self.initial_y

    def update(self):
        pass


class Background(GameElement):
    def __init__(self, x, y):
        super().__init__(x, y, HorizontalDirection.none, VerticalDirection.none, 0)


class Floor(GameElement):
    def __init__(self, x, y):
        super().__init__(x, y, HorizontalDirection.none, VerticalDirection.none, 0)


class Backboard1(GameElement):
    def __init__(self, x, y):
        super().__init__(x, y, HorizontalDirection.none, VerticalDirection.none, 0)
        self.catch_radius = (backboard1_height / 2) + (ball_height / 2) + 10

class Backboard2(GameElement):
    def __init__(self, x, y):
        super().__init__(x, y, HorizontalDirection.none, VerticalDirection.none, 0)
        self.catch_radius = (backboard2_height / 2) + (ball_height / 2) + 10

class Backboard3(GameElement):
    def __init__(self, x, y):
        super().__init__(x, y, HorizontalDirection.none, VerticalDirection.none, 0)
        self.catch_radius = (backboard3_height / 2) + (ball_height / 2) + 10

class Player(GameElement):
    def __init__(self, x, y):
        super().__init__(x, y, HorizontalDirection.none, VerticalDirection.none, speed=6)
        self.img_direction = ImgDirection.left

    def update(self):
        if self.direction_x == HorizontalDirection.left:
            if self.x > 0:
                self.move()
        elif self.direction_x == HorizontalDirection.right:
            if self.x < bg_width:
                self.move()

    def move(self):
        self.x += self.direction_x * self.speed
        self.direction_x = HorizontalDirection.none


class Ball(GameElement):
    def __init__(self, x, y):
        super().__init__(x, y, HorizontalDirection.none, VerticalDirection.up, speed=10)

    def update(self):
        self.y += self.direction_y*self.speed
        print("This is self.y: {}".format(self.y))


class TextInfo(GameElement):
    def __init__(self, x, y):
        super().__init__(x, y, HorizontalDirection.none, VerticalDirection.none, speed=0)
        self.score = 0
        self.lives = 3

    def change_to_initial_position(self):
        self.score = 0
        self.lives = 3
        super().change_to_initial_position()

controller.py

from model import *


class GameController:
    def __init__(self, model):
        self.model = model
        pass

    def start_new_game(self):
        self.model.change_to_initial_state()
        self.model.status = Status.run

    def continue_game(self):
        self.model.status = Status.run
        print(Status.run)

    def exit_game(self):
        self.model.status = Status.terminate


    def press_p(self, event):
        if self.model.status == Status.run:
            self.model.status = Status.pause
            print(Status.pause)


    def press_left(self, event):
        self.model.player.direction_x = HorizontalDirection.left
        self.model.player.img_direction = ImgDirection.left
        print(HorizontalDirection.left)



    def press_right(self, event):
        self.model.player.direction_x = HorizontalDirection.right
        self.model.player.img_direction = ImgDirection.right
        print(HorizontalDirection.right)

    def press_space(self, event):
        if self.model.status == Status.run:
            self.model.status = Status.shoot
            self.model.update()
            print(Status.shoot)


    def update_model(self):
        if self.model.status == Status.run:
            self.model.update()

view.py

import tkinter as tk
from PIL import ImageTk, Image

from model import *


class GameImages:
    def __init__(self):
        # background
        self.bg_pil_img = Image.open('./resources/bg.png')
        self.bg_img = ImageTk.PhotoImage(self.bg_pil_img)

        # floor
        self.floor_pil_img = Image.open('./resources/floor.png')
        self.floor_img = ImageTk.PhotoImage(self.floor_pil_img)

        # backboard1
        self.backboard1_pil_img = Image.open('./resources/backboard1.png')
        self.backboard1_pil_img = self.backboard1_pil_img.resize((backboard1_height, backboard1_width))
        self.backboard1_img = ImageTk.PhotoImage(self.backboard1_pil_img)

        # backboard2
        self.backboard2_pil_img = Image.open('./resources/backboard2.png')
        self.backboard2_pil_img = self.backboard2_pil_img.resize((backboard2_height, backboard2_width))
        self.backboard2_img = ImageTk.PhotoImage(self.backboard2_pil_img)

        # backboard3
        self.backboard3_pil_img = Image.open('./resources/backboard3.png')
        self.backboard3_pil_img = self.backboard1_pil_img.resize((backboard3_height, backboard3_width))
        self.backboard3_img = ImageTk.PhotoImage(self.backboard3_pil_img)

        # player
        self.player_pil_img = Image.open('./resources/player.png')
        self.player_pil_img_right = self.player_pil_img.resize((player_height, player_width))
        self.player_pil_img_left = self.player_pil_img_right.transpose(Image.FLIP_LEFT_RIGHT)
        self.player_img_right = ImageTk.PhotoImage(self.player_pil_img_right)
        self.player_img_left = ImageTk.PhotoImage(self.player_pil_img_left)

        # ball
        self.ball_pil_img = Image.open('./resources/ball.png')
        self.ball_pil_img = self.ball_pil_img.resize((ball_height, ball_width))
        self.ball_img = ImageTk.PhotoImage(self.ball_pil_img)

    def get_image(self, element):
        if type(element) is Background:
            return self.bg_img

        if type(element) is Floor:
            return self.floor_img

        if type(element) is Backboard1:
            return self.backboard1_img

        if type(element) is Backboard2:
            return self.backboard2_img

        if type(element) is Backboard3:
            return self.backboard3_img

        if type(element) is Player:
            if element.img_direction == ImgDirection.left:
                return self.player_img_left
            else:
                return self.player_img_right

        if type(element) is Ball:
            return self.ball_img

        return None


class DisplayGame:
    def __init__(self, canvas, _id):
        self.canvas = canvas
        self.id = _id

    def delete_from_screen(self):
        self.canvas.delete(self.id)


class DisplayGameImage(DisplayGame):
    def __init__(self, canvas, element, img):
        super().__init__(canvas, canvas.create_image(element.x, element.y, image=img))


class DisplayGameText(DisplayGame):
    def __init__(self, canvas, element):
        text = "Score: %d\nLives: %d" % (element.score, element.lives)
        super().__init__(canvas, canvas.create_text(element.x, element.y, font='12', text=text))


class DisplayMenu(DisplayGame):
    def __init__(self, root, canvas, controller):
        menu = tk.Frame(root, bg='grey', width=400, height=40)
        menu.pack(fill='x')
        new_game = tk.Button(menu, text="New Game", width=15, height=2, font='12', command=controller.start_new_game)
        new_game.pack(side="top")
        continue_game = tk.Button(menu, text="Continue", width=15, height=2, font='12', command=controller.continue_game)
        continue_game.pack(side="top")
        exit_game = tk.Button(menu, text="Exit Game", width=15, height=2, font='12', command=controller.exit_game)
        exit_game.pack(side="top")
        _id = canvas.create_window(bg_width / 2, bg_height / 2, window=menu)
        super().__init__(canvas, _id)


class GameView:
    def __init__(self, model, controller):
        self.model = model
        self.controller = controller

        # root
        self.root = tk.Tk()
        self.root.title('Basketball Game')

        # load images files
        self.images = GameImages()

        # canvas
        self.canvas = tk.Canvas(self.root, width= bg_width, height= bg_height)
        self.canvas.pack()
        self.root.update()

        # canvas elements id
        self.elements_id = []
        self.add_elements_to_canvas()

        self.add_event_handlers()

        self.is_menu_open = False

        self.draw()
        self.root.mainloop()


    def add_elements_to_canvas(self):
        for e in self.model.elements:
            if type(e) is TextInfo:
                self.elements_id.append(DisplayGameText(self.canvas, e))
            else:
                self.elements_id.append(DisplayGameImage(self.canvas, e, self.images.get_image(e)))
        if self.model.status == Status.pause or self.model.status == Status.game_over:
            self.elements_id.append(DisplayMenu(self.root, self.canvas, self.controller))
            self.is_menu_open = True



    def add_event_handlers(self):
        self.root.bind("<Left>", self.controller.press_left)
        self.root.bind("<Right>", self.controller.press_right)
        self.root.bind("p", self.controller.press_p)
        self.root.bind("<space>",self.controller.press_space)

    def draw(self):
        self.controller.update_model()
        if self.model.status == Status.run or not self.is_menu_open:
            self.is_menu_open = False
            self.canvas.delete("all")
            self.add_elements_to_canvas()
        if self.model.status == Status.terminate:
            self.root.destroy()
        else:
            self.canvas.after(5, self.draw)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...