# 第三章:遊戲物件初始設定 ## 磚塊 * ### 定義磚塊類別 * #### 介紹: * 初始建構: * 將圖像設成寬為`BRICK_WIDTH`、高為`BRICK_HEIGHT`、顏色為紅色的矩形。 * 將左上角位置設在傳入的`(x, y)`座標 * #### 程式碼: ```python= class Brick(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.image = pygame.Surface((BRICK_WIDTH, BRICK_HEIGHT)) self.image.fill(RED) self.rect = self.image.get_rect() self.rect.topleft = x, y ``` * ### 相關常數設定 * #### 介紹: ![上午1.06 2026](https://hackmd.io/_uploads/ryDQdC67el.jpg =75%x) * #### 程式碼: ```python= BRICK_ROWS = 5 BRICK_COLS = 8 BRICK_MARGIN = 70 BRICK_SPACING = 8 BRICK_WIDTH = (WIDTH - 2 * BRICK_MARGIN - (BRICK_COLS - 1) * BRICK_SPACING) // BRICK_COLS BRICK_HEIGHT = 45 ``` * ### 創建物件 ```python= # 磚塊 Group bricks = pygame.sprite.Group() # 迴圈創建磚塊 for r in range(BRICK_ROWS): for c in range(BRICK_COLS): x = c * (BRICK_WIDTH + BRICK_SPACING) + BRICK_MARGIN y = r * (BRICK_HEIGHT + BRICK_SPACING) + BRICK_MARGIN brick = Brick(x, y) all_sprites.add(brick) bricks.add(brick) ``` ## 板子 * ### 定義板子類別 * #### 介紹: * 初始建構: * 將圖像設為大小為`BOARD_SIZE`、顏色為藍色的矩形 * 將中心位置設在傳入的`center`座標 * 移動速度(每步移動距離)設為 15 * 每次`update()`時若按住 * 左鍵:向左移動一步,若圖形左側超出視窗左側,將其移回視窗左側 * 右鍵:向右移動一步,若圖形右側超出視窗右側,將其移回視窗右側 * #### 程式碼: ```python= BOARD_SIZE = (150, 30) class Board(pygame.sprite.Sprite): def __init__(self, center): super().__init__() self.image = pygame.Surface(BOARD_SIZE) self.image.fill(BLUE) self.rect = self.image.get_rect() self.rect.center = center self.speed = 15 def update(self): keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: self.rect.x -= self.speed if self.rect.left < 0: self.rect.left = 0 if keys[pygame.K_RIGHT]: self.rect.x += self.speed if self.rect.right > WIDTH: self.rect.right = WIDTH ``` * #### 語法說明: * `pygame.key.get_pressed()`: 用來偵測鍵盤上哪些按鍵正被按住。回傳一個「*boolean* 的列表」,表示每個按鍵的狀態(按下是 True,沒按是 False)。 * `pygame.K_LEFT` / `pygame.K_RIGHT`: 用以表示鍵盤某個按鍵的 *int* 常數,拿來和鍵盤事件做比對或查詢。分別表示左鍵和右鍵。 * ### 創建物件 ```python= board = Board((WIDTH // 2, HEIGHT - 60)) all_sprites.add(board) ``` ## 球 * ### 定義球類別 * #### 介紹: * 設定「全部球」的移動速度。 * 初始建構: * 將圖像設定為半徑為`BALL_RADIUS`、顏色為綠色的「圓形」 * 將中心位置設在傳入的`center`座標 * 利用球速以及傳入的移動角度`angle`,透過三角函數算出 x , y 方向的速度 ![image](https://hackmd.io/_uploads/r1PyvXsxlx.png =40%x) * 每次`update`: * 向前移動一步 * 如果撞到上、左或右的便反彈 * 如果掉到底下則將其刪除 * #### 程式碼: ```python= import math BALL_RADIUS = 15 class Ball(pygame.sprite.Sprite): speed = 7 def __init__(self, angle, center): super().__init__() self.image = pygame.Surface((2 * BALL_RADIUS, 2 * BALL_RADIUS), pygame.SRCALPHA) pygame.draw.circle(self.image, GREEN, (BALL_RADIUS, BALL_RADIUS), BALL_RADIUS) self.rect = self.image.get_rect() self.rect.center = center self.dx = Ball.speed * math.sin(angle) self.dy = -Ball.speed * math.cos(angle) def update(self): self.rect.x += self.dx self.rect.y += self.dy if self.rect.left <= 0: self.rect.left = 0 self.dx = -self.dx elif self.rect.right >= WIDTH: self.rect.right = WIDTH self.dx = -self.dx if self.rect.top <= 0: self.rect.top = 0 self.dy = -self.dy elif self.rect.top >= HEIGHT: self.kill() ``` :::info 須先導入 `math` 模組 ::: * #### 語法說明: * `pygame.SRCALPHA` Pygame 中的一個旗標常數(flag constant),代表啟用透明度的功能。原先預設只有 (R, G, B) 三個通道,使用後變成 (R, G, B, A) 四個通道,A 表示透明度。 * `pygame.draw.circle(surface, color, center, radius)` 在平面上畫一個圓形。surface為選擇的平面,color為圓形顏色,center為圓心在平面上的位置,radius為圓形半徑。 * ### 創建物件 ```python= balls = pygame.sprite.Group() ball = Ball(math.pi / 4, (WIDTH // 2, HEIGHT - 150)) all_sprites.add(ball) balls.add(ball) ``` --- :::spoiler 完整程式碼 ```python= import pygame import math FPS = 60 # 大小設定 WIDTH, HEIGHT = 800, 700 BRICK_ROWS = 5 BRICK_COLS = 8 BRICK_MARGIN = 70 BRICK_SPACING = 8 BRICK_WIDTH = (WIDTH - 2 * BRICK_MARGIN - (BRICK_COLS - 1) * BRICK_SPACING) // BRICK_COLS BRICK_HEIGHT = 40 BOARD_SIZE = (150, 30) BALL_RADIUS = 15 # 顏色設定 WHITE = (255, 255, 255) BLUE = (0, 0, 255) RED = (255, 0, 0) GREEN = (0, 255, 0) pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("打磚塊遊戲") clock = pygame.time.Clock() # 定義磚塊類別 class Brick(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.image = pygame.Surface((BRICK_WIDTH, BRICK_HEIGHT)) self.image.fill(RED) self.rect = self.image.get_rect() self.rect.topleft = x, y # 定義板子類別 class Board(pygame.sprite.Sprite): def __init__(self, center): super().__init__() self.image = pygame.Surface(BOARD_SIZE) self.image.fill(BLUE) self.rect = self.image.get_rect() self.rect.center = center self.speed = 15 def update(self): keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: self.rect.x -= self.speed if self.rect.left < 0: self.rect.left = 0 if keys[pygame.K_RIGHT]: self.rect.x += self.speed if self.rect.right > WIDTH: self.rect.right = WIDTH class Ball(pygame.sprite.Sprite): speed = 7 def __init__(self, angle, center): super().__init__() self.image = pygame.Surface((2 * BALL_RADIUS, 2 * BALL_RADIUS), pygame.SRCALPHA) pygame.draw.circle(self.image, GREEN, (BALL_RADIUS, BALL_RADIUS), BALL_RADIUS) self.rect = self.image.get_rect() self.rect.center = center self.dx = Ball.speed * math.sin(angle) self.dy = -Ball.speed * math.cos(angle) def update(self): self.rect.x += self.dx self.rect.y += self.dy if self.rect.left <= 0: self.rect.left = 0 self.dx = -self.dx elif self.rect.right >= WIDTH: self.rect.right = WIDTH self.dx = -self.dx if self.rect.top <= 0: self.rect.top = 0 self.dy = -self.dy elif self.rect.top >= HEIGHT: self.kill() all_sprites = pygame.sprite.Group() # 磚塊 bricks = pygame.sprite.Group() for r in range(BRICK_ROWS): for c in range(BRICK_COLS): x = c * (BRICK_WIDTH + BRICK_SPACING) + BRICK_MARGIN y = r * (BRICK_HEIGHT + BRICK_SPACING) + BRICK_MARGIN brick = Brick(x, y) all_sprites.add(brick) bricks.add(brick) # 板子 board = Board((WIDTH // 2, HEIGHT - 60)) all_sprites.add(board) # 球 balls = pygame.sprite.Group() ball = Ball(math.pi / 4, (WIDTH // 2, HEIGHT - 150)) all_sprites.add(ball) balls.add(ball) running = True while running: clock.tick(FPS) # 輸入處理 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # 更新遊戲 all_sprites.update() # 畫面顯示 screen.fill(WHITE) all_sprites.draw(screen) pygame.display.update() pygame.quit() ``` :::