Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tkinter as tk
- class Shape:
- def __init__(self, x, y, width, height, center=False):
- if center:
- x -= width // 2
- y -= height // 2
- self.x1 = x
- self.y1 = y
- self.x2 = x + width
- self.y2 = y + height
- class Paddle(Shape):
- def __init__(self, x, y, width=45, height=8, speed=6, color="blue"):
- super().__init__(x, y, width, height, center=True)
- self.speed = speed
- self.color = color
- self.name = "paddle"
- def right(self, event):
- self.x1 += self.speed
- self.x2 += self.speed
- def left(self, event):
- self.x1 -= self.speed
- self.x2 -= self.speed
- def move(self):
- pass
- def limit(self, area):
- adjust = (max(self.x1, area.x1) - self.x1 or
- min(self.x2, area.x2) - self.x2)
- self.x1 += adjust
- self.x2 += adjust
- class Ball(Shape):
- def __init__(self, x, y, size=10, dx=2, dy=2, color="red"):
- super().__init__(x, y, size, size, center=True)
- self.dx = dx
- self.dy = dy
- self.color = color
- self.name = "ball"
- def move(self):
- self.x1 += self.dx
- self.y1 += self.dy
- self.x2 += self.dx
- self.y2 += self.dy
- def limit(self, area):
- if self.x1 <= area.x1 or area.x2 <= self.x2:
- self.dx *= -1
- if self.y1 <= area.y1 or area.y2 <= self.y2:
- self.dy *= -1
- def bound(self, target):
- hit_x = max(self.x1, target.x1) <= min(self.x2, target.x2)
- hit_y = max(self.y1, target.y1) <= min(self.y2, target.y2)
- if not (hit_x and hit_y):
- return False
- center_x = (self.x1 + self.x2) // 2
- center_y = (self.y1 + self.y2) // 2
- if (self.dx > 0 and center_x <= target.x1 or
- self.dx < 0 and target.x2 <= center_x):
- self.dx *= -1
- if (self.dy > 0 and center_y <= target.y1 or
- self.dy < 0 and target.y2 <= center_y):
- self.dy *= -1
- return True
- class Block(Shape):
- def __init__(self, x, y, width, height, gap_x=0, gap_y=0, center=False,
- color="orange", point=1):
- super().__init__(x + gap_x, y + gap_y,
- width - gap_x * 2, height - gap_y * 2, center=center)
- self.point = point
- self.color = color
- self.name = f"block{x}.{y}"
- self.exists = True
- def break_and_bound(self, target):
- if self.exists and target.bound(self):
- self.exists = False
- return self.point
- else:
- return 0
- def is_broken(self):
- return not self.exists
- class BlockRow:
- def __init__(self, color, point):
- self.color = color
- self.point = point
- class Blocks:
- #ROWS = [BlockRow("orange", 1)] * 3
- ROWS = BlockRow("cyan", 10), BlockRow("yellow", 20), BlockRow("orange", 30)
- def __init__(self, x, y, width, height, columns=12, rows=None):
- rows = (rows or self.ROWS)[::-1]
- w = width // columns
- h = height // len(rows)
- self.blocks = [Block(x + dx, y + dy, w, h, gap_x=6, gap_y=12,
- color=row.color, point=row.point)
- for dy, row in zip(range(0, h * len(rows) + 1, h), rows)
- for dx in range(0, w * columns + 1, w)]
- def __iter__(self):
- return iter(self.blocks)
- def break_and_bound(self, target):
- return sum(block.break_and_bound(target) for block in self.blocks)
- def are_wiped(self):
- return all(block.is_broken() for block in self.blocks)
- class Wall(Shape):
- CATCH_LINES = 3
- def __init__(self, x, y, width, height):
- super().__init__(x, y, width, height)
- self.catch_line = self.y2 - self.CATCH_LINES
- def catch(self, target):
- return target.y2 >= self.catch_line
- class Score:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- self.score = 0
- self.name = "score"
- def __str__(self):
- return str(self.score)
- def add(self, point):
- self.score += point
- class BreakoutModel:
- def __init__(self, width, height):
- self.paddle = Paddle(width // 2, height - 30)
- self.ball = Ball(width // 3, height * 2 // 3)
- self.blocks = Blocks(0, 40, width, 120)
- self.wall = Wall(0, 0, width, height)
- self.score = Score(width - 70, 20)
- self.message = None
- def update(self):
- self.paddle.move()
- self.paddle.limit(self.wall)
- self.ball.move()
- self.ball.limit(self.wall)
- self.ball.bound(self.paddle)
- point = self.blocks.break_and_bound(self.ball)
- self.score.add(point)
- self.over()
- self.clear()
- def over(self):
- self.message = self.wall.catch(self.ball) and "GAME OVER(T_T)"
- def clear(self):
- self.message = self.blocks.are_wiped() and "GAME CLEAR(^0^)"
- class BreakoutView:
- SCORE_FONT = ('FixedSys', 16)
- MESSAGE_FONT = ('FixedSys', 40)
- def __init__(self, window, width, height):
- self.canvas = tk.Canvas(window, width=width, height=height)
- self.center = (width // 2, height // 2)
- window.title("ブロック崩し")
- window.minsize(width, height)
- window.maxsize(width, height)
- self.draw_rectangle = self.canvas.create_rectangle
- self.draw_oval = self.canvas.create_oval
- self.draw_text = self.canvas.create_text
- def update(self, model):
- self.ball(model.ball)
- self.paddle(model.paddle)
- self.blocks(model.blocks)
- self.score(model.score)
- self.message(model.message)
- self.canvas.pack()
- def delete(self, model):
- self.canvas.delete(model.name)
- def paddle(self, paddle):
- self.delete(paddle)
- self.draw_rectangle(paddle.x1, paddle.y1, paddle.x2, paddle.y2,
- fill=paddle.color, tag=paddle.name)
- def ball(self, ball):
- self.delete(ball)
- self.draw_oval(ball.x1, ball.y1, ball.x2, ball.y2,
- fill=ball.color, tag=ball.name)
- def blocks(self, blocks):
- for block in blocks:
- self.delete(block)
- if block.exists:
- self.draw_rectangle(block.x1, block.y1, block.x2, block.y2,
- fill=block.color, tag=block.name)
- def score(self, score):
- self.delete(score)
- self.draw_text(score.x, score.y, text=f"Score = {score}",
- font=self.SCORE_FONT, tag=score.name)
- def message(self, message):
- if message:
- self.draw_text(*self.center, text=message, font=self.MESSAGE_FONT)
- class Breakout:
- TICK = 20 # 更新間隔
- def __init__(self, width, height):
- self.controller = window = tk.Tk()
- self.model = BreakoutModel(width, height)
- self.view = BreakoutView(window, width, height)
- self.view.update(self.model)
- self.keybind()
- def keybind(self):
- self.controller.bind("q", self.controller.quit)
- self.controller.bind("<Right>", self.model.paddle.right)
- self.controller.bind("<Left>", self.model.paddle.left)
- def start(self):
- self.update()
- try:
- self.controller.mainloop()
- except KeyboardInterrupt:
- self.controller.quit()
- def update(self):
- try:
- if self.model.message:
- input("Hit return key to end")
- self.controller.quit()
- else:
- self.model.update()
- self.view.update(self.model)
- self.controller.after(self.TICK, self.update)
- except KeyboardInterrupt:
- self.controller.quit()
- if __name__ == '__main__':
- Breakout(width=600, height=480).start()
Add Comment
Please, Sign In to add comment