プログラミング言語「Python」で制作 Part73 | Photoshop CC Tutorials

今回はプログラミング言語の「Python」を使って作成しました。

 

インベーダーゲームです。敵と防御壁が接触すると壊れるようにしました。

 

■ プログラム

import traceback
 
try:
    import sys
    from random import randint
    import pygame
    from pygame.locals import Rect, QUIT, KEYDOWN, \
        K_LEFT, K_RIGHT, K_SPACE

    #-----------------------------------------------------------
    # グローバル変数
    #-----------------------------------------------------------
    # Pygame初期設定
    pygame.init()
    pygame.key.set_repeat(5, 5)
    SURFACE = pygame.display.set_mode((600, 600))
    FPSCLOCK = pygame.time.Clock()

    BLOCKS = []

    #-----------------------------------------------------------
    # スーパークラス定義
    #-----------------------------------------------------------
    class Drawable:
        """ 全ての描画オブジェクトのスーパークラス """
        def __init__(self, rect, offset0, offset1):
            strip = pygame.image.load("strip.png")
            self.images = (pygame.Surface((24, 24), pygame.SRCALPHA),
                           pygame.Surface((24, 24), pygame.SRCALPHA))
            self.rect = rect
            self.count = 0
            self.images[0].blit(strip, (0, 0),
                                Rect(offset0, 0, 24, 24))
            self.images[1].blit(strip, (0, 0),
                                Rect(offset1, 0, 24, 24))

        def move(self, diff_x, diff_y):
            """ オブジェクトを移動 """
            self.count += 1
            self.rect.move_ip(diff_x, diff_y)

        def draw(self):
            """ オブジェクトを描画 """
            image = self.images[0] if self.count % 2 == 0 \
                    else self.images[1]
            SURFACE.blit(image, self.rect.topleft)

    #-----------------------------------------------------------
    # サブクラス定義
    #-----------------------------------------------------------
    class Block:
        """ ブロックオブジェクト """
        def __init__(self, col, rect):
            self.col = col
            self.rect = rect
            self.blockHP = 5
            self.visibleFlag = True

        def draw(self):
            """ ブロックを描画する """
            pygame.draw.rect(SURFACE, self.col, self.rect)

    class Ship(Drawable):
        """ 自機オブジェクト """
        def __init__(self):
            super().__init__(Rect(300, 550, 24, 24), 192, 192)

    class Beam(Drawable):
        """ ビームオブジェクト """
        def __init__(self):
            super().__init__(Rect(300, 0, 24, 24), 0, 24)

    class Bomb(Drawable):
        """ 爆弾オブジェクト """
        def __init__(self):
            super().__init__(Rect(300, -50, 24, 24), 48, 72)
            self.time = randint(5, 220)

    class Alien(Drawable):
        """ エイリアンオブジェクト """
        def __init__(self, rect, offset, score):
            super().__init__(rect, offset, offset+24)
            self.score = score
            self.HP = 3

    #-----------------------------------------------------------
    # メインルーチン
    #-----------------------------------------------------------
    def main():
        global BLOCKS

        sysfont = pygame.font.SysFont(None, 72)
        scorefont = pygame.font.SysFont(None, 36)
        message_clear = sysfont.render("!!CLEARED!!",
                                       True, (0, 255, 225))
        message_over = sysfont.render("GAME OVER!!",
                                      True, (0, 255, 225))
        message_rect = message_clear.get_rect()
        message_rect.center = (300, 300)
        game_over = False
        moving_left = True
        moving_down = False
        move_interval = 20
        counter = 0
        score = 0
        aliens = []
        bombs = []

        #-----------------------------------------------------------
        # インスタンス生成
        #-----------------------------------------------------------
        ship = Ship()
        beam = Beam()

        # ブロック生成
        colors = [(255, 0, 0), (255, 0, 0), (255, 0, 0),
                  (255, 0, 0), (255, 0, 0), (255, 0, 0)]

        for ypos, color in enumerate(colors):
            for xpos in range(0, 5):
                BLOCKS.append(Block(color,
                                    Rect(xpos * 100 + 75, ypos * 10 + 350, 50, 10)))

        # エイリアンの並びを初期化
        for ypos in range(6):
            offset = 96 if ypos < 2 else 144
            for xpos in range(10):
                rect = Rect(100+xpos*50, ypos*50 + 50, 24, 24)
                alien = Alien(rect, offset, (4-ypos)*10)
                aliens.append(alien)

        # 爆弾を設定
        for _ in range(8):
            bombs.append(Bomb())

        #----------------------------------------------------------------------------------
        # ループ処理
        #----------------------------------------------------------------------------------
        while True:
            ship_move_x = 0
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == KEYDOWN:
                    if event.key == K_LEFT:
                        ship_move_x = -5
                    elif event.key == K_RIGHT:
                        ship_move_x = +5
                    elif event.key == K_SPACE and beam.rect.bottom < 0:
                        beam.rect.center = ship.rect.center

            if not game_over:
                counter += 1

            #-----------------------------------------------------------
            # 移動処理
            #-----------------------------------------------------------
            # 自機を移動
            ship.move(ship_move_x, 0)

            # ビームを移動
            beam.move(0, -10)

            # エイリアンを移動
            area = aliens[0].rect.copy()
            for alien in aliens:
                area.union_ip(alien.rect)

            if counter % move_interval == 0:
                move_x = -5 if moving_left else 5
                move_y = 0

                if (area.left < 10 or area.right > 590) and \
                    not moving_down:
                    moving_left = not moving_left
                    move_x, move_y = 0, 24
                    move_interval = max(1, move_interval - 2)
                    moving_down = True
                else:
                    moving_down = False

                for alien in aliens:
                    alien.move(move_x, move_y)

            if area.bottom > 550:
                game_over = True

            # 爆弾を移動
            HitFlag = False # bombとblockの当たり判定用フラグ
            for bomb in bombs:
                if bomb.time < counter and bomb.rect.top < 0:
                    enemy = aliens[randint(0, len(aliens) - 1)]
                    bomb.rect.center = enemy.rect.center

                if bomb.rect.top > 0:
                    bomb.move(0, 10)

                for x in BLOCKS:
                    if x.rect.colliderect(bomb.rect):
                        x.blockHP -= 1
                        HitFlag = True
                    if x.blockHP < 1:
                        x.visibleFlag = False

                BLOCKS = [x for x in BLOCKS if x.visibleFlag]
                #BLOCKS = [x for x in BLOCKS if not x.rect.colliderect(bomb.rect)]

                if bomb.rect.top > 600 or HitFlag == True:
                    bomb.time += randint(50, 250)
                    bomb.rect.top = -50
                    HitFlag = False

                if bomb.rect.colliderect(ship.rect):
                    game_over = True

            #-----------------------------------------------------------
            # 衝突処理
            #-----------------------------------------------------------
            # ビームがブロックと衝突
            for x in BLOCKS:
                if x.rect.colliderect(beam.rect):
                    x.blockHP -= 1
                    beam.rect.top = -50

                if x.blockHP < 1:
                    x.visibleFlag = False
                        
            BLOCKS = [x for x in BLOCKS if x.visibleFlag]
            #BLOCKS = [x for x in BLOCKS if not x.rect.colliderect(beam.rect) or x.blockHP < 0]

            # ビームがエイリアンと衝突?
            tmp = []
            for alien in aliens:
                # エイリアンとブロックが衝突
                for block in BLOCKS:
                    if alien.rect.colliderect(block.rect):
                        BLOCKS = [x for x in BLOCKS if not x.rect.colliderect(block.rect)]
                if alien.rect.collidepoint(beam.rect.center):
                    beam.rect.top = -50
                    score += alien.score
                else:
                    tmp.append(alien)
            aliens = tmp
            if len(aliens) == 0:
                game_over = True
            
            #-----------------------------------------------------------
            # 描画処理
            #-----------------------------------------------------------
            # 描画
            SURFACE.fill((0, 0, 0))
            for alien in aliens:
                alien.draw()
            ship.draw()
            beam.draw()
            for bomb in bombs:
                bomb.draw()
            
            for block in BLOCKS:
                block.draw()

            score_str = str(score).zfill(5)
            score_image = scorefont.render(score_str,
                                           True, (0, 255, 0))
            SURFACE.blit(score_image, (500, 10))

            if game_over:
                if len(aliens) == 0:
                    SURFACE.blit(message_clear, message_rect.topleft)
                else:
                    SURFACE.blit(message_over, message_rect.topleft)

            pygame.display.update()
            FPSCLOCK.tick(30)
    
    #-----------------------------------------------------------
    # エントリポイント
    #-----------------------------------------------------------
    if __name__ == '__main__':
        main()

except Exception as e:
    # 文字列を取得する format_exec()メソッド
    print("エラー情報\n" + traceback.format_exc())

input()

 

■ 参考書

「ゲームを作りながら楽しく学べるPythonプログラミング (Future Coders(NextPublishing))」

 

■ ゲーム用ライブラリ

「Pygame」

 

■ プログラミング言語