Skip to content

Instantly share code, notes, and snippets.

@wuyongzheng
Created March 26, 2024 16:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wuyongzheng/115e048ce228a4c9573afecd0c480b09 to your computer and use it in GitHub Desktop.
Save wuyongzheng/115e048ce228a4c9573afecd0c480b09 to your computer and use it in GitHub Desktop.
import math
import pygame
# define game setting
NUM_BRICKS = (10, 10)
SCREEN_SIZE = (600, 400)
PAD_SIZE = (120, 10)
BALL_R = 10
BRICK_W = SCREEN_SIZE[0] / NUM_BRICKS[0]
BRICK_H = SCREEN_SIZE[1] / NUM_BRICKS[1] / 2
# game state variable
class GameState(object):
def __init__(self):
self.bricks = [[True] * NUM_BRICKS[1] for i in range(NUM_BRICKS[0])]
self.bx = 0 # ball position x
self.by = 0 # ball position y
self.bvx = 0 # ball velocity x
self.bvy = 0 # ball velocity y
self.px = (SCREEN_SIZE[0] - PAD_SIZE[0]) / 2 # pad's left edge x coordinate
def render(gs):
screen = pygame.display.get_surface()
# draw black background
screen.fill((0, 0, 0))
# draw bricks
for x in range(NUM_BRICKS[0]):
for y in range(NUM_BRICKS[1]):
if gs.bricks[x][y]:
pygame.draw.rect(screen, (128, 128, 128), pygame.Rect(x * BRICK_W + 1, y * BRICK_H + 1, BRICK_W - 2, BRICK_H - 2))
# draw pad and ball
pygame.draw.rect(screen, (255, 255, 255), pygame.Rect(gs.px, SCREEN_SIZE[1] - PAD_SIZE[1], PAD_SIZE[0], PAD_SIZE[1]))
if gs.bvx == 0 and gs.bvy == 0: # game have not started. ball is resting on the pad.
pygame.draw.circle(screen, (255, 255, 255), (gs.px + PAD_SIZE[0] * 0.75, SCREEN_SIZE[1] - PAD_SIZE[1] - BALL_R), BALL_R)
else:
pygame.draw.circle(screen, (255, 255, 255), (gs.bx, gs.by), BALL_R)
def ball_brick_hit(gs, kx1, ky1, kx2, ky2):
# detect if ball hit block's top and bottom surface
if gs.bx > kx1 and gs.bx < kx2 and gs.by + BALL_R > ky1 and gs.by - BALL_R < ky2:
gs.bvy = -gs.bvy
return True
# detect if ball hit block's left and right surface
if gs.by > ky1 and gs.by < ky2 and gs.bx + BALL_R > kx1 and gs.bx - BALL_R < kx2:
gs.bvx = -gs.bvx
return True
return False
# compute ball velocity after hitting the pad
def ball_pad_hit(gs):
# x is between 0 and 1. x=0 means hitting pad's left most part.
x = (gs.bx - gs.px) / PAD_SIZE[0]
out_angle = 170 - 160*x
out_angle = out_angle * math.pi / 180
v = math.sqrt(gs.bvx*gs.bvx + gs.bvy*gs.bvy)
gs.bvx = math.cos(out_angle) * v
gs.bvy = -math.sin(out_angle) * v
def update(gs):
if gs.bvx == 0 and gs.bvy == 0: # game have not started. ball is resting on the pad.
return
gs.bx += gs.bvx
gs.by += gs.bvy
# detect ball-border collision
if gs.bvx > 0 and gs.bx > SCREEN_SIZE[0] - BALL_R:
gs.bvx = -gs.bvx
if gs.bvx < 0 and gs.bx < BALL_R:
gs.bvx = -gs.bvx
if gs.bvy < 0 and gs.by < BALL_R:
gs.bvy = -gs.bvy
# detect abyss
if gs.bvy > 0 and gs.by > SCREEN_SIZE[1] - PAD_SIZE[1] - BALL_R:
if gs.bx < gs.px or gs.bx > gs.px + PAD_SIZE[0]: # game over, reset
gs.bvx = gs.bvy = 0
else: # bounce from pad
ball_pad_hit(gs)
# detect ball-block collision
for x in range(NUM_BRICKS[0]):
for y in range(NUM_BRICKS[1]):
if gs.bricks[x][y]:
if ball_brick_hit(gs, x * BRICK_W, y * BRICK_H, (x+1) * BRICK_W, (y+1) * BRICK_H):
gs.bricks[x][y] = False
def main():
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
clock = pygame.time.Clock()
gs = GameState()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
elif event.type == pygame.MOUSEMOTION:
pos = pygame.mouse.get_pos()
gs.px = pos[0] - PAD_SIZE[0] / 2
if gs.px < 0:
gs.px = 0
elif gs.px > SCREEN_SIZE[0] - PAD_SIZE[0]:
gs.px = SCREEN_SIZE[0] - PAD_SIZE[0]
elif event.type == pygame.MOUSEBUTTONUP:
if gs.bvx == 0 and gs.bvy == 0:
gs.bvx = 2
gs.bvy = -4.5
gs.bx = gs.px + PAD_SIZE[0] * 0.75
gs.by = SCREEN_SIZE[1] - PAD_SIZE[1] - BALL_R
update(gs)
render(gs)
pygame.display.flip()
clock.tick(50)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment