0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【pygame】スクラッチくじの削る部分を作ってみた!

Posted at

image.png

はじめに

 ゲームでよくあるスクラッチくじを作ってみたので、その解説をしていきます。タイトルの通り削る部分を作っただけなので、演出などは各自で付け足してください。

実装方針

  • 削るための層(上)
  • 背景となるマークや文字を表示する層(下)

まず上記の二つの層を作り、上のレイヤーを削ることで隠されていた部分が徐々に見えるようにします。

事前知識

 肝心の「削る」というのが、pygame上では、どの操作に対応するか先に説明しておきます。

 pygameでSurfaceに対して書換を行う方法としてblitdrawがありますが、今回はdrawを用います。不透明な図形を扱う分には違いが分かりずらいのですが、drawblitと違い、指定した色で指定した領域の画像情報を上書きするので(ざっくり)、無色透明で上書きすれば、削ったりくりぬいたりできるという理屈です。

image.png

↑元となるSurfaceに対して半透明の四角をdrawした場合(左)とblitした場合(右)

コード解説

import pygame, sys, random
pygame.init()

WIDTH, HEIGHT = 600, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("スクラッチくじ")
clock = pygame.time.Clock()
font = pygame.font.SysFont('MS Gothic', 54)

# 背景用サーフェス
background = pygame.Surface((WIDTH, HEIGHT))
background.fill((80, 112, 255))

# 透明度付きのマスクサーフェス
mask_surface = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)

class ScratchArea:
    def __init__(self, rect):
        self.rect = rect
        result = random.choice(['あたり', 'はずれ'])
        self.text = font.render(result, True, (255, 0, 0))

        # 文字の表示位置を計算
        x, y, w, h = self.rect
        tw, th = self.text.get_size()
        tx = x + (w - tw)//2
        ty = y + (h - th)//2
        self.text_pos = (tx, ty)

        self.draw()

        # 初期不透明ピクセル数を取得
        init_mask = pygame.mask.from_surface(
            mask_surface.subsurface(self.rect), threshold=1
        )
        self.initial_count = init_mask.count()

    def update(self):
        # 現在の不透明ピクセル数を再取得
        current_mask = pygame.mask.from_surface(
            mask_surface.subsurface(self.rect), threshold=1
        )
        current_count = current_mask.count()

        # 不透明ピクセル数の差分から削った割合を計算
        scratched = self.initial_count - current_count
        scratched_percent = scratched / self.initial_count * 100

        # 一定割合以上削れた時の処理
        if scratched_percent >= 75:
            pygame.draw.ellipse(mask_surface, (0, 0, 0, 0), self.rect)


    def draw(self):
        x, y, w, h = self.rect
        pygame.draw.ellipse(background, (255, 255, 255, 255), self.rect)
        pygame.draw.ellipse(background, (255, 255, 0, 255), (x-5, y-5, w+10, h+10), 6)

        background.blit(self.text, self.text_pos)

        pygame.draw.ellipse(mask_surface, (192, 192, 192, 255), self.rect)

scratch_area = ScratchArea((300, 100, 200, 200))

# マウスドラッグの軌跡(線分リスト)
drawing = False
path = []

def main():
    global drawing, path

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

            # 左クリック押したら描画開始
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                drawing = True
                path = [list(event.pos)]

            # 左クリック離したら描画終了
            elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
                drawing = False
                path = []

            # ドラッグ中は軌跡を追加
            elif event.type == pygame.MOUSEMOTION and drawing:
                path.append(list(event.pos))

        # 軌跡に沿ってマスクを透明化
        for i in range(len(path) - 1):
            pygame.draw.line(mask_surface, (0, 0, 0, 0), path[i], path[i+1], 10) 

        scratch_area.update()
        screen.blit(background, (0, 0))  # 背景
        screen.blit(mask_surface, (0, 0))  # マスクを描画
        pygame.display.update()
        clock.tick(60)

if __name__ == '__main__':
    main()

コードの各部分の役割はコメントを確認していただければと思います。全体としては、マウスでドラッグされている間の軌道を記録しておき、その軌道上に無色透明な線をdrawすることで、スクラッチ部分を削り取る構成になっています。

また、ある程度削り終わった時、綺麗に削り取る処理を追加するために、不透明なピクセルの割合を出す処理も実装しています。この部分は毎ループ呼び出す必要があります。削り終わったかどうか返すようにしておけば、ゲームループ側で受け取って、当たりの演出を付け加えるなども可能です。

まとめ

画像をくりぬきたい時は、無色透明な図形をdrawしよう

最後に

 ここまで読んで下さりありがとうございました。今回は簡単な図形や塗りつぶししか使っていませんが、当然Surfaceであれば削ったりくりぬいたりできるので、用意した画像次第ではかなり本格的なものが作れる想定です。ぜひ自作ゲームの1要素として組み込んでみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?