すでにPythonを知っている人向けのPygame入門です。この記事では、プレイヤーがバウンドするボールをかわすシンプルなゲームを作る手順をお教えします。
Pygameのインストール
-
Pygameをダウンロードします。.NETからあなたのプラットフォームに合ったものを探してください。
-
インストーラを実行する。
-
インストールがうまくいったか確認する。Pythonターミナルを開く。"import pygame "と入力する。エラーが表示されなければ、Pygameは正常にインストールされています。import pygame
基本的なウィンドウの設定
-
新しいファイルを開きます。
-
Pygameをインポートします。Pygameはグラフィック関数へのアクセスを提供するライブラリです。これらの関数がどのように動作するか、より詳しい情報が必要であれば、Pygameのウェブサイトで調べることができます。import pygame from pygame.locals import *.
-
ウィンドウの解像度を設定します。画面解像度のグローバル変数を作り、ゲームのいくつかの部分で参照できるようにします。また、ファイルの先頭で見つけやすいので、後で変更することもできます。高度なプロジェクトでは、この情報を別のファイルにしたほうがいいだろう。解像度 = (400,300)
-
色を定義します。pygameの色は(RBGAで、0から255の間の値です。アルファ値(A)は任意ですが、他の色(赤、青、緑)は必須です。白 = (255,255,255) 黒 = (0,0,0) 赤 = (255,0,0)
-
画面を初期化する。先ほど定義したresolution変数を使います。screen = pygame.display.set_mode(resolution)
-
ゲームループを作ります。ゲームの各フレームで特定のアクションを繰り返します。これらのアクションを繰り返すループを作ります。while True:
-
画面に色をつける。screen.fill(white)
-
画面を表示する。このプログラムを実行すると、画面が白くなり、プログラムがクラッシュします。これは、オペレーティング・システムがゲームにイベントを送っているのに、ゲームがそれに対して何もしていないからです。ゲームが処理されないイベントを受け取りすぎると、クラッシュします。while True: ... pygame.display.flip()
-
イベントを処理します。各フレームで発生したすべてのイベントのリストを取得します。あなたが気にするイベントは1つだけです。これはユーザーがゲームウィンドウを閉じたときに発生します。これは、イベントが多すぎてプログラムがクラッシュするのを防ぐためでもある。while True: ... for event in pygame.event.get(): if event.type == QUIT: pygame.quit()
-
試してみてください!コードは以下のようになります:import pygame from pygame.locals import * resolution = (400,300) white = (255,255,255) black = (0,0,0) red = (255,0,0) screen = pygame.display.set_mode(resolution) while True: screen.fill(white) pygame.display.flip() for event in pygame.event.get(): if event.type == QUIT: pygame.quit()
ゲームオブジェクトを作る
-
新しいクラスとコンストラクタを作ります。オブジェクトのすべてのプロパティを設定します。また、すべてのプロパティにデフォルト値を設定します。class Ball: def __init__(self, xPos = resolution[0] / 2, yPos = resolution[1] / 2, xVel = 1, yVel = 1, rad = 15): self.x = xPos self.y = yPos self.dx = xVel self.dy = yVel self.radius = rad self.type = "ball" オブジェクトの描画方法を定義する。
-
オブジェクトの描画方法を定義する。コンストラクタで定義したプロパティを使用して、ボールを円として描画し、オブジェクトを描画するサーフェスを関数に渡す。サーフェスは、先ほど解像度を使用して作成したスクリーン・オブジェクトになる。定義 draw(self, surface): pygame.draw.circle(surface, black, (self.x, self.y), self.radius)
-
このクラスのインスタンスを作り、ゲームループにボールを描画するように指示します。ball = Ball() while True: ... ball.draw(screen)
-
オブジェクトを動かす。オブジェクトの位置を更新する関数を作る。この関数をゲームのループごとに呼び出す。class Ball: ... def update(self): self.x += self.dx self.y += self.dy
-
フレームレートを制限する。ゲームループは1秒間に何百回も実行されるので、ボールの動きはとても速くなります。Pygameのクロックを使ってフレームレートを60fpsに制限します。clock = pygame.time.Clock() while True: ... clock.tick(60)
-
画面上にボールを表示し続ける。ボールが画面の端にぶつかったら、ボールの向きを逆にするチェックをupdate関数に追加します。class Ball: ... def update(self): ... if (self.x <= 0 or self.x >= resolution[0]): self.dx *= -1 if (self.y <= 0 or self.y >= resolution[1]): self.dy *= -1
-
試してみよう!コードは以下のようになります:import pygame from pygame.locals import * resolution = (400,300) white = (255,255,255) black = (0,0,0) red = (255,0,0) screen = pygame.display.set_mode(resolution) class Ball: def __init__(self, xPos = resolution[0] / 2, yPos = resolution[1] / 2, xVel = 1, yVel = 1, rad = 15): self.x = xPos self.y = yPos self.dx = xVel self.dy = yVel self.radius = rad self.type = "ball" def draw(self, surface): pygame.draw.circle(surface, black, (self.x, self.y), self.radius) def update(self): self.x += self.dx self.y += self.dy if (self.x <= 0 or self.x >= resolution[0]): self.dx *= -1 if (self.y <= 0 or self.y >= resolution[1]): self.dy *= -1 ball = Ball() clock = pygame.time.Clock() while True: screen.fill(white) ball.draw(screen) ball.update() pygame.display.flip() clock.tick(60) for event in pygame.event.get(): if event.type == QUIT: pygame.quit()
ゲームの整理
-
クラスを使ってすべてを整理します。ゲームは複雑になっていきます。オブジェクト指向のテクニックを使ってコードを整理しましょう。
-
ゲームループをクラス化する。ゲームオブジェクトと関数を含むデータを持つようになったので、ゲームループをクラス化するのは理にかなっています。クラス game():
-
コンストラクタを追加します。ここでゲームオブジェクトをインスタンス化し、画面と時計を作成し、Pygameを初期化します。Pygameはテキストやサウンドのような特定の機能を使うために初期化する必要があります。class game(): def __init__(self): pygame.init() self.screen = pygame.display.set_mode(resolution) self.clock = pygame.time.Clock()
-
関数の中でイベントを処理します。class game(): ... def handleEvents(self): for event in pygame.event.get(): if event.type == QUIT: pygame.quit()。
-
ゲームループを関数にします。ループごとにイベント処理関数を呼び出します。class game(): ... def run(self): while True: self.handleEvents() self.screen.fill(white) self.clock.tick(60) pygame.display.flip()。
-
複数のゲームオブジェクトを扱う。今のところ、このコードはフレームごとにオブジェクトの描画と更新を呼び出さなければなりません。これはオブジェクトがたくさんある場合に面倒になります。オブジェクトを配列に追加して、ループのたびに配列内のすべてのオブジェクトを更新して描画するようにしましょう。これで簡単に別のオブジェクトを追加して、別の開始位置を与えることができる。class game(): def __init__(self): ... self.gameObjects = [] self.gameObjects.append(Ball()) self.gameObjects.append(Ball(100)) ... def run(self): while True: self.handleEvents() for gameObj in self.for gameObj in self.gameObjects: gameObj.update() self.screen.fill(white) for gameObj in self.gameObjects: gameObj.draw(self.screen) self.clock.tick(60) pygame.display.flip()
-
試してみてください!コードはこんな感じになります:import pygame from pygame.locals import * resolution = (400,300) white = (255,255,255) black = (0,0,0) red = (255,0,0) screen = pygame.display.set_mode(resolution) class Ball: def __init__(self, xPos = resolution[0] / 2, yPos = resolution[1] / 2, xVel = 1, yVel = 1, rad = 15): self.x = xPos self.y = yPos self.dx = xVel self.dy = yVel self.radius = rad self.type = "ball" def draw(self, surface): pygame.draw.circle(surface, black, (self.x, self.y), self.radius) def update(self): self.x += self.dx self.y += self.dy if (self.x <= 0 or self.x >= resolution[0]): self.dx *= -1 if (self.y <= 0 or self.y >= resolution[1]): self.dy *= -1 class game(): def __init__(self): pygame.init() self.screen = pygame.display.set_mode(resolution) self.clock = pygame.time.Clock() self.gameObjects = [] self.gameObjects.append(Ball()) self.gameObjects.append(Ball(100)) def handleEvents(self): for event in pygame.event.get(): if event.type == QUIT: pygame.quit() def run(self): while True: self.handleEvents() for gameObj in self.gameObjects: gameObj.update() self.screen.fill(white) for gameObj in self.gameObjects: gameObj.draw(self.screen) self.clock.tick(60) pygame.display.flip() game().run()
プレイヤーオブジェクトの追加
-
プレイヤークラスとコンストラクタを作ります。マウスで操作するもう1つの円を作ります。コンストラクタで値を初期化します。半径だけが重要な値である。class Player: def __init__(self, rad = 20): self.x = 0 self.y = 0 self.radius = rad
-
プレイヤー・オブジェクトの描画方法を定義する。他のゲーム・オブジェクトと同じように描画する。クラス Player: ... def draw(self, surface): pygame.draw.circle(surface, red, (self.x, self.y), self.radius)
-
プレイヤーオブジェクトにマウスコントロールを追加します。毎フレーム、マウスの位置をチェックし、プレイヤーのオブジェクトの位置をその点に設定する。class Player: ... def update(self): cord = pygame.mouse.get_pos() self.x = cord[0] self.y = cord[1].
-
gameObjectsにプレイヤーオブジェクトを追加する。新しいプレイヤーインスタンスを作成し、リストに追加します。class game(): def __init__(self): ... self.gameObjects.append(Player())
-
試してみてください!コードは以下のようになります:import pygame from pygame.locals import * resolution = (400,300) white = (255,255,255) black = (0,0,0) red = (255,0,0) screen = pygame.display.set_mode(resolution) class Ball: def __init__(self, xPos = resolution[0] / 2, yPos = resolution[1] / 2, xVel = 1, yVel = 1, rad = 15): self.x = xPos self.y = yPos self.dx = xVel self.dy = yVel self.radius = rad self.type = "ball" def draw(self, surface): pygame.draw.circle(surface, black, (self.x, self.y), self.radius) def update(self): self.x += self.dx self.y += self.dy if (self.x <= 0 or self.x >= resolution[0]): self.dx *= -1 if (self.y <= 0 or self.y >= resolution[1]): self.dy *= -1 class Player: def __init__(self, rad = 20): self.x = 0 self.y = 0 self.radius = rad self.type = "player" def draw(self, surface): pygame.draw.circle(surface, red, (self.x, self.y), self.radius) def update(self): cord = pygame.mouse.get_pos() self.x = cord[0] self.y = cord[1] class game(): def __init__(self): pygame.init() self.screen = pygame.display.set_mode(resolution) self.clock = pygame.time.Clock() self.gameObjects = [] self.gameObjects.append(Player()) self.gameObjects.append(Ball()) self.gameObjects.append(Ball(100)) def handleEvents(self): for event in pygame.event.get(): if event.type == QUIT: pygame.quit() def run(self): while True: self.handleEvents() for gameObj in self.for gameObj in self.gameObjects: gameObj.update() self.screen.fill(white) for gameObj in self.gameObjects: gameObj.draw(self.screen) self.clock.tick(60) pygame.display.flip() game().run()
オブジェクトをプレイヤーとインタラクトさせる
-
Update関数を変更します。オブジェクトが相互作用するためには、お互いにアクセスする必要があります。Updateにもうひとつパラメーターを追加して、gameObjectsリストを渡すようにしましょう。PlayerオブジェクトとBallオブジェクトの両方に追加する必要がある。ゲーム・オブジェクトがたくさんある場合は、継承を使えば、すべてのメソッドのシグネチャを同じにすることができる。class Ball: ... def update(self, gameObjects): ... class Player: ... def update(self, gameObjects):
-
プレイヤーとボールの衝突をチェックする。すべてのゲームオブジェクトを調べて、オブジェクトのタイプがボールかどうかをチェックする。それから、2つのオブジェクトの半径と距離の式を使って、衝突しているかどうかをチェックする。円は衝突をチェックするのがとても簡単です。これが、このゲームに他のシェイプを使わなかった最大の理由だ。class Player: ... def update(self, gameObjects): ... for gameObj in gameObjects: if gameObj.type == "ball": if (gameObj.x - self.x)**2 + (gameObj.y - self.y)**2 <= (gameObj.radius + self.radius)**2:
-
プレイヤーが「ヒット」したらゲームを終了する。とりあえずゲームを終了しよう。if (gameObj.x - self.x)**2 + (gameObj.y - self.y)**2 <= (gameObj.radius + self.radius)**2: pygame.quit()
-
試してみてください!コードは次のようになります:import pygame from pygame.locals import * resolution = (400, 300) white = (255,255,255) black = (0,0,0) red = (255,0,0) screen = pygame.display.set_mode(resolution) class Ball: def __init__(self, xPos = resolution[0] / 2, yPos = resolution[1] / 2, xVel = 1, yVel = 1, rad = 15): self.x = xPos self.y = yPos self.dx = xVel self.dy = yVel self.radius = rad self.type = "ball" def draw(self, surface): pygame.draw.circle(surface, black, (self.x, self.y), self.radius) def update(self, gameObjects): self.x += self.dx self.y += self.dy if (self.x <= 0 or self.x >= resolution[0]): self.dx *= -1 if (self.y <= 0 or self.y >= resolution[1]): self.dy *= -1 class Player: def __init__(self, rad = 20): self.x = 0 self.y = 0 self.radius = rad self.type = "player" def draw(self, surface): pygame.draw.circle(surface, red, (self.x, self.y), self.radius) def update(self, gameObjects): cord = pygame.mouse.get_pos() self.x = cord[0] self.y = cord[1] for gameObjects in gameObj: if gameObj.type == "ball": if (gameObj.x - self.x)**2 + (gameObj.y - self.y)**2 <= (gameObj.radius + self.radius)**2: pygame.quit() class game(): def __init__(self): pygame.init() self.screen = pygame.display.set_mode(resolution) self.clock = pygame.time.Clock() self.gameObjects = [] self.gameObjects.append(Player()) self.gameObjects.append(Ball()) self.gameObjects.append(Ball(100)) def handleEvents(self): for event in pygame.event.get(): if event.type == QUIT: pygame.quit() def run(self): while True: self.handleEvents() for gameObj in self.gameObjects: gameObj.update(self.gameObjects) self.screen.fill(white) for gameObj in self.gameObjects: gameObj.draw(self.screen) self.clock.tick(60) pygame.display.flip() game().run()
オブジェクトを生成するゲームコントローラの追加
-
ゲームコントローラクラスを作ります。ゲームコントローラはゲームの "実行 "を担当します。オブジェクトの描画や更新を行うゲームクラスとは異なります。コントローラは定期的に別のボールを画面に追加して、ゲームを難しくします。コンストラクタを追加して、基本的な値を初期化します。インターバルは、別のボールが追加されるまでの時間になります。class GameController: def __init__(self, interval = 5): self.inter = interval self.next = pygame.time.get_ticks() + (2 * 1000) self.type = "ゲームコントローラ"
-
update関数を追加します。これは、ボールが追加された時、またはゲーム開始からの経過時間をチェックします。もし時間がインターバルより長ければ、時間をリセットしてボールを追加する。class GameController: ... def update(self, gameObjects): if self.next < pygame.time.get_ticks(): self.next = pygame.time.get_ticks() + (self.inter * 1000) gameObjects.append(ボール())
-
ボールにランダムな速度を与えます。ゲームを毎回違うものにするために乱数を使う必要があります。ただし、ボールの速度は整数ではなく浮動小数点数になる。class GameController: ... def update(self, gameObjects): if self.next < pygame.time.get_ticks(): self.next = pygame.time.get_ticks() + (self.inter * 1000) gameObjects.append(Ball(xVel=random()*2, yVel=random()*2))
-
描画関数を修正。draw関数は浮動小数点数を受け付けない。ボールが描画される前に、ボールの位置を整数に変換しよう。クラス Ball: ... def draw(self, surface): pygame.draw.circle(surface, black, (int(self.x), int(self.y)), self.radius)
-
ゲームコントローラの描画メソッドを定義します。ゲームオブジェクトなので、メインループで描画しようとします。ゲームがクラッシュしないように、何もしない描画関数を定義する必要がある。class GameController: ... def draw(self, screen): pass
-
ゲームコントローラーをgameObjectsに追加し、2つのボールを削除する。これでゲームは5秒ごとにボールを生成するようになる。class game(): def __init__(self): ... self.gameObjects = [] self.gameObjects.append(GameController()) self.gameObjects.append(Player())
-
試してみよう!コードは以下のようになります:import pygame from random import random from pygame.locals import * resolution = (400,300) white = (255,255,255) black = (0,0,0) red = (255,0,0) screen = pygame.display.set_mode(resolution) class Ball: def __init__(self, xPos = resolution[0] / 2, yPos = resolution[1] / 2, xVel = 1, yVel = 1, rad = 15): self.x = xPos self.y = yPos self.dx = xVel self.dy = yVel self.radius = rad self.type = "ball" def draw(self, surface): pygame.draw.circle(surface, black, (int(self.x), int(self.y)), self.radius) def update(self, gameObjects): self.x += self.dx self.y += self.dy if (self.x <= 0 or self.x >= resolution[0]): self.dx *= -1 if (self.y <= 0 or self.y >= resolution[1]): self.dy *= -1 class Player: def __init__(self, rad = 20): self.x = 0 self.y = 0 self.radius = rad self.type = "player" def draw(self, surface): pygame.draw.circle(surface, red, (self.x, self.y), self.radius) def update(self, gameObjects): cord = pygame.mouse.get_pos() self.x = cord[0] self.y = cord[1] for gameObjects in gameObj: if gameObj.type == "ball": if (gameObj.x - self.x)**2 + (gameObj.y - self.y)**2 <= (gameObj.radius + self.radius)**2: pygame.quit() class GameController: def __init__(self, interval = 5): self.inter = interval self.next = pygame.time.get_ticks() + (2 * 1000) self.type = "game controller" def update(self, gameObjects): if self.next < pygame.time.get_ticks(): self.next = pygame.time.get_ticks() + (self.inter * 1000) gameObjects.append(Ball(xVel=random()*2, yVel=random()*2)) def draw(self, screen): pass class game(): def __init__(self): pygame.init() self.screen = pygame.display.set_mode(resolution) self.clock = pygame.time.Clock() self.gameObjects = [] self.gameObjects.append(GameController()) self.gameObjects.append(Player()) def handleEvents(self): for event in pygame.event.get(): if event.type == QUIT: pygame.quit() def run(self): while True: self.handleEvents() for gameObj in self.gameObjects: gameObj.update(self.gameObjects) self.screen.fill(white) for gameObj in self.gameObjects: gameObj.draw(self.screen) self.clock.tick(60) pygame.display.flip() game().run()
スコアとゲームオーバーの追加
-
ゲームコントローラクラスに得点を追加します。フォントオブジェクトとスコア変数を作ります。毎フレームでフォントを描画して得点を表示し、更新で毎フレーム得点を増やす。class GameController: def __init__(self, interval = 5): ... self.score = 0 self.scoreText = pygame.font.Font(None, 12) def update(self, gameObjects): ... self.score += 1 def draw(self, screen): screen.blit(self.scoreText.render(str(self.score), True, black), (5,5))
-
ゲームの終了方法を変更する。プレーヤーが衝突を検知したら終了するようにしよう。その代わりに、プレイヤーがチェックできる変数を設定する。gameOverがセットされたら、オブジェクトの更新を停止する。これですべてがフリーズするので、プレイヤーは何が起こったかを確認し、スコアをチェックすることができる。オブジェクトは更新されないだけで、まだ描画されていることに注意。class Player: def __init__(self, rad = 20): ... self.gameOver = False def update(self, gameObjects): ... for gameObj in gameObjects: if gameObj.type == "ball": if (gameObj.x - self.x)**2 + (gameObj.y - self.y)**2 <= (gameObj.radius + self.radius)**2: self.gameOver = True class game(): def __init__(self): ... self.gameOver = False def run(self): while True: self.handleEvents() if not self.gameOver: for gameObj in self.gameObjects: gameObj.update(self.gameObjects) if gameObj.type == "player": self.gameOver = gameObj.gameOver
-
試してみてください!完成したコードはこんな感じです:import pygame from random import random from pygame.locals import * resolution = (400,300) white = (255,255,255) black = (0,0,0) red = (255,0,0) screen = pygame.display.set_mode(resolution) class Ball: def __init__(self, xPos = resolution[0] / 2, yPos = resolution[1] / 2, xVel = 1, yVel = 1, rad = 15): self.x = xPos self.y = yPos self.dx = xVel self.dy = yVel self.radius = rad self.type = "ball" def draw(self, surface): pygame.draw.circle(surface, black, (int(self.x), int(self.y)), self.radius) def update(self, gameObjects): self.x += self.dx self.y += self.dy if (self.x <= 0 or self.x >= resolution[0]): self.dx *= -1 if (self.y <= 0 or self.y >= resolution[1]): self.dy *= -1 class Player: def __init__(self, rad = 20): self.x = 0 self.y = 0 self.radius = rad self.type = "player" self.gameOver = False def draw(self, surface): pygame.draw.circle(surface, red, (self.x, self.y), self.radius) def update(self, gameObjects): cord = pygame.マウス.get_pos() self.x = cord[0] self.y = cord[1] for gameObj in gameObjects: if gameObj.type == "ball": if (gameObj.x - self.x)**2 + (gameObj.y - self.y)**2 <= (gameObj.radius + self.radius)**2: self.gameOver = True class GameController: def __init__(self, interval = 5): self.inter = interval self.next = pygame.time.get_ticks() + (2 * 1000) self.type = "game controller" self.score = 0 self.scoreText = pygame.font.Font(None, 12) def update(self, gameObjects): if self.next < pygame.time.get_ticks(): self.next = pygame.time.get_ticks() + (self.inter * 1000) gameObjects.append(Ball(xVel=random()*2, yVel=random()*2)) self.score += 1 def draw(self, screen): screen.blit(self.scoreText.render(str(self.score), True, black), (5,5)) class game(): def __init__(self): pygame.init() self.screen = pygame.display.set_mode(resolution) self.clock = pygame.time.Clock() self.gameObjects = [] self.gameObjects.append(GameController()) self.gameObjects.append(Player()) self.gameOver = False def handleEvents(self): for event in pygame.event.get(): if event.type == QUIT: pygame.quit() def run(self): while True: self.handleEvents() if not self.gameOver: for gameObj in self.gameObjects: gameObj.update(self.gameObjects) if gameObj.type == "player": self.gameOver = gameObj.gameOver self.screen.fill(white) for gameObj in self.gameObjects: gameObj.draw(self.screen) self.clock.tick(60) pygame.display.flip() game().run()
コメント
最新を表示する
NG表示方式
NGID一覧