pythonでブロック崩し

pygame

事前準備

今回はwindows環境でwindows版pythonをインストールしています。

pythonにはAnaconda版もあります。使用目的によって使い分けます。

pythonの公式リンクを参考にしてください。

そしてpythonでゲームをするにはpygameをインストールします。

コマンドプロントを開いて、

python3 -m pip install pygame

でインストールできます。

素材の準備

今回ブロック崩しを制作するにあたり、こちらの記事を参考にさせていただきました。

ブロックやボールなどの素材は、windows標準のペイントやペイント3Dを使用して作っています。

ダウンロード

ゲームの反響音などは、プログラミングで有名なScratchを使用しました。

こちらの記事を参考にしてください。

ダウンロード

ゲームのバックミュージックも無料で自作しました。

BandLabというアプリを使用しています。

ダウンロード

まずは結果をご覧ください

プログラムや素材の保存場所

プログラムを実行するには、プログラム内で素材の場所などにパスを通す必要があります。

プログラムと素材を同じフォルダーに入れます。

今回はデスクトップにblocksというフォルダーを作りました。

こんな感じです。

このフォルダー内で右クリックし、「ターミナルで開く」を選択。

python block.py

を実行します。

プログラムの名前は何でもいいのですが、pythonは最後に、.pyをつけてください。

実際のプログラム

156行目以下の(r”C:\Users\\Desktop\blocks\hit1.○○○○”)ですが、

先ほど素材やプログラムを格納したフォルダを右クリックして、

パスのコピーをすると簡単です。

それを()内に貼り付けるのですが、先頭にrをつけて””でパスを囲むのを忘れずに。

そして実際には(r”C:\Users\あなたのユーザー名\Desktop\blocks\hit1.wav”)

のようになります。

あとはコピペでも動くと思うのですが・・・

block.py

#coding: utf-8
import pygame
from pygame.locals import *
import math
import sys
import pygame.mixer

# 画面サイズ
GAMEN = Rect(0, 0, 760, 800)# スコアを上部に入れるため、縦を長くした
pygame.display.set_caption("俺のブロック崩し")# pygame左上のタイトル

# パドルのクラス
class Paddle(pygame.sprite.Sprite):
    # コンストラクタ(初期化メソッド)
    def __init__(self, filename):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = pygame.image.load(filename).convert()
        # 画像サイズをrectで取得する rect.bottom位置の設定
        self.rect = self.image.get_rect()
        self.rect.bottom = GAMEN.bottom -20    # パドルyの座標

    def update(self):
        # マウス操作で移動するように設定
        self.rect.centerx = pygame.mouse.get_pos()[0]# マウスのx座標をパドルのx座標に
        self.rect.clamp_ip(GAMEN)                    # ゲーム内のみで移動

# ボールのクラス
class Ball(pygame.sprite.Sprite):
    # コンストラクタ(初期化メソッド)
    def __init__(self, filename, paddle, blocks, score, speed, angle_left, angle_right):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = pygame.image.load(filename).convert()
        self.rect = self.image.get_rect()
        self.dx = self.dy = 0                     # ボールの速度 
        self.paddle = paddle                      # パドルへの参照
        self.blocks = blocks                      # ブロックグループへの参照
        self.update = self.start                  # ゲーム開始状態に更新
        self.score = score
        self.hit = 0                              # 連続でブロックを壊した回数
        self.speed = speed                        # ボールの初期速度
        self.angle_left = angle_left              # パドルの反射方向(左端135度)
        self.angle_right = angle_right            # パドルの反射方向(右端45度)

    # ゲーム開始状態(マウスを左クリックで、ボールを射出)
    def start(self):
        # ボールの初期位置(パドルの上)
        self.rect.centerx = self.paddle.rect.centerx
        self.rect.bottom = self.paddle.rect.top

        # 左クリックでボール射出
        if pygame.mouse.get_pressed()[0] == 1:
            self.dx = 0
            self.dy = -self.speed
            self.update = self.move
            
    # ボールの挙動
    def move(self):
        self.rect.centerx += self.dx
        self.rect.centery += self.dy

        # 壁との反射
        if self.rect.left < GAMEN.left:             # 左側
            self.rect.left = GAMEN.left
            self.dx = -self.dx                      # 速度を反転
            self.kabe_sound.play()                  # 壁の反射音

        if self.rect.right > GAMEN.right:           # 右側
            self.rect.right = GAMEN.right
            self.dx = -self.dx                      # 速度を反転
            self.kabe_sound.play()                  # 壁の反射音

        if self.rect.top < GAMEN.top:               # 上側
            self.rect.top = GAMEN.top
            self.dy = -self.dy                      # 速度を反転
            self.kabe_sound.play()                  # 壁の反射音

        # パドルとの反射(左端:135度方向, 右端:45度方向, それ以外:線形補間)
        # 2つのspriteが接触しているかどうかの判定
        if self.rect.colliderect(self.paddle.rect) and self.dy > 0:
            self.hit = 0   # 連続ヒットを0に戻す。
            (x1, y1) = (self.paddle.rect.left - self.rect.width, self.angle_left)
            (x2, y2) = (self.paddle.rect.right, self.angle_right)
            x = self.rect.left  # ボールが当たった位置
            y = (float(y2-y1)/(x2-x1)) * (x - x1) + y1  # 線形補間
            angle = math.radians(y)                     # 反射角度
            self.dx = self.speed * math.cos(angle)
            self.dy = -self.speed * math.sin(angle)
            self.paddle_sound.play()  # 反射音
       
        # ボールを落とした場合
        if self.rect.top > GAMEN.bottom:
                self.update = self.start   # ボールを初期状態に
                self.shippai_sound.play()
                self.hit = 0
                self.score.add_score(-100)  # スコア原点(-100)

        # ボールと衝突したブロックリストを取得
        # (Groupが格納しているSpriteの中から、
        # 指定したSpriteと接触しているものを探索)
        blocks_collided = pygame.sprite.spritecollide(self, self.blocks, True)
        if blocks_collided:        # 衝突ブロックがある場合
            oldrect = self.rect
            for block in blocks_collided:
                # ボールが左から衝突
                if oldrect.left < block.rect.left < oldrect.right < block.rect.right:
                    self.rect.right = block.rect.left
                    self.dx = -self.dx
                # ボールが右から衝突
                if block.rect.left < oldrect.left < block.rect.right < oldrect.right:
                    self.rect.left = block.rect.right
                    self.dx = -self.dx
                # ボールが上から衝突
                if oldrect.top < block.rect.top < oldrect.bottom < block.rect.bottom:
                    self.rect.bottom = block.rect.top
                    self.dy = -self.dy
                # ボールが下から衝突
                if block.rect.top < oldrect.top < block.rect.bottom < oldrect.bottom:
                    self.rect.top = block.rect.bottom
                    self.dy = -self.dy
                self.block_sound.play()
                self.hit += 1                        # 衝突回数
                self.score.add_score(self.hit * 10)  # 衝突回数に応じてスコア加点

# ブロックのクラス
class Block(pygame.sprite.Sprite):
    def __init__(self, filename, x,y):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = pygame.image.load(filename).convert()
        self.rect = self.image.get_rect()
        self.rect.left = GAMEN.top + x * self.rect.width
        # スコア表示のためブロックを20下げる
        self.rect.top = GAMEN.top + 20 + y * self.rect.height 

# スコアのクラス
class Score():
    def __init__(self, x, y):
        # スコアのフォントサイズは40
        self.sysfont = pygame.font.SysFont(None, 40)# スコアのフォントサイズは40
        self.score = 0
        (self.x, self.y) = (x, y)
    def draw(self, screen):
        # 黄色の文字
        img = self.sysfont.render("SCORE:"+str(self.score), True, (255,255,0)) 
        screen.blit(img, (self.x, self.y))
    def add_score(self, x):
        self.score += x

def main():
    pygame.init()
    screen = pygame.display.set_mode(GAMEN.size)
    # Mixerを初期化(サンプリング周波数を設定)
    pygame.mixer.init(frequency = 44100)
    # バックグラウンドミュージックのボリューム設定
    pygame.mixer.music.set_volume(0.6) 
    # パドルにボールが衝突した時の効果音取得
    Ball.paddle_sound = pygame.mixer.Sound(r"C:\Users\\Desktop\blocks\hit1.wav")
    # ブロックにボールが衝突した時の効果音取得
    Ball.block_sound = pygame.mixer.Sound(r"C:\Users\\Desktop\blocks\hit2.wav")    
    # ボールを落とした時の効果音取得
    Ball.shippai_sound = pygame.mixer.Sound(r"C:\Users\\Desktop\blocks\shippai.wav")
    # 壁に当たった時の効果音取得
    Ball.kabe_sound = pygame.mixer.Sound(r"C:\Users\\Desktop\blocks\kabe.wav")  
    # 画像用のスプライトグループ
    group = pygame.sprite.RenderUpdates()

    # 衝突判定用のスプライトグループ
    blocks = pygame.sprite.Group()

    # スプライトグループに追加                   
    Paddle.containers = group
    Ball.containers = group
    Block.containers = group, blocks

    # パドルの作成
    paddle = Paddle(r"C:\Users\\Desktop\blocks\paddle.png")

    # ブロックの作成(14*10)
    for x in range(1, 15):
        for y in range(1, 11):
            Block(r"C:\Users\\Desktop\blocks\block.png", x, y)

     # スコア画面(10, 10)表示
    score = Score(10, 10)                           
    # ボールを作成
    Ball(r"C:\Users\\Desktop\blocks\ball.png", paddle, blocks, score, 5, 135, 45)

    clock = pygame.time.Clock()

    while (1):
        clock.tick(60)               # フレームレート(60fps)
        screen.fill((0,20,0))
        # すべてのスプライトグループを更新
        group.update()
        # すべてのスプライトグループを描画
        group.draw(screen)
        # スコアを描画
        score.draw(screen)
        # 描画処理を実行                           
        pygame.display.update()

        # キーイベント(終了)
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
            # マウスボタンクリックでバックグラウンドミュージック開始
            if event.type == pygame.MOUSEBUTTONDOWN:
                pygame.mixer.music.load(r"C:\Users\\Desktop\blocks\gameongaku.wav")
                pygame.mixer.music.play(-1)
            if len(blocks) == 0:
                pygame.mixer.music.stop()
                continue

if __name__ == "__main__":
    main()

うまくいったらうれしいです。

コメント

タイトルとURLをコピーしました