こんにちは!スタビジ編集部です!
今回はPythonを使ってゲームの作り方について解説していきます!
Pythonで出来ることはたくさんありますが、なんと”ゲーム開発“も出来るんです!
実際にコードを書きながらPythonでのゲーム開発の基礎を学んでいきましょう。
プログラミングは楽しみながら学ぶのが一番だね!
より詳しくPythonでゲームを作る方法を動画で学びたい方は以下のUdemy講座でお話していますのでぜひチェックしてみてください!
【初心者向け】Pythonでゲーム作りに挑戦!pygameを使ってpythonでブロック崩しゲームを作ってみよう!
【時間】 | 3時間 |
---|---|
【レベル】 | 初級 |
Pythonを使ってゲームを作ってみたいならこれ!今なら購入時に「VGRBCQDF」という講師クーポンコードを入れると94%OFFになりますのでぜひご受講ください!
目次
Pythonでゲームを開発するメリット
“Python“はデータ分析や・Webアプリケーション開発など幅広い分野で利用されているプログラミング言語です。
そのため、ゲーム開発に特化して作られた言語ではないですが、Pythonを使ってゲーム開発することも以下のようなメリットがあります。
・豊富なライブラリやフレームワーク
・マルチプラットフォーム対応
それぞれ見ていきましょう。
豊富なライブラリやフレームワーク
Pythonは「ライブラリやフレームワーク」が豊富に用意されています。
ゲーム開発においても”Pygame“といったライブラリや”Panda3D“といったゲームエンジンなど数多くあります。
そのため、それらのツールを活用することで初心者でも簡単にゲーム開発を始めることが可能です。
マルチプラットフォーム対応
Pythonでゲーム開発する利点として「マルチプラットフォーム対応」があります。
他のゲーム開発のソフトウェアやプログラミング言語は土台のプラットフォームと依存関係がある場合があります。
例えば、Windowsの環境で作ったゲームがmacの環境だと動かないといったことがありえます。
それに対し、Pythonで開発されたゲームは、Windows、macOS、Linuxなどの複数のプラットフォームで動作するため、共有がしやすいです。
また自分のPCにPython環境を構築しなくても、”Google Colaboratory“といったクラウド環境で簡単にPythonコードを実行できます。
Pythonでパズルゲームを作る
まずはゲーム開発の入門として画像をタイルにして並び替える「パズルゲーム」を作っていきます。
今回のパズルゲームでは以下のルールで作りたいと思います。
・画像を読み込んで3×3のタイルとする
・クリックしたタイルと次にクリックしたタイルを入れ替える
・タイルが元の画像と同じ配置になったら”正解”と表示する
パズルゲームの作成にはPythonの”pyglet“を利用します。
pygletとは
“pyglet“はゲームやテキスト・動画・音声といった複数のメディアを組み合わせたアプリケーションを開発するためのPythonライブラリです。
pygletには以下の特徴があります。
・依存関係が少ない:インストールするだけで豊富な機能が使える
・マルチメディア機能:ほとんどの形式の画像、音声、動画をサポート
・3Dグラフィックにも対応:OpenGLをベースに3Dグラフィックもサポート
このようにpygletでは様々な要素を簡単に組み合わせたゲームを作ることが出来ます。
pygletの使い方については公式ドキュメントに詳しく書いてあるので、チェックしてみて下さい。
画像のタイル化
では実際にコードを書いてパズルゲームを作っていきましょう。
pip install pyglet
まずはpygletをインストールします。
import pyglet
from pyglet.window import mouse
import random
# 画像の読み込み
image = pyglet.image.load('cat2.jpg')
# ウィンドウの作成
window = pyglet.window.Window(width=image.width, height=image.height, caption="パズルゲーム")
# タイルのサイズと行列の数
TILE_SIZE = image.width // 3
HEIGHT_SIZE = image.height // 3
NUM_TILES = 3
pygletを使って画像の読み込みおよびウィンドウの作成を行います。
ウィンドウはグラフィックを表示したり、ユーザー入力(キーボードやマウス)を処理したりするためのもので、”pyglet.window.Window“クラスを使って作成・管理できます。
# タイルを格納するリスト
tiles = []
# 正解のリスト
correct_indices = list(range(9))
# タイルを作成してリストに追加
for row in range(NUM_TILES):
for col in range(NUM_TILES):
tile = image.get_region(x=col*TILE_SIZE, y=(NUM_TILES - 1 - row)*HEIGHT_SIZE, width=TILE_SIZE, height=HEIGHT_SIZE)
tiles.append(tile)
続いて画像をタイル化してリストに追加していきます。
“get_region“メソッドを使って画像をタイルに分割します。
Pygletの座標系では左下が原点のため、今回は左上から順番に画像を取り込んでいます。
# タイルをシャッフル
def shuffle_tiles():
indices = list(range(len(tiles)))
random.shuffle(indices)
shuffled_tiles = [tiles[i] for i in indices]
return shuffled_tiles, indices
tiles, tile_indices = shuffle_tiles()
タイルをシャッフルします。
ここでは、先に位置の番号をシャッフルし、その番号にタイルを紐づけてシャッフル後のタイルの順番としています。
タイルの描画
次にシャッフルしたタイルを描画していきます。
# タイルの描画
@window.event
def on_draw():
window.clear()
for i, tile in enumerate(tiles):
if tile is not None:
col = i % NUM_TILES
row = i // NUM_TILES
tile.blit(col * TILE_SIZE, window.height - (row + 1) * HEIGHT_SIZE)
# タイルが正しく並んでいるか確認
if tile_indices == correct_indices:
draw_correct_label()
def draw_correct_label():
# 正解のテキストを描画
label = pyglet.text.Label('正解!',
font_name='Times New Roman',
font_size=36,
x=window.width // 2, y=window.height // 2,
anchor_x='center', anchor_y='center',
color=(255, 0, 0, 255), # 赤色
bold=True)
label.draw()
ここでタイルの描画を行います。pygletでは”@window.event“デコレータを使用することで特定のウィンドウイベントが発生した時の処理を定義できます。
ここではウィンドウが再描画されるときに呼び出される”on_draw“イベントを使用しています。
“on_draw“イベントではタイルに紐づいた番号からタイルを左上から順番に描画しています。
そしてタイルが最初の順番通りに並んでいた場合、「正解」という文字を描画する処理を行っています。
タイルの移動
プレイヤーが指定したタイルを入れ替える処理を実装していきましょう。
# タイルの入れ替え
def swap_tiles(index1, index2):
tiles[index1], tiles[index2] = tiles[index2], tiles[index1]
tile_indices[index1], tile_indices[index2] = tile_indices[index2], tile_indices[index1]
print(f"Swapped indices {index1} and {index2}")
print(f"tile_indices after swap: {tile_indices}")
# マウスイベント用変数
selected_index = None
# マウス押下イベント
@window.event
def on_mouse_press(x, y, button, modifiers):
global selected_index
if button == mouse.LEFT:
col = x // TILE_SIZE
row = (window.height - y) // HEIGHT_SIZE
clicked_index = row * NUM_TILES + col
if selected_index is None:
selected_index = clicked_index
else:
swap_tiles(selected_index, clicked_index)
selected_index = None
print(f"tile_indices in on_mouse_press: {tile_indices}")
swap_tiles関数でタイルの入れ替え処理を記述しており、ここではタイルそのものとタイルに紐づく番号をそれぞれのリストの中で交換します。
タイルの入れ替え操作は先ほどの”@window.event”デコレータの”on_mouse_press“イベントを使用します。
“on_mouse_press“イベントはマウスボタンが押された時に呼び出され、ここではクリックしたタイルの座標を記録しています。
1度目のクリック(移動したいタイルをクリック)ではselected_indexに座標を保存したまま終了します。
2度目のクリック(移動先のタイルをクリック)ではselected_indexに値が入っているため、swap_tile関数が実行され、タイルが入れ替えられるという仕組みになっています。
パズルゲーム実装
では実際パズルゲームを動かしてみましょう。
if __name__ == '__main__':
pyglet.app.run()
“pyglet.app.run()“でpygletアプリケーションが実行されます。
実際にタイルを移動してみましょう。
③の位置を⑧の位置にマウスをクリックして移動してみます(入れ替えてみます。)
ちゃんと入れ替わっているのがわかりますね。
printで出力している履歴にもちゃんと③から⑧の位置へタイルに紐づいた番号が入れ替わっているのが確認できます。
元の画像と同じ順番に並べ替えることが出来ると「正解」と表示されます。
Pythonでブロック崩しゲームを作る
つぎに2Dゲームで動きを取り入れたゲームを開発していきます。
今回は「ブロック崩しゲーム」を実装していきます。
ブロック崩しは以下のルールで作ります。
・ボールが直線状に動き、何かに当たったら跳ね返る
・ブロックに当たったら、そのブロックを消す(ブロック一つ+100点)
・下にボールが落ちたらゲームオーバー
・最後までブロックを崩せたらゲームクリア(クリアボーナスで+1000点)
・ゲームが終わったらスコアを表示する
今回のブロック崩しでは”Pygame“を使って実装していきます。
Pygameとは
“Pygame“はゲーム開発に特化したPythonライブラリです。
“Pygame“には以下の特徴があります。
・ゲーム開発に必要な機能を搭載:主に2Dゲーム開発で機能が充実している
・歴史が長くドキュメントが豊富:20年以上活用されていて、ドキュメントやサンプルコードが多い
・使いやすいAPI:直感的で初心者にもゲーム作成しやすい
Pygameの詳細については公式ドキュメントをチェックしてみて下さい。
初期設定
では実際にコードを書いていきます。
pip install pygame
まずPygameをインストールします。
つづいて、ブロック崩しゲーム全体のレイアウトを決めていきます。
import pygame
import sys
import time
# 初期化
pygame.init()
# 画面サイズ
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('ブロック崩し')
# 色の定義
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
blue = (0, 0, 255)
green = (0, 255, 0)
# フォント設定
font = pygame.font.Font(None, 36)
まず”pygame.init()“でPygameの各モジュールを初期化します。
これはPygameを使う上でのおまじないのようなもので、この初期化によってPygameのすべての機能が利用可能になります。
“pygame.display“モジュールでゲーム画面の作成・タイトル設定を行います。
各パーツの設定
つづいて、ボールやブロックといった各パーツを定義していきます。
# パドルの設定
paddle_width = 100
paddle_height = 10
paddle_speed = 10
paddle = pygame.Rect(screen_width // 2 - paddle_width // 2, screen_height - 30, paddle_width, paddle_height)
# ボールの設定
ball_radius = 10
ball_speed_x = 5
ball_speed_y = -5
ball = pygame.Rect(screen_width // 2, screen_height // 2, ball_radius * 2, ball_radius * 2)
# ブロックの設定
block_width = 60
block_height = 20
block_rows = 5
block_cols = 13
blocks = []
for row in range(block_rows):
block_row = []
for col in range(block_cols):
block_x = col * (block_width + 10) + 35
block_y = row * (block_height + 10) + 50
block = pygame.Rect(block_x, block_y, block_width, block_height)
block_row.append(block)
blocks.append(block_row)
各パーツで定義した内容を”pygame.Rect“クラスを使って画面上に描画します。
Pygameでは四角形の領域を作成・操作・処理を管理する際にRectオブジェクトを使用します。
ブロックは配列として格納することで、どのブロックが残っているかのブロックの管理を行っています。
ゲーム開始時の設定
次にゲーム開始時の設定を定義します。
# スコア
score = 0
game_won = False
# カウントダウンの表示
for i in range(3, 0, -1):
screen.fill(black)
countdown_text = font.render(f'Starting in {i}', True, white)
screen.blit(countdown_text, (screen_width // 2 - countdown_text.get_width() // 2, screen_height // 2 - countdown_text.get_height() // 2))
pygame.display.flip()
time.sleep(1)
通常、アプリ起動時にすぐにゲームが始まるため、今回ゲームが開始される前に3秒間待機時間を設定しています。
動作処理の設定
ではブロック崩しゲームの肝となる動作処理の部分を実装していきます。
# ゲームループ
running = True
game_over = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# パドルの操作
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and paddle.left > 0:
paddle.left -= paddle_speed
if keys[pygame.K_RIGHT] and paddle.right < screen_width:
paddle.right += paddle_speed
# ボールの移動
ball.x += ball_speed_x
ball.y += ball_speed_y
# 壁との衝突判定
if ball.left <= 0 or ball.right >= screen_width:
ball_speed_x = -ball_speed_x
if ball.top <= 0:
ball_speed_y = -ball_speed_y
if ball.bottom >= screen_height:
game_over = True # ボールが下に落ちたらゲームオーバー
# パドルとの衝突判定
if ball.colliderect(paddle):
ball_speed_y = -ball_speed_y
# ブロックとの衝突判定
for row in blocks:
for block in row:
if ball.colliderect(block):
ball_speed_y = -ball_speed_y
row.remove(block)
score += 100
break
“pygame.key“モジュールでPygameでのキーボード入力を処理できます。
その中で”pygame.key.get_pressed()“では、現在押されているキーの状態を取得できます。
今回は「←」「→」のキーが押された状態の時、パドルをその方向に動かす処理をしています。
ボールの衝突の判定では、衝突した方向と逆の方向にボールのベクトルを変更することで実現しています。
ブロックとボールが衝突した際はブロックを配列から削除し、スコアを加点します。
画面の描画
先ほどの動作処理の内容をゲーム画面に描画します。
# 画面の描画
screen.fill(black)
pygame.draw.rect(screen, blue, paddle)
pygame.draw.ellipse(screen, white, ball)
for row in blocks:
for block in row:
pygame.draw.rect(screen, green, block)
# スコアの表示
score_text = font.render(f'Score: {score}', True, white)
screen.blit(score_text, (10, 10))
# 画面外のブロックを削除
blocks = [[block for block in row if block.x <= screen_width] for row in blocks]
blocks = [row for row in blocks if row] # 空の行を削除
pygame.display.flip()
pygame.time.Clock().tick(60)
画面の描画には”pygame.draw“モジュールを使用します。
“pygame.draw.rect“関数や”pygame.draw.ellipse“関数を使って、ブロックやパドル、ボールを画面上に描画していきます。
また、ボールにブロックが当たりブロックが削除された際の画面の更新は”pygame.display.flip()“によって行われます。
画面の更新頻度は”pygame.time.Clock().tick(60)“で制御しており、今回は1秒間に60フレームに制限しています。
上記の制限値を上げることでより滑らかな挙動を表現できますが、その分PCのリソースを消費するため注意しましょう。
ゲーム終了時
最後にゲーム終了時の挙動について定義していきます。
# ブロックが全て消えたらゲームクリア
if not any(blocks):
score += 1000
game_over = True
game_won = True
if game_over:
running = False
ゲームのループの部分で、ボールが下に落ちる(スクリーンの株に衝突した場合)、もしくはブロックが全部削除された場合、game_overをTrueにして、ループを抜けます。
ループを抜けた後は、結果を表示の画面に描画します。
# ゲーム終了後のスコア表示とエンターキー待機
screen.fill(black)
final_score_text = font.render(f'Final Score: {score}', True, white)
exit_text = font.render('Press Enter to exit', True, white)
if game_won:
congrats_text = font.render('CONGRATULATIONS!', True, red)
screen.blit(congrats_text, (screen_width // 2 - congrats_text.get_width() // 2, screen_height // 2 - congrats_text.get_height() // 2 - 60))
screen.blit(final_score_text, (screen_width // 2 - final_score_text.get_width() // 2, screen_height // 2 - final_score_text.get_height() // 2 - 20))
screen.blit(exit_text, (screen_width // 2 - exit_text.get_width() // 2, screen_height // 2 - exit_text.get_height() // 2 + 20))
pygame.display.flip()
waiting_for_exit = True
while waiting_for_exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
waiting_for_exit = False
elif event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:
waiting_for_exit = False
pygame.quit()
終了時の画面には獲得したスコアとゲーム終了の合図を記載します。
またブロックを全部消した場合は「CONGRATULATIONS!」の文字列を追加します。
エンターキーが押されると”wating_for_exit”がTrueとなり、pygameが終了するという流れです。
このPythonコードを実行するとゲームがスタートし開始時の画面が立ち上がります。
Pygameを使うと各操作がモジュールで用意されているから記述がわかりやすい!
Pythonでゲーム開発 まとめ
Pythonでゲーム開発する方法について見ていきました。
おさらいするとPythonでゲーム開発するメリットは以下です。
・豊富なライブラリやフレームワーク
・マルチプラットフォーム対応
実際にいろんなサンプルを参考にしながら作ってみよう!
冒頭でも紹介しましたが、より詳しくPythonでゲームを作る方法を動画で学びたい方は以下のUdemy講座でお話していますのでぜひチェックしてみてください!
【初心者向け】Pythonでゲーム作りに挑戦!pygameを使ってpythonでブロック崩しゲームを作ってみよう!
【時間】 | 3時間 |
---|---|
【レベル】 | 初級 |
Pythonを使ってゲームを作ってみたいならこれ!今なら購入時に「VGRBCQDF」という講師クーポンコードを入れると94%OFFになりますのでぜひご受講ください!
ただし、Pythonはインタプリタ言語であり、コンパイル型言語(C#など)と比べると実行速度が遅いため、高パフォーマンスのゲームを開発したい場合はPython以外で作った方が良いので注意しましょう。
また、Pythonについて深く学習したい方は、当メディアが運営する教育サービス「スタアカ(スタビジアカデミー)」をチェックしてみてください。
AIデータサイエンス特化スクール「スタアカ」
【価格】 | ライトプラン:1280円/月 プレミアムプラン:149,800円 |
---|---|
【オススメ度】 | |
【サポート体制】 | |
【受講形式】 | オンライン形式 |
【学習範囲】 | データサイエンスを網羅的に学ぶ 実践的なビジネスフレームワークを学ぶ SQLとPythonを組み合わせて実データを使った様々なワークを行う マーケティングの実行プラン策定 マーケティングとデータ分析の掛け合わせで集客マネタイズ |
データサイエンティストとしての自分の経験をふまえてエッセンスを詰め込んだのがこちらのスタビジアカデミー、略して「スタアカ」!!
24時間以内の質問対応と現役データサイエンティストによる複数回のメンタリングを実施します!
カリキュラム自体は、他のスクールと比較して圧倒的に良い自信があるのでぜひ受講してみてください!
他のスクールのカリキュラムはPythonでの機械学習実装だけに焦点が当たっているものが多く、実務に即した内容になっていないものが多いです。
そんな課題感に対して、実務で使うことの多いSQLや機械学習のビジネス導入プロセスの理解なども合わせて学べるボリューム満点のコースになっています!
Pythonが初めての人でも学べるようなカリキュラムしておりますので是非チェックしてみてください!
ウォルマートのデータを使って商品の予測分析をしたり、実務で使うことの多いGoogleプロダクトのBigQueryを使って投球分析をしたり、データサイエンティストに必要なビジネス・マーケティングの基礎を学んでマーケティングプランを作ってもらったり・Webサイト構築してデータ基盤構築してWebマーケ×データ分析実践してもらったりする盛りだくさんの内容になってます!
・BigQuery上でSQL、Google Colab上でPythonを使い野球の投球分析
・世界最大手小売企業のウォルマートの実データを用いた需要予測
・ビジネス・マーケティングの基礎を学んで実際の企業を題材にしたマーケティングプランの策定
・Webサイト構築してデータ基盤構築してWebマーケ×データ分析実践して稼ぐ