Created
March 26, 2024 16:00
-
-
Save wuyongzheng/115e048ce228a4c9573afecd0c480b09 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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