mirror of
https://github.com/metafy-social/python-scripts.git
synced 2024-11-24 04:21:12 +00:00
230 lines
6.0 KiB
Python
230 lines
6.0 KiB
Python
import pygame
|
|
import math
|
|
|
|
pygame.init()
|
|
|
|
WIDTH, HEIGHT = 800, 600
|
|
win = pygame.display.set_mode((WIDTH, HEIGHT))
|
|
pygame.display.set_caption("Brick Breaker")
|
|
|
|
FPS = 60
|
|
PADDLE_WIDTH = 100
|
|
PADDLE_HEIGHT = 15
|
|
BALL_RADIUS = 10
|
|
|
|
LIVES_FONT = pygame.font.SysFont("comicsans", 40)
|
|
|
|
|
|
class Paddle:
|
|
VEL = 5
|
|
|
|
def __init__(self, x, y, width, height, color):
|
|
self.x = x
|
|
self.y = y
|
|
self.width = width
|
|
self.height = height
|
|
self.color = color
|
|
|
|
def draw(self, win):
|
|
pygame.draw.rect(
|
|
win, self.color, (self.x, self.y, self.width, self.height))
|
|
|
|
def move(self, direction=1):
|
|
self.x = self.x + self.VEL * direction
|
|
|
|
|
|
class Ball:
|
|
VEL = 5
|
|
|
|
def __init__(self, x, y, radius, color):
|
|
self.x = x
|
|
self.y = y
|
|
self.radius = radius
|
|
self.color = color
|
|
self.x_vel = 0
|
|
self.y_vel = -self.VEL
|
|
|
|
def move(self):
|
|
self.x += self.x_vel
|
|
self.y += self.y_vel
|
|
|
|
def set_vel(self, x_vel, y_vel):
|
|
self.x_vel = x_vel
|
|
self.y_vel = y_vel
|
|
|
|
def draw(self, win):
|
|
pygame.draw.circle(win, self.color, (self.x, self.y), self.radius)
|
|
|
|
|
|
class Brick:
|
|
def __init__(self, x, y, width, height, health, colors):
|
|
self.x = x
|
|
self.y = y
|
|
self.width = width
|
|
self.height = height
|
|
self.health = health
|
|
self.max_health = health
|
|
self.colors = colors
|
|
self.color = colors[0]
|
|
|
|
def draw(self, win):
|
|
pygame.draw.rect(
|
|
win, self.color, (self.x, self.y, self.width, self.height))
|
|
|
|
def collide(self, ball):
|
|
if not (ball.x <= self.x + self.width and ball.x >= self.x):
|
|
return False
|
|
if not (ball.y - ball.radius <= self.y + self.height):
|
|
return False
|
|
|
|
self.hit()
|
|
ball.set_vel(ball.x_vel, ball.y_vel * -1)
|
|
return True
|
|
|
|
def hit(self):
|
|
self.health -= 1
|
|
self.color = self.interpolate(
|
|
*self.colors, self.health/self.max_health)
|
|
|
|
@staticmethod
|
|
def interpolate(color_a, color_b, t):
|
|
# 'color_a' and 'color_b' are RGB tuples
|
|
# 't' is a value between 0.0 and 1.0
|
|
# this is a naive interpolation
|
|
return tuple(int(a + (b - a) * t) for a, b in zip(color_a, color_b))
|
|
|
|
|
|
def draw(win, paddle, ball, bricks, lives):
|
|
win.fill("white")
|
|
paddle.draw(win)
|
|
ball.draw(win)
|
|
|
|
for brick in bricks:
|
|
brick.draw(win)
|
|
|
|
lives_text = LIVES_FONT.render(f"Lives: {lives}", 1, "black")
|
|
win.blit(lives_text, (10, HEIGHT - lives_text.get_height() - 10))
|
|
|
|
pygame.display.update()
|
|
|
|
|
|
def ball_collision(ball):
|
|
if ball.x - BALL_RADIUS <= 0 or ball.x + BALL_RADIUS >= WIDTH:
|
|
ball.set_vel(ball.x_vel * -1, ball.y_vel)
|
|
if ball.y + BALL_RADIUS >= HEIGHT or ball.y - BALL_RADIUS <= 0:
|
|
ball.set_vel(ball.x_vel, ball.y_vel * -1)
|
|
|
|
|
|
def ball_paddle_collision(ball, paddle):
|
|
if not (ball.x <= paddle.x + paddle.width and ball.x >= paddle.x):
|
|
return
|
|
if not (ball.y + ball.radius >= paddle.y):
|
|
return
|
|
|
|
paddle_center = paddle.x + paddle.width/2
|
|
distance_to_center = ball.x - paddle_center
|
|
|
|
percent_width = distance_to_center / paddle.width
|
|
angle = percent_width * 90
|
|
angle_radians = math.radians(angle)
|
|
|
|
x_vel = math.sin(angle_radians) * ball.VEL
|
|
y_vel = math.cos(angle_radians) * ball.VEL * -1
|
|
|
|
ball.set_vel(x_vel, y_vel)
|
|
|
|
|
|
def generate_bricks(rows, cols):
|
|
gap = 2
|
|
brick_width = WIDTH // cols - gap
|
|
brick_height = 20
|
|
|
|
bricks = []
|
|
for row in range(rows):
|
|
for col in range(cols):
|
|
brick = Brick(col * brick_width + gap * col, row * brick_height +
|
|
gap * row, brick_width, brick_height, 2, [(0, 255, 0), (255, 0, 0)])
|
|
bricks.append(brick)
|
|
|
|
return bricks
|
|
|
|
|
|
def main():
|
|
clock = pygame.time.Clock()
|
|
|
|
paddle_x = WIDTH/2 - PADDLE_WIDTH/2
|
|
paddle_y = HEIGHT - PADDLE_HEIGHT - 5
|
|
paddle = Paddle(paddle_x, paddle_y, PADDLE_WIDTH, PADDLE_HEIGHT, "black")
|
|
ball = Ball(WIDTH/2, paddle_y - BALL_RADIUS, BALL_RADIUS, "black")
|
|
|
|
bricks = generate_bricks(3, 10)
|
|
lives = 3
|
|
|
|
def reset():
|
|
paddle.x = paddle_x
|
|
paddle.y = paddle_y
|
|
ball.x = WIDTH/2
|
|
ball.y = paddle_y - BALL_RADIUS
|
|
|
|
|
|
def display_text(text):
|
|
text_render = LIVES_FONT.render(text, 1, "red")
|
|
win.blit(text_render, (WIDTH/2 - text_render.get_width() /
|
|
2, HEIGHT/2 - text_render.get_height()/2))
|
|
pygame.display.update()
|
|
pygame.time.delay(3000)
|
|
|
|
run = True
|
|
while run:
|
|
clock.tick(FPS)
|
|
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT:
|
|
run = False
|
|
break
|
|
|
|
keys = pygame.key.get_pressed()
|
|
|
|
if keys[pygame.K_LEFT] and paddle.x - paddle.VEL >= 0:
|
|
paddle.move(-1)
|
|
if keys[pygame.K_RIGHT] and paddle.x + paddle.width + paddle.VEL <= WIDTH:
|
|
paddle.move(1)
|
|
|
|
ball.move()
|
|
ball_collision(ball)
|
|
ball_paddle_collision(ball, paddle)
|
|
|
|
for brick in bricks[:]:
|
|
brick.collide(ball)
|
|
|
|
if brick.health <= 0:
|
|
bricks.remove(brick)
|
|
|
|
# lives check
|
|
if ball.y + ball.radius >= HEIGHT:
|
|
lives -= 1
|
|
ball.x = paddle.x + paddle.width/2
|
|
ball.y = paddle.y - BALL_RADIUS
|
|
ball.set_vel(0, ball.VEL * -1)
|
|
|
|
if lives <= 0:
|
|
bricks = generate_bricks(3, 10)
|
|
lives = 3
|
|
reset()
|
|
display_text("You Lost!")
|
|
|
|
if len(bricks) == 0:
|
|
bricks = generate_bricks(3, 10)
|
|
lives = 3
|
|
reset()
|
|
display_text("You Won!")
|
|
|
|
draw(win, paddle, ball, bricks, lives)
|
|
|
|
pygame.quit()
|
|
quit()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|