# Python班 ## 5/31社課 --- ### 本次課程內容 * 簡易三角函數 * 建立多個相同物件 * 角色-群組碰撞 * 角色-角色碰撞 --- ## 前置作業 在今天的點名文字檔裡,有附上程式的半成品,請複製到replit上面。 ---- 半成品 ```= import pygame, sys from pygame.locals import QUIT pygame.init() FPS = 30 WIDTH, HEIGHT = 400, 300 global deltax, deltay v = 6 DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption('Hello World!') clock = pygame.time.Clock() class Block(pygame.sprite.Sprite): def __init__(self,x): super().__init__() self.image = pygame.Surface(((WIDTH - 50)/7, 40)) self.image.fill((0, 255, 0)) self.rect = self.image.get_rect() self.rect.x = x self.rect.bottom = 50 class Ball(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((30, 30)) self.image.fill((255,255,255)) pygame.draw.circle(self.image, (255,0,0), (15,15), 15) self.rect = self.image.get_rect() self.rect.centerx = WIDTH/2 self.rect.centery = HEIGHT/2 self.vx = 0 self.vy = 6 def update(self): self.rect.x += self.vx self.rect.y += self.vy if self.rect.left < 0 or self.rect.right > WIDTH: self.vx = -self.vx if self.rect.top < 0: self.vy = -self.vy class Player(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((70, 10)) self.image.fill((0,0,255)) self.rect = self.image.get_rect() self.rect.centerx = WIDTH/2 self.rect.bottom = 250 self.v = 8 def update(self): keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: self.rect.x -= self.v if keys[pygame.K_RIGHT]: self.rect.x += self.v all_sprite = pygame.sprite.Group() balls = pygame.sprite.Group() blocks = pygame.sprite.Group() ball = Ball() balls.add(ball) player = Player() all_sprite.add(ball) all_sprite.add(player) running = True while running: clock.tick(FPS) for event in pygame.event.get(): if event.type == QUIT: running = False sys.exit() all_sprite.update() DISPLAYSURF.fill((255,255,255)) all_sprite.draw(DISPLAYSURF) pygame.display.update() pygame.quit() ``` --- ### 反彈後的速度 --- #### 目標 我們預期的最終的結果 要像一般的打磚塊那樣 反彈方向由接觸點決定 ---- ### 開始囉 反彈與位置有關,因此碰撞時得確認兩者的位置 所以先寫出一個判斷碰撞與否的程式 然後計算兩者位置之差,以便計算反彈後速度 ```python= ... all_sprite.update() if pygame.sprite.collide_rect(ball, player): deltax = ball.rect.centerx - player.rect.centerx deltay = ball.rect.centery - player.rect.centery ball.col() ``` ---- 有個$\texttt{ball.col()}$要幹嘛咧? 就是去計算反彈後的速度 ---- 我們希望速度是定值,只有方向上的改變 因此我們用到一些簡單的三角函數概念 我們來到$\texttt{ball}$底下,定義$\texttt{col}$ ```= def col(self): self.vx = v*(deltax/((deltax**2+deltay**2)**0.5)) self.vy = v*(deltay/((deltax**2+deltay**2)**0.5)) ``` --- ## 打方塊 ---- 已經幫你們定義好了$\texttt{block}$ 仔細看,在$\texttt{__init__}$的括弧中,除了$\texttt{self}$之外還有一個$\texttt{x}$,這是用來定義生成時的位置的。 ```= class Block(pygame.sprite.Sprite): def __init__(self,x): super().__init__() self.image = pygame.Surface(((WIDTH - 50)/7, 40)) self.image.fill((0, 255, 0)) self.rect = self.image.get_rect() self.rect.x = x self.rect.bottom = 50 ``` ---- 接著開始建立方塊 ---- 首先,如果這些方塊生來就是要被打掉,不在意誰是誰的話,我們可以用一個$\texttt{for}$迴圈大量製造 ```= for i in range(7): block = Block(i*(WIDTH/7)) blocks.add(block) all_sprite.add(block) ``` 這裡之所以多開一個$\texttt{blocks}$是為了等等的判斷 ---- 來到遊戲進行區,我們要來讓球碰到方塊 ```= hit = pygame.sprite.spritecollide(ball, blocks, True) if hit: ball.hit() ``` 這裡用的是角色-群組碰撞,凡涉及「群組」的碰撞,通常代表不確定碰撞者是誰,所以可以在後面設定布林值來決定碰撞後是否刪除屬於群組的物件 這裡因為方塊要刪掉所以用$\texttt{True}$ ---- 最後是打到磚塊的反彈 因為我們是極簡版,只有一層磚塊, 所以判斷上比較簡單 我們需要判斷是從側面撞擊還是正面撞擊 ---- 我們可以在判斷前往回推一步,看看碰撞前一刻球在哪裡 ``` def hit(self): self.rect.x -= self.vx self.rect.y -= self.vy ... ``` ---- 接著就可以用碰撞前的位置判斷是碰到左右邊還是下邊 ```= def hit(self): self.rect.x -= self.vx self.rect.y -= self.vy if self.rect.top >= 50: self.vy = -self.vy else: self.vx = -self.vx ``` --- # 完成啦 --- # 謝謝大家
{"title":"112-2-Pygame-極簡版打磚塊實作","contributors":"[{\"id\":\"084e105f-92be-4605-b399-8d3c0ef40c64\",\"add\":6170,\"del\":2186}]","description":"簡易三角函數"}
    16 views