from tkinter import * # 1. Задання розмірів об'єктів: WIDTH = 740 # ширина вікна HEIGHT = 400 # висота вікна PAD_W = 10 # ширина ракетки PAD_H = 100 # висота ракетки BALL_D = 30 # діаметр м'яча # 2. Створення об'єктів: вікна root = Tk() root.title("Ping Pong") # 2. Створення … полотна c = Canvas(root, width=WIDTH, height=HEIGHT, background="green") c.pack() # 2. Створення … ліній розмітки c.create_line(PAD_W, 0, PAD_W, HEIGHT, fill="white") c.create_line(WIDTH-PAD_W, 0, WIDTH-PAD_W, HEIGHT, fill="white") c.create_line(WIDTH/2, 0, WIDTH/2, HEIGHT, fill="white") # 2. Створення … круга - зображення м'яча BALL = c.create_oval(WIDTH/2-BALL_D/2, HEIGHT/2-BALL_D/2, WIDTH/2+BALL_D/2, HEIGHT/2+BALL_D/2, fill="WHITE") # 2. Створення … прямокутників - зображень ракеток LEFT_PAD = c.create_line(PAD_W/2, 0, PAD_W/2, PAD_H, width=PAD_W, fill="yellow") RIGHT_PAD = c.create_line(WIDTH-PAD_W/2,0, WIDTH-PAD_W/2,PAD_H, width=PAD_W, fill="red") # 3. Опис руху м'ячика BALL_X_CHANGE = 20 BALL_Y_CHANGE = 0 def move_ball(): c.move(BALL, BALL_X_CHANGE, BALL_Y_CHANGE) def main(): move_ball() root.after(40, main) main() # 4. Опис керування ракетками PAD_SPEED = 20 # приріст ординати LEFT_PAD_SPEED = 0 # початкова швидкість RIGHT_PAD_SPEED = 0 # початкова швидкість def move_pads(): # словник (ракетка, швидкість) PADS = {LEFT_PAD: LEFT_PAD_SPEED, RIGHT_PAD: RIGHT_PAD_SPEED} for pad in PADS: # перебір ракеток c.move(pad, 0, PADS[pad]) # рух ракетки if c.coords(pad)[1] < 0: # при виході за межі поля повернення на поле c.move(pad, 0, -c.coords(pad)[1]) elif c.coords(pad)[3] > HEIGHT: c.move(pad, 0, HEIGHT - c.coords(pad)[3]) def main(): move_ball() move_pads() root.after(40, main) # 5. Опис опрацювання натискання клавіш c.focus_set() def movement_handler(event): global LEFT_PAD_SPEED, RIGHT_PAD_SPEED if event.keysym == "w": LEFT_PAD_SPEED = -PAD_SPEED elif event.keysym == "s": LEFT_PAD_SPEED = PAD_SPEED elif event.keysym == "Up": RIGHT_PAD_SPEED = -PAD_SPEED elif event.keysym == "Down": RIGHT_PAD_SPEED = PAD_SPEED # прив'язування до Canvas функції movement_handler c.bind("", movement_handler) # 6. Опис опрацювання відпускання клавіші def stop_pad(event): global LEFT_PAD_SPEED, RIGHT_PAD_SPEED if event.keysym in "ws": LEFT_PAD_SPEED = 0 elif event.keysym in ("Up", "Down"): RIGHT_PAD_SPEED = 0 c.bind("", stop_pad) # 7. Опис відбивання м'ячика import random BALL_SPEED_UP = 0.05 # приріст швидкості м'яча після кожного удару BALL_MAX_SPEED = 20 # максимальна швидкість м'яча BALL_X_SPEED = 10 # початкова швидкість по горизонталі BALL_Y_SPEED = 10 # початкова швидкість по вертикалі right_line_distance = WIDTH - PAD_W # відстань до правого краю поля def bounce(action): global BALL_X_SPEED, BALL_Y_SPEED if action == "strike": # якщо вдарили ракеткою… BALL_Y_SPEED = random.randrange(-10, 10) if abs(BALL_X_SPEED) < BALL_MAX_SPEED: BALL_X_SPEED *= -BALL_SPEED_UP else: BALL_X_SPEED = -BALL_X_SPEED else: BALL_Y_SPEED = -BALL_Y_SPEED def move_ball(): # переозначення функції руху м'яча # визначення координат сторін м'яча і його центру ball_left, ball_top, ball_right, ball_bot = c.coords(BALL) ball_center = (ball_top + ball_bot) / 2 # якщо м'яч далеко від правої та лівої меж поля… if ball_right + BALL_X_SPEED < right_line_distance and \ ball_left + BALL_X_SPEED > PAD_W: c.move(BALL, BALL_X_SPEED, BALL_Y_SPEED) # прямолінійний і рівномірний рух # якщо м'яч торкається правого або лівого краю поля… elif ball_right == right_line_distance or ball_left == PAD_W: if ball_right > WIDTH / 2: # якщо м'яч торкається правого краю поля… # якщо м'яч торкається ракетки… if c.coords(RIGHT_PAD)[1] < ball_center < c.coords(RIGHT_PAD)[3]: bounce("strike") else: update_score("left") # очко на користь гравця ліворуч spawn_ball() # вкидання м'яча else: # якщо м'яч торкається лівого краю поля… # якщо м'яч торкається ракетки… if c.coords(LEFT_PAD)[1] < ball_center < c.coords(LEFT_PAD)[3]: bounce("strike") else: update_score("right") # очко на користь гравця праворуч spawn_ball() # вкидання м'яча else: # якщо м'ячик може вилетіти за межі поля, рух його до межі поля if ball_right > WIDTH / 2: c.move(BALL, right_line_distance-ball_right, BALL_Y_SPEED) else: c.move(BALL, -ball_left+PAD_W, BALL_Y_SPEED) if ball_top + BALL_Y_SPEED < 0 or ball_bot + BALL_Y_SPEED > HEIGHT: bounce("ricochet") # відбивання від верхнього або нижнього краю # 8. Опис обліку й виведення рахунку. PLAYER_1_SCORE = 0 # кількість очок, набраних гравцем 1 (праворуч) PLAYER_2_SCORE = 0 # кількість очок, набраних гравцем 2 (ліворуч) # виведення кількостей очок p_1_text = c.create_text(WIDTH-WIDTH/6, PAD_H/4,text=PLAYER_1_SCORE,font="Arial 20",fill="white") p_2_text = c.create_text(WIDTH/6, PAD_H/4,text=PLAYER_2_SCORE,font="Arial 20",fill="white") INITIAL_SPEED = 20 # початкова швидкість def update_score(player): # оновлення рахунку global PLAYER_1_SCORE, PLAYER_2_SCORE if player == "right": PLAYER_1_SCORE += 1 c.itemconfig(p_1_text, text=PLAYER_1_SCORE) else: PLAYER_2_SCORE += 1 c.itemconfig(p_2_text, text=PLAYER_2_SCORE) # 9. Вкидання м'яча def spawn_ball(): global BALL_X_SPEED # Виставити м'яч у центрі поля c.coords(BALL, WIDTH/2 -BALL_D/2, HEIGHT/2-BALL_D/2, WIDTH/2 +BALL_D/2, HEIGHT/2+BALL_D/2) BALL_X_SPEED = (BALL_X_SPEED) * INITIAL_SPEED / abs(BALL_X_SPEED) # 10. Відкриття вікна програми. root.mainloop()