砂漠シューティングゲーム(pygame)

スポンサーリンク

windowsのpcにpythonが入っていたらそれで実行できるか試してみてください。駄目だったら今windowsのpcに入ってるpythonをアンインストールしてpython3.6.1をインストールするか、仮想環境にpython3.6.1を入れて実行するかしてみてください。(仮想環境で成功していないのでできるかわかりません。)
(Macなどのpythonが元から入っているpcはそのpythonで実行してみて、駄目だったら仮想環境にpython3.6.1を入れて実行してみてください。)
cmd.exeを開いて

pip install pygame==1.9.4

でバージョン1.9.4のpygameを入れます。
(アンインストールする時は

pip uninstall pygame==1.9.4

でEnterを押します。)

ゲームのコードは人工知能に関する断創録さんのほとんどを借用させていただきました。pcのpythonがpython2の人はこちらの方で実行できると思います。以下のコードをUTF-8で保存して、そのpyファイルがあるフォルダと同じ所に画像、音声ファイルを入れたdataフォルダを置きます。そしてpyファイルをダブルクリックして実行するとゲームを始められると思います。やめる時はpygameの画面の右上の×をクリックします。キーボードの←→↑↓で自機を動かし、スペースキーでミサイルを発射します。クリアとかはないですが敵がすべて消えたら終わりです。

#coding: utf-8
import pygame
from pygame.locals import *
import os
import random
import sys
SCR_RECT = Rect(0, 0, 640, 640)
def main():
    pygame.init()
    screen = pygame.display.set_mode(SCR_RECT.size)
    pygame.display.set_caption("Invader 05 エイリアンの反撃")
    # サウンドのロード
    Alien.randomize_sound = load_sound("randomize.wav")
    Player.shoot_sound = load_sound("shoot.wav")
    Player.explosion_sound = load_sound("explosion.wav")
    # スプライトグループを作成して登録
    all = pygame.sprite.RenderUpdates()
    aliens = pygame.sprite.Group()  # エイリアングループ
    shots = pygame.sprite.Group()   # ミサイルグループ
    beams = pygame.sprite.Group()   # ビームグループ
    Player.containers = all
    Shot.containers = all, shots
    Alien.containers = all, aliens
    Beam.containers = all, beams
    # スプライトの画像を登録
    Back_image = load_image("desert.png")
    back_rect = Back_image.get_rect()
    Player.image = load_image("probe.png")
    Shot.image = load_image("missile.png")
    Alien.images = split_image(load_image("ufo.png"), 2)
    Beam.image = load_image("ball.png")
    # 自機を作成
    player = Player()
    # エイリアンを作成
    for i in range(0, 50):
        x = 20 + (i % 10) * 40
#        y = 20 + (i / 10) * 40
        y = 20 + (i - 25) * (i - 25) / 3
        Alien((x,y))
    
    clock = pygame.time.Clock()
    while True:
        clock.tick(60)
        all.update()
        # ミサイルとエイリアンの衝突判定
        collision_detection(player, aliens, shots, beams)
        all.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()
        screen.blit(Back_image, back_rect)

def collision_detection(player, aliens, shots, beams):
    """衝突判定"""
    # エイリアンとミサイルの衝突判定
    alien_collided = pygame.sprite.groupcollide(aliens, shots, True, True)
    for alien in list(alien_collided.keys()):
        Alien.randomize_sound.play()
    # プレイヤーとビームの衝突判定
    beam_collided = pygame.sprite.spritecollide(player, beams, True)
    if beam_collided:  # プレイヤーと衝突したビームがあれば
        Player.explosion_sound.play()
        # TODO: ゲームオーバー処理
    # ビームとミサイルの衝突判定
    beam_collided = pygame.sprite.groupcollide(beams, shots, True, True)
    for beam in list(alien_collided.keys()):
        beam.randomize_sound.play()

class Player(pygame.sprite.Sprite):
    """自機"""
    speed = 5  # 移動速度
    reload_time = 15  # リロード時間
    def __init__(self):
        # imageとcontainersはmain()でセット
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.rect = self.image.get_rect()
        self.rect.bottom = SCR_RECT.bottom  # プレイヤーが画面の一番下
        self.reload_timer = 0
    def update(self):
        # 押されているキーをチェック
        pressed_keys = pygame.key.get_pressed()
        # 押されているキーに応じてプレイヤーを移動
        if pressed_keys[K_LEFT]:
            self.rect.move_ip(-self.speed, 0)
        elif pressed_keys[K_RIGHT]:
            self.rect.move_ip(self.speed, 0)
        elif pressed_keys[K_UP]:
            self.rect.move_ip(0, -self.speed)
        elif pressed_keys[K_DOWN]:
            self.rect.move_ip(0, self.speed)
        self.rect.clamp_ip(SCR_RECT)
        # ミサイルの発射
        if pressed_keys[K_SPACE]:
            # リロード時間が0になるまで再発射できない
            if self.reload_timer > 0:
                # リロード中
                self.reload_timer -= 1
            else:
                # 発射!!!
                Player.shoot_sound.play()
                Shot(self.rect.center)  # 作成すると同時にallに追加される
                self.reload_timer = self.reload_time

class Alien(pygame.sprite.Sprite):
    """エイリアン"""
    speed = 2  # 移動速度
    animcycle = 18  # アニメーション速度
    frame = 0
    move_width = 230  # 横方向の移動範囲
    prob_beam = 0.005  # ビームを発射する確率
    def __init__(self, pos):
        # imagesとcontainersはmain()でセット
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = self.images[0]
        self.rect = self.image.get_rect()
        self.rect.center = pos
        self.left = pos[0]  # 移動できる左端
        self.right = self.left + self.move_width  # 移動できる右端
    def update(self):
        # 横方向への移動
        self.rect.move_ip(self.speed, 0)
        if self.rect.center[0] < self.left or self.rect.center[0] > self.right:
            self.speed = -self.speed
        # ビームを発射
        if random.random() < self.prob_beam:
            Beam(self.rect.center)
        # キャラクターアニメーション
        self.frame += 1
#        self.image = self.images[self.frame/self.animcycle%2]
        self.image = self.images[self.frame//self.animcycle%2]       

class Shot(pygame.sprite.Sprite):
    """プレイヤーが発射するミサイル"""
    speed = 9  # 移動速度
    def __init__(self, pos):
        # imageとcontainersはmain()でセット
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.rect = self.image.get_rect()
        self.rect.center = pos  # 中心座標をposに
    def update(self):
        self.rect.move_ip(0, -self.speed)  # 上へ移動
        if self.rect.top < 0:  # 上端に達したら除去
            self.kill()

class Beam(pygame.sprite.Sprite):
    """エイリアンが発射するビーム"""
    speed = 5  # 移動速度
    def __init__(self, pos):
        # imageとcontainersはmain()でセット
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.rect = self.image.get_rect()
        self.rect.center = pos
    def update(self):
        self.rect.move_ip(0, self.speed)  # 下へ移動
        if self.rect.bottom > SCR_RECT.height:  # 下端に達したら除去
            self.kill()

def load_image(filename, colorkey=None):
    """画像をロードして画像と矩形を返す"""
    filename = os.path.join("data", filename)
    try:
        image = pygame.image.load(filename)
    except pygame.error as message:
        print("Cannot load image:", filename)
        raise SystemExit(message)
#    image = image.convert()
    image = image.convert_alpha()
    return image

def split_image(image, n):
    """横に長いイメージを同じ大きさのn枚のイメージに分割
    分割したイメージを格納したリストを返す"""
    image_list = []
    w = image.get_width()
    h = image.get_height()
    w1 = w / n
#    for i in range(0, w, w1):
    for i in range(0, w, 22):        
        surface = pygame.Surface((w1,h))
        surface.blit(image, (0,0), (i,0,w1,h))
        surface.set_colorkey(surface.get_at((0,0)), RLEACCEL)
        surface.convert()
        image_list.append(surface)
    return image_list

def load_sound(filename):
    filename = os.path.join("data", filename)
    return pygame.mixer.Sound(filename)

if __name__ == "__main__":
    main()

#が先頭にある所のコードは人工知能に関する断創録さんのコードから変えている所です。他には画像、音声ファイルの名前を変えて

def main():

の所の

Back_image = load_image("desert.png")
back_rect = Back_image.get_rect()
screen.blit(Back_image, back_rect)

を付け加え
「# ビームとミサイルの衝突判定」も付け加え
他には2to3で直したのが

except pygame.error as message:
print("Cannot load image:", filename)
raise SystemExit(message)

です。はまった所は

screen.blit(Back_image, back_rect)

while True:

の中に書かないと背景が正常に表示されないことです。

screen.fill((0, 0, 0))

が2か所に書かれていても背景が正常に表示されなかったです。

効果音は「bfxr」を利用させていただきました。
上方のDownload Bfxr Standalone V1.4.1 ( WINDOWS | MAC )の自分のpcでWINDOWSかMACを選びクリックするとダウンロードできます。そしてLhaplusなどで解凍すると使えます。使い方は、クリックするだけで効果音を自動生成する「bfxr」 – Unityインターハイブログさん
Bfxrでアプリの効果音を作る – モーリーのメモさんが参考になりました。

ゲームのプレイは下のようになります。

自作する手間を省きたい人は次のzipファイルをダウンロードして、Lhaplusなどで解凍してお使いください。
invader5