# 資研 6/7 上課講義 ## Pygame >參考自 *Python 自學聖經-Python 入門教學* ### 繪圖函式 #### 矩形 :::warning **分開寫的話在後續經營、維護時比較修改參數** ::: ```python= color = (255, 0, 0) # 紅色 x = 50 y = 50 width = 100 height = 150 linewidth = 2 pygame.draw.rect(background, color, [x, y, width, height], linewidth) ``` >color(r, g, b) rgb 的值可以上網找喜歡的顏色 >linewidth 為線寬,預設為 0(表圖形實心) ```python= import pygame pygame.init() screen = pygame.display.set_mode((640, 320)) pygame.display.set_caption('I2TRC2') background = pygame.Surface(screen.get_size()) background = background.convert() background.fill((255, 255, 255)) # 白色 # 畫矩形 color = (255, 0, 0) # 紅色 x = 50 y = 50 width = 100 height = 150 linewidth = 2 pygame.draw.rect(background, color, [x, y, width, height], linewidth) screen.blit(background, (0, 0)) pygame.display.update() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False pygame.quit() ``` ![image](https://hackmd.io/_uploads/Hy8VoJ8V0.png) #### 圓形 ```python= color = (0, 0, 0) # 黑色 x = 200 y = 200 r = 100 linewidth = 0 # 實心 pygame.draw.circle(background, color, (x, y), r, linewidth) ``` ![image](https://hackmd.io/_uploads/SJ_w2y8EC.png) #### 橢圓形 ```python= color = (0, 0, 255) # 藍色 x = 200 y = 200 x_r = 100 y_r = 20 linewidth = 0 # 實心 pygame.draw.ellipse(background, color, [x, y, x_r, y_r], linewidth) ``` ![image](https://hackmd.io/_uploads/ByVHAk8NC.png) #### 直線 ```python= color = (0, 0, 255) # 藍色 x_1 = 200 y_1 = 200 x_2 = 100 y_2 = 20 linewidth = 3 pygame.draw.line(background, color, (x_1, y_1), (x_2, y_2), linewidth) ``` ![image](https://hackmd.io/_uploads/S1SxylIEC.png) #### 圓弧 ```python= color = (0, 0, 255) # 藍色 x = 200 y = 200 x_r = 100 y_r = 20 start_angle = 0 end_angle = 3.14 linewidth = 3 pygame.draw.arc(background, color, [x, y, x_r, y_r], start_angle, end_angle, linewidth) ``` ![image](https://hackmd.io/_uploads/Hkbkxg840.png) #### 多邊形 ```python= color = (0, 0, 255) # 藍色 points = [(50, 300), (100, 100), (200, 250), (600, 300)] linewidth = 0 pygame.draw.polygon(background, color, points, linewidth) ``` ![image](https://hackmd.io/_uploads/ByIaee8V0.png) ### 載入圖片 #### 載入圖片 ```python= image = pygame.image.load('檔案路徑') ``` #### 建立副本 ```python= image.convert() ``` #### 貼到畫布 ```python= background.blit(image, (50, 50)) ``` >(100, 100) 是圖片被貼上的座標 #### 程式碼 ```python= import pygame pygame.init() screen = pygame.display.set_mode((1000, 500)) pygame.display.set_caption('I2TRC2') background = pygame.Surface(screen.get_size()) background = background.convert() background.fill((255, 255, 255)) # 白色 image = pygame.image.load("C:\\Users\\ti546\\Downloads\\LOGO5S (1).png") image.convert() background.blit(image, (50, 50)) screen.blit(background, (0, 0)) pygame.display.update() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False pygame.quit() ``` ![image](https://hackmd.io/_uploads/SkcwSxUNC.png) ### 顯示文字 #### 設定字型 ```python= font = pygame.font.Font('字型檔案', 24) ``` >24 為字型尺寸 #### 設定文字 ```python= word = '要顯示的文字' smooth = True color = (0, 0, 0) background_color = (245, 222, 179) text = font.render(word, smooth, color, background_color) ``` #### 貼上文字 ```python= background.blit(text, (50, 50)) ``` #### 程式碼 ```python= import pygame pygame.init() screen = pygame.display.set_mode((640, 320)) pygame.display.set_caption('I2TRC2') background = pygame.Surface(screen.get_size()) background = background.convert() background.fill((255, 255, 255)) # 白色 font = pygame.font.Font("C:\\Users\\ti546\\Downloads\\kaiu.ttf", 24) word = '要顯示的文字' smooth = True color = (0, 0, 0) background_color = (245, 222, 179) text = font.render(word, smooth, color, background_color) background.blit(text, (50, 50)) screen.blit(background, (0, 0)) pygame.display.update() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False pygame.quit() ``` ![image](https://hackmd.io/_uploads/H1hGXM8EA.png) ### 動畫 #### 基礎架構 - <font color="##005757">**建立時間**</font> ```python= clock = pygame.time.Clock() ``` - <font color="##005757">**每秒執行 n 次**</font> ```python= clock.tick(n) ``` - <font color="##005757">**清除繪圖視窗**</font> ```python= screen.blit(background, (0 ,0)) ``` >重新貼上一次畫布 ### 打磚塊遊戲 >[**程式碼出處**](https://ithelp.ithome.com.tw/articles/10209660) ```python= import pygame as pg import random import math import time # 建立球體 class Ball(pg.sprite.Sprite): dx = 0 # x位移量 dy = 0 # y位移量 x = 0 # 球x坐標 y = 0 # 球y坐標 direction = 0 # 球移動方向 speed = 0 # 球移動速度 def __init__(self, sp, srx, sry, radium, color): pg.sprite.Sprite.__init__(self) self.speed = sp self.x = srx self.y = sry # 繪製球體 self.image = pg.Surface([radium*2, radium*2]) self.image.fill((255, 255, 255)) pg.draw.circle(self.image, color, (radium, radium), radium, 0) self.rect = self.image.get_rect() # 取得球體區域 self.rect.center = (srx, sry) # 初始位置 self.direction = random.randint(40, 70) # 移動角度 # 球體移動 def update(self): radian = math.radians(self.direction) # 角度轉為弳度 self.dx = self.speed * math.cos(radian) # 球水平運動速度 self.dy = -self.speed * math.sin(radian) # 球垂直運動速度 self.x += self.dx # 計算球新坐標 self.y += self.dy self.rect.x = self.x # 移動球圖形 self.rect.y = self.y # 到達左右邊界 if (self.rect.left <= 0 or self.rect.right >= screen.get_width()-10): self.bouncelr() elif (self.rect.top <= 10): # 到達上邊界 self.rect.top = 10 self.bounceup() if (self.rect.bottom >= screen.get_height()-10): # 到達下邊界出界 return True else: return False def bounceup(self): # 上邊界反彈 self.direction = 360 - self.direction def bouncelr(self): # 左右邊界反彈 self.direction = (180 - self.direction) % 360 # 磚塊類別 class Brick(pg.sprite.Sprite): def __init__(self, color, x, y): pg.sprite.Sprite.__init__(self) self.image = pg.Surface([38, 13]) # 磚塊長寬38x13 self.image.fill(color) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y # 板子類別 class Pad(pg.sprite.Sprite): def __init__(self): pg.sprite.Sprite.__init__(self) self.image = pg.image.load( "C:\\Users\\ti546\\Downloads\\pad.png") # 滑板圖片 self.image.convert() self.rect = self.image.get_rect() self.rect.x = int((screen.get_width() - self.rect.width)/2) # 滑板位置 self.rect.y = screen.get_height() - self.rect.height - 30 # 板子位置隨滑鼠移動 def update(self): pos = pg.mouse.get_pos() self.rect.x = pos[0] # 滑鼠x坐標 # 不要移出右邊界 if self.rect.x > screen.get_width() - self.rect.width: self.rect.x = screen.get_width() - self.rect.width # 結束程式 def gameover(message): global running # 顯示訊息 text = ffont.render(message, 1, (255, 0, 255)) screen.blit(text, (screen.get_width()/2-150, screen.get_height()/2-20)) pg.display.update() # 更新畫面 time.sleep(5) # 暫停5秒 running = False # 結束程式 pg.init() score = 0 # 得分 dfont = pg.font.SysFont("Arial", 20) # 下方訊息字體 ffont = pg.font.SysFont("SimHei", 32) # 結束程式訊息字體 # 背景 screen = pg.display.set_mode((600, 400)) pg.display.set_caption("Sean's Brick Game") background = pg.Surface(screen.get_size()) background = background.convert() background.fill((255, 255, 255)) allsprite = pg.sprite.Group() # 建立全部角色群組 bricks = pg.sprite.Group() # 建立磚塊角色群組 ball = Ball(15, 300, 350, 10, (255, 123, 188)) # 建立粉球 allsprite.add(ball) # 加入全部角色群組 pad = Pad() # 建立滑板球物件 allsprite.add(pad) # 加入全部角色群組 # 建立磚塊 for row in range(0, 5): # 5列方塊 for column in range(0, 15): # 每列15磚塊 if row == 1 or row == 0: brick = Brick((153, 205, 255), column * 40 + 1, row * 15 + 1) # 位置為40*15 if row == 2: brick = Brick((94, 175, 254), column * 40 + 1, row * 15 + 1) if row == 3 or row == 4: brick = Brick((52, 153, 207), column * 40 + 1, row * 15 + 1) bricks.add(brick) # 加入磚塊角色群組 allsprite.add(brick) # 加入全部角色群組 clock = pg.time.Clock() downmsg = "Press Left Click Button to start game!" # 起始訊息 playing = False # 開始時球不會移動 running = True # 運行的程式碼 while running: clock.tick(40) for event in pg.event.get(): if event.type == pg.QUIT: running = False buttons = pg.mouse.get_pressed() # 檢查滑鼠按鈕 if buttons[0]: # 按滑鼠左鍵後球可移動 playing = True # 遊戲進行中 if playing == True: screen.blit(background, (0, 0)) # 清除繪圖視窗 fail = ball.update() # 移動球體 if fail: # 球出界 gameover("You failed!See you next time~") pad.update() # 更新滑板位置 # 檢查球和磚塊碰撞 hitbrick = pg.sprite.spritecollide(ball, bricks, True) if len(hitbrick) > 0: # 球和磚塊發生碰撞 score += len(hitbrick) # 計算分數 ball.rect.y += 20 # 球向下移 ball.bounceup() # 球反彈 if len(bricks) == 0: # 所有磚塊消失 gameover("Congratulations!!") # 檢查球和滑板碰撞 hitpad = pg.sprite.collide_rect(ball, pad) if hitpad: # 球和滑板發生碰撞 ball.bounceup() # 球反彈 allsprite.draw(screen) # 繪製所有角色 downmsg = "Score: " + str(score) # 繪製下方訊息 message = dfont.render(downmsg, 1, (255, 0, 255)) screen.blit(message, (screen.get_width()/2-125, screen.get_height()-30)) pg.display.update() pg.quit() ```