のあの

のあの日常ブログ

シューティングゲームにゲームクリア画面を付ける

半年前にシューティングを作成しようという話があがりました

ただただ普通のシューティングゲームを作成しても面白みがないので、
何かオリジナリティあるもの を探していました。

いつものようにtwitterを眺めていると気づきました、みんなこれが大好きだと。

ガチャ

ガチャを回して出てきたキャラクターを機体としてクリアするシューティングゲーム!
無料で何度でもガチャが回せるのできっと人気がでます。

そんなコンセプトで半年前に身内用にシューティングゲームを作成しました。

なんとか遊べる程度には無理やり作成できましたが、
ゲームのクリア画面がなかったので今回はあの頃に戻り、ゲームクリア画面を実装したいと思います。

使用言語はPythonです
pygameを利用しています

こちらの記事を参考に初めは作成しました。

aidiary.hatenablog.com

Pythonでゲームを作ろうと思うと必ずお世話になるのではないでしょうか?
こちらのインベーダー部分を基にごちゃっととりあえず動くものを作成しました。

確か画面遷移はこんな感じです

f:id:nor24:20180818191646p:plain

ステージは5つあり、次のステージに進むためのステージクリア画面は用意してありますが、
全てのステージをクリアしたときにもステージクリア画面へ移行してしまいます。

次のステージがないならゲームクリアと判断し、リザルトを表示するゲームクリア画面を作成します

f:id:nor24:20180818191835p:plain

ここから先は今の実装を見ないとわからないと思うので個人的なメモみたいになりますm__m

クリアタイムの保存

ゲームクリア時に各ステージのクリアタイムとそれを合計したものを表示する 現状のソースコードを見ると、ゲームスタート時に測定を開始し、それからずっとストップすることない目印みたいなものになっている

        if self.gameState == PLAY:
            # 残機とか体力とかスコアとか.
            # プレイ時間.
            self.result = time.time() - self.stime
            result = int(self.result * 100)
            text = getText("{:.2f}".format(result/100), 30, WHITE)
            self.screen.blit(text, (self.scr_rect.width - text.get_width() - 5, self.scr_rect.height - text.get_height() - 5))
            # 体力
            text = getText(str(self.player.hp), 30, WHITE)
            self.screen.blit(text, (150, self.scr_rect.height - text.get_height() - 5))
            pygame.draw.rect(self.screen, YELLOW, Rect(30, self.scr_rect.height - text.get_height() - 5, 100 * self.player.hp / self.player.hp_max, 30))
            
        elif self.gameState == GAMECLEAR:
            titleText = getText("CLEAR", 75, YELLOW)
            self.screen.blit(titleText, (self.scr_rect.width//2 - titleText.get_width()//2, self.scr_rect.height//4))
            self.updateButtonView()

self.result に今の時間が入ってそう。。 100倍してIntにキャストして、100で割っているのは小数点第二桁より下を切り捨てするためっぽい

その値を保存し、クリア時に表示させたいので一旦以下のように変更

        if self.gameState == PLAY:
            # 残機とか体力とかスコアとか.
            # プレイ時間.
            playTime = time.time() - self.stime
            time_buf = int(playTime * 100)
            self.clearTime = "{:.2f}".format(time_buf/100)
            text = getText(self.clearTime, 30, WHITE)
            self.screen.blit(text, (self.scr_rect.width - text.get_width() - 5, self.scr_rect.height - text.get_height() - 5))
            # 体力
            text = getText(str(self.player.hp), 30, WHITE)
            self.screen.blit(text, (150, self.scr_rect.height - text.get_height() - 5))
            pygame.draw.rect(self.screen, YELLOW, Rect(30, self.scr_rect.height - text.get_height() - 5, 100 * self.player.hp / self.player.hp_max, 30))
            
        elif self.gameState == GAMECLEAR:
            titleText = getText("CLEAR", 75, YELLOW)
            self.screen.blit(titleText, (self.scr_rect.width//2 - titleText.get_width()//2, self.scr_rect.height//4))
            clearText = "clear time: " + self.clearTime
            text = getText(clearText, 30, WHITE)
            self.screen.blit(text, (self.scr_rect.width//2 - text.get_width()//2, self.scr_rect.height//4 + 150))
            self.updateButtonView()

f:id:nor24:20180819194318p:plain

クリア時に時間が表示されるようになった。

あととこの時間を保存していたいのでNEXTを押したときに保存するように関数をたたく

                    if self.chooing_buton == NEXT_BUTTON:
+                        self.stime = time.time()
+                        self.gameManager.setClearTime(self.clearTime)
                        self.returnStatus = GameState.Pass
                        self.gameManager.stageNumber += 1
                        self.gameManager.createStage()
                        self.gameState = PLAY

gameManagerにセット関数を用意し、stimeを現在地で初期化。
これで次のステージはまた0秒からカウントアップをする

ゲームクリア画面への遷移

最終ステージをクリアしても、特別な画面へ遷移することがないのでとりあえず側だけ作る
基本はgameOver画面をコピーしてgameClear画面を作成。

GameStateにGameclearを追加。

    def createStage(self):
        if self.stageNumber == 1:
            self.stage = Stage1()
        elif self.stageNumber == 2:
            self.stage = Stage2()
        elif self.stageNumber == 3:
            self.stage = Stage3()
        elif self.stageNumber == 4:
            self.stage = Stage4()
        elif self.stageNumber == 5:
            self.stage = Stage5()
        else:
            self.state = GAMECLEAR
            return
        self.state = PLAY

あまりよくない実装っぽいけど次のステージがない場合はstateをGAMECLEARにする
GAMECLEARならGameclearを返す(なんだこの実装は・・・)

        self.key_handler()
        if self.gameManager.state == GAMECLEAR:
            self.clearTimes = self.gameManager.getClearTimes();
            self.returnStatus = GameState.Gameclear
        elif self.gameState == PLAY:
            self.gameState = self.gameManager.update()
        elif self.gameState == GAMEOVER:
            self.returnStatus = GameState.Gameover
        return self.returnStatus

GAMECLEARならGameClear画面を呼び出す

        while True:
            clock.tick(60)
            event = view.main()
            pygame.display.update()
            if(event == GameState.Title):
                view = TitleView()
            elif(event == GameState.Gacha):
                view = GachaView()
            elif(event == GameState.Wait):
                view = WaitView(view.player)
            elif(event == GameState.Play):
                view = PlayView(view.player)
            elif(event == GameState.Gameover):
                view = GameoverView(view.player)
            elif(event == GameState.Gameclear):
                view = GameClearView(view.player)
            elif(event == GameState.Quit):
                pygame.quit()
                sys.exit()
                break
            elif(event == GameState.Pass):
                pass

これで画面遷移するように
あとはGameClearViewのメンテナンス

とりあえずGameClearView作成時に各ステージのクリアタイムを渡す

                view = GameoverView(view.player)
            elif(event == GameState.Gameclear):
-                view = GameClearView(view.player)
+               view = GameClearView(view.player, view.clearTimes)
            elif(event == GameState.Quit):

あとは結果を張り付けるだけ!

    def updateResultView(self):
        stageCount = len(self.clearTimes)
        stageNum = 1
        totalTime = 0.0
        for clearTime in self.clearTimes:
            clearTimeText = getText("Stage" + str(stageNum) + " : " + str(self.clearTimes[stageNum-1]), 30, WHITE)
            self.screen.blit(clearTimeText, (self.scr_rect.width//2 - 100, self.scr_rect.height//4 + (30 * stageNum)))
            totalTime += float(self.clearTimes[stageNum-1])
            stageNum += 1
        time = int(totalTime * 100)
        totalTime = time/100
        clearTimeText = getText("TotalClearTime : "+ str(totalTime), 40, WHITE)
        self.screen.blit(clearTimeText, (self.scr_rect.width//8, self.scr_rect.height//4*3))

関数名が hogeView なのが気に食わない・・・今はこれで。。

f:id:nor24:20180819204732p:plain

いい感じ

あとはどのキャラクターでクリアしたのかも表示したいので、ちょこっと修正

    def updatePlayerView(self):
        text = getText("Player : " + self.player.NAME, 30, BLUE)
        self.screen.blit(text, (self.scr_rect.width//8 * 2 + 30, self.scr_rect.height//5*3 + 80))
        
        image = pygame.transform.scale(self.player.image, (160, 160))
        self.screen.blit(image, (self.scr_rect.width//4 * 3 , self.scr_rect.height//5*3 - 20))

マジックナンバーだらけ。
もう仕様変更不可\(^o^)/

f:id:nor24:20180819205830p:plain

完成。

あとはバランスを少し調整しておわり!! stage4と5は難しいので省略した

配布用にpyinstallerを使用

$pyinstaller [src.main.py] --clean --noconsole --onefile

exeの完成!!

STG.zip

暇だったら遊んでやってください(-"-)