1
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?

Qiita全国学生対抗戦Advent Calendar 2024

Day 16

【Pygame】放置ゲームのプロトタイプを作ってみた

Posted at

【Pygame】放置ゲームのプロトタイプを作ってみた

 Pygameで放置ゲームのプロトタイプ的なプログラムを作ってみました。

超絶シンプルな仕様

  • 円をクリックするとリソース+1。
  • オートマトンの部分をクリックすると、リソースが足りていた時のみレベルが上がってプロデュースが増加。
  • プログラムを終了後再起動すると経過時間に応じてリソースがもらえる。

 各部分の英単語は適当です。

 ソースコード

game.py
#インポート
import pygame
import time
from pygame.locals import *
import sys

#クラス
class App:
    #コンストラクタ
    def __init__(self):
        #初期化
        self.running=True
        self.fps=15
        self.resouce=0
        self.produce=0
        self.level=0
        self.clock=pygame.time.Clock()
        self.res=None
        self.t=None

        #ウインドウの設定
        self.screen=pygame.display.set_mode((600,600))
        pygame.display.set_caption("Producing & Developing")

        #セーブデータ読み込み
        try:
            with open("data.txt") as f:
                self.t=int(time.time())
                t_b=None
                l=[s.rstrip() for s in f.readlines()]
                if len(l)==3:
                    for i in range(len(l)):
                        l[i]=int(l[i])
                    t_b=l[0]
                    self.resouce=l[1]
                    self.level=l[2]
                    self.t-=t_b
                    self.produce=self.level
                    for i in range(self.level//10):
                        self.produce*=2
                    self.res=self.produce*self.t
                    self.resouce+=self.res
        except:pass

        #フォントの設定
        self.font=pygame.font.SysFont("Menlo",30)
        self.f_b=pygame.font.SysFont("Menlo",15)

        #一秒間隔でタイマーを設定
        pygame.time.set_timer(1,1000)

        #更新処理
        self.run()

    #更新関数
    def run(self):
        #ループ
        while self.running:
            #fpsを設定
            self.clock.tick(self.fps)
            #イベント取得
            for event in pygame.event.get():
                #終了処理
                if event.type==QUIT:
                    self.running=False
                    s=int(time.time())
                    #セーブ
                    with open("data.txt",mode="w") as f:
                        f.write("\n".join([str(s),str(self.resouce),str(self.level)]))
                    #プログラムを終了
                    pygame.mixer.stop()
                    pygame.quit()
                    sys.exit()

                #マウスクリック
                elif event.type==MOUSEBUTTONDOWN:
                    btn=event.button
                    x,y=event.pos
                    if btn==1 and x>=150 and x<=300 and y>=225 and y<=375:
                        self.resouce+=1
                    elif x>=150 and y<=495 and y>=450 and x<=385:
                        if self.resouce>=(self.level+1)*10+200*(self.level//10)**2:
                            self.resouce-=(self.level+1)*10+200*(self.level//10)**2
                            self.level+=1

                #タイマーに対してリソースの所持数を更新
                elif event.type==1:
                    self.resouce+=self.produce
                
                #エスケープキーで画面遷移
                elif event.type==KEYDOWN:
                    if event.key==K_ESCAPE:
                        self.res=None
                        self.screen.fill((0,0,0))
                    
            #毎秒生産量を計算
            self.produce=self.level
            for i in range(self.level//10):
                self.produce*=1.5
            
            #描画処理
            #描画の順番:円->通常テキスト->放置テキスト
            self.txt=[self.font.render("Resouce:%5g"%(self.resouce),True,(255,255,255),(0,0,0)),
                self.font.render("Produce:%3g/s"%(self.produce),True,(255,255,255),(0,0,0)),
                self.font.render("AutomatonLv:%d"%(self.level),True,(0,0,0),(255,255,255)),
                self.f_b.render("Necessary:%3d"%((self.level+1)*10+200*(self.level//10)**2),True,(255,255,255),(0,0,0))]
            
            #放置情報
            if self.res!=None:
                self.spec=self.f_b.render("Game was frozen for %d seconds"%(self.t),True,(255,0,0),(0,0,0))
                self.spec_b=self.f_b.render("Resouce + %d"%(self.res),True,(255,0,0),(0,0,0))
                self.end=self.f_b.render("Plese press to ESC",True,(255,255,255),(0,0,0))
                self.screen.blit(self.spec,(50,300))
                self.screen.blit(self.spec_b,(50,340))
                self.screen.blit(self.end,(50,380))

            self.screen.blit(self.txt[1],(150,55))
            self.screen.blit(self.txt[0],(150,15))
            self.screen.blit(self.txt[2],(150,450))
            self.screen.blit(self.txt[3],(150,485))
            #アップデート
            pygame.display.update()
            
            #サークルの描画
            pygame.draw.circle(self.screen,(255,255,255),(225,300),75)

#メイン
if __name__=="__main__":
    #pygame初期化
    pygame.init()
    pygame.mixer.init()
    #インスタンス生成
    main=App()

解説

 といっても、そこまで解説することはありません。
 インターフェース部分は「クリックに反応してリソースを加算する」ということと、「規定のリソースを消費してプロデュースを加算する」というシンプルな構成です。更新処理も一秒ごとにプロデュースの値分リソースを増加させるということをやるだけ。放置ゲームは意外と単純なロジックで実装できます。
 肝は開始時のロード処理と終了時のセーブ処理です。終了時、このプログラムはセーブファイルにtime.time()の値とリソースの値、オートマトンのレベルを書き込みます。次回起動時は初めにその三つを読み込むわけです。リソースの値はそのままリソースに、オートマトンのレベルはオートマトンのレベルに反映したのち、プロデュースの値の計算に使います。time.time()の値は前回の終了時刻を示すため、それとは別に今回の開始時刻をtime.time()を計算し差を取ることで経過時間を計算します。その経過時間とプロデュースをかけた値が「放置報酬」として通知、加算される仕組みです。

pygameを触っていて思ったこと

 普段はドット絵ばかり扱っているため、描画関係を考えるのが大変でした。もう少し更新だとか描画の上下関係とか画面遷移とか、その辺を楽に管理できるといいんですが。
 描画の内容を簡潔に表現できるライブラリがあればいいなあ。

1
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
1
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?