# 資研 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()
```

#### 圓形
```python=
color = (0, 0, 0) # 黑色
x = 200
y = 200
r = 100
linewidth = 0 # 實心
pygame.draw.circle(background, color, (x, y), r, linewidth)
```

#### 橢圓形
```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)
```

#### 直線
```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)
```

#### 圓弧
```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)
```

#### 多邊形
```python=
color = (0, 0, 255) # 藍色
points = [(50, 300), (100, 100), (200, 250), (600, 300)]
linewidth = 0
pygame.draw.polygon(background, color, points, linewidth)
```

### 載入圖片
#### 載入圖片
```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()
```

### 顯示文字
#### 設定字型
```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()
```

### 動畫
#### 基礎架構
- <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()
```