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

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

 

下記の本の「3Dブロック崩しのサンプル」にボールの数やブロックのHPを増やして難易度が高くなるように改造しました。

 

■ プログラム

import traceback
 
try:
    import sys
    import random
    from math import sin, cos, floor, radians
    import pygame
    from pygame.locals import QUIT, K_LEFT, K_RIGHT, KEYDOWN

    #----------------------------------------------------------------------
    # Pygame初期設定
    #----------------------------------------------------------------------
    pygame.init()
    pygame.key.set_repeat(5, 5)
    SURFACE = pygame.display.set_mode([600, 600])
    FPSCLOCK = pygame.time.Clock()

    #----------------------------------------------------------------------
    # 3Dオブジェクトクラス
    #----------------------------------------------------------------------
    class Cube:

        SPEED = 5
        THETA = 270 + floor(random.randint(-10, 10))
        HP = 10

        """ Cube for blocks and paddle """
        polygons = [
            [2, 1, 5, 6], [0, 1, 2, 3], [4, 5, 1, 0],
            [2, 6, 7, 3], [7, 6, 5, 4], [0, 3, 7, 4]
        ]

        def __init__(self, x, y, z, w, h, d, color):
            self.xpos = x
            self.ypos = y
            self.width = w
            self.height = h
            self.color = color
            self.pos = []
            self.vertices = [
                {"x": x - w, "y": y - h, "z": z + d},
                {"x": x - w, "y": y + h, "z": z + d},
                {"x": x + w, "y": y + h, "z": z + d},
                {"x": x + w, "y": y - h, "z": z + d},
                {"x": x - w, "y": y - h, "z": z - d},
                {"x": x - w, "y": y + h, "z": z - d},
                {"x": x + w, "y": y + h, "z": z - d},
                {"x": x + w, "y": y - h, "z": z - d},
            ]

        def set_camera(self, rad_x, rad_y):
            "update vertice positions depending on camera location"
            self.pos.clear()
            for vert in self.vertices:
                p0x = vert["x"]
                p0y = vert["y"]
                p0z = vert["z"]

                # rotate around X axis
                p1x = p0x
                p1y = p0y * cos(rad_x) - p0z * sin(rad_x)
                p1z = p0y * sin(rad_x) + p0z * cos(rad_x)

                # rotate around Y axis
                p2x = p1x * cos(rad_y) + p1z * sin(rad_y)
                p2y = p1y
                p2z = -p1x * sin(rad_y) + p1z * cos(rad_y)

                self.pos.append({"x": p2x, "y": p2y, "z": p2z})

        def ishit(self, xpos, ypos):
            "return if (x,y) hits the block"
            return self.xpos-self.width < xpos < self.xpos+self.width \
                and self.ypos-self.height < ypos < self.ypos+self.height

        def translate(self, diffx, diffy):
            "move the block"
            self.xpos += diffx
            self.ypos += diffy
            for vert in self.vertices:
                vert["x"] += diffx
                vert["y"] += diffy

    #----------------------------------------------------------------------
    # 移動、衝突処理
    #----------------------------------------------------------------------
    def tick():
        """ called periodically from the main loop """
        global SPEED, THETA, BLOCKS, MESSAGE, BALLS
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == KEYDOWN:
                if event.key == K_LEFT:
                    PADDLE.translate(-10, 0)
                elif event.key == K_RIGHT:
                    PADDLE.translate(+10, 0)

        if not MESSAGE is None:
            return

        # move the ball
        for BALL in BALLS:

            for block in BLOCKS:
                if block.ishit(BALL.xpos, BALL.ypos) and not block == PADDLE:
                    block.HP -= 1
                    BALL.THETA = -BALL.THETA

            diffx = cos(radians(BALL.THETA)) * BALL.SPEED
            diffy = sin(radians(BALL.THETA)) * BALL.SPEED
            BALL.translate(diffx, diffy)

            # hit any blocks?
            count = len(BLOCKS)
            BLOCKS = [x for x in BLOCKS if x == PADDLE or x.HP>0 or not x.ishit(BALL.xpos, BALL.ypos)]

            if len(BLOCKS) != count:
                BALL.THETA = -BALL.THETA

            # hit ceiling, wall or paddle?
            if BALL.ypos > 800:
                BALL.THETA = -BALL.THETA
                SPEED = 10
            if BALL.xpos < -250 or BALL.xpos > 250:
                BALL.THETA = 180 - BALL.THETA
            if PADDLE.ishit(BALL.xpos, BALL.ypos):
                BALL.THETA = 90 + ((PADDLE.xpos - BALL.xpos) / PADDLE.width) * 80
            BALLS = [x for x in BALLS if not x.ypos < -600]
            if len(BALLS) == 0:
                MESSAGE = MESS1
            if len(BLOCKS) == 2:
                MESSAGE = MESS0

            # Rotate the Cube
            rad_y = PADDLE.xpos / 1000
            rad_x = 0.5 + BALL.ypos / 2000

            BALL.set_camera(0.5, rad_y)

        for block in BLOCKS:
            block.set_camera(0.5, rad_y)

    def paint():
        "update the screen"
        SURFACE.fill((0, 0, 0))

        # Paint polygons
        for block in BLOCKS:
            for indices in block.polygons:
                poly = []
                for index in indices:
                    pos = block.pos[index]
                    zpos = pos["z"] + 500
                    xpos = pos["x"] * 500 / zpos + 300
                    ypos = -pos["y"] * 500 / zpos + 500
                    poly.append((xpos, ypos))
                pygame.draw.lines(SURFACE, block.color, True, poly)

        # Paint balls
        for BALL in BALLS:
            for indices in BALL.polygons:
                poly = []
                for index in indices:
                    pos = BALL.pos[index]
                    zpos = pos["z"] + 500
                    xpos = pos["x"] * 500 / zpos + 300
                    ypos = -pos["y"] * 500 / zpos + 500
                    poly.append((xpos, ypos))
                pygame.draw.lines(SURFACE, BALL.color, True, poly)

        if not MESSAGE is None:
            SURFACE.blit(MESSAGE, (150, 400))
        pygame.display.update()

    FPS = 60
    BLOCKS = []
    BALLS = [Cube(random.randint(-200, 200), random.randint(200, 300), 0, 5, 5, 5, (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))) for i in range(20)]
    PADDLE = Cube(0, 0, 0, 100, 10, 5, (255, 255, 255))
    MESSAGE = None
    MYFONT = pygame.font.SysFont(None, 80)
    MESS0 = MYFONT.render("Cleared!!!", True, (255, 255, 0))
    MESS1 = MYFONT.render("Game Over!", True, (255, 255, 0))

    #----------------------------------------------------------------------
    # メインルーチン
    #----------------------------------------------------------------------
    def main():
        """ main routine """
        colors = [(255, 0, 0), (255, 165, 0), (242, 242, 0),
                  (0, 128, 0), (128, 0, 128), (0, 0, 250)]

        for ypos in range(0, len(colors)):
            for xpos in range(-3, 4):
                block = Cube(xpos * 70, ypos * 50 + 450, 0, 30, 10, 5, colors[ypos])
                BLOCKS.append(block)

        BLOCKS.append(PADDLE)

        #----------------------------------------------------------------------
        # 毎フレーム処理
        #----------------------------------------------------------------------
        while True:
            tick()
            #----------------------------------------------------------------------
            # 描画処理
            #----------------------------------------------------------------------
            paint()
            FPSCLOCK.tick(FPS)

    if __name__ == '__main__':
        main()

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

input()

 

■ 参考書

「Pythonゲームプログラミング 知っておきたい数学と物理の基本 (Future Coders(NextPublishing))」

 

■ ゲーム用ライブラリ

「Pygame」

 

■ プログラミング言語

「Python」