Я пытаюсь создать "Баскетбольную игру", используя 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)