「Pythonでゲームを作ってみたい。でも、何から勉強すればいいの?」
「ゲーム用のライブラリの解説を読んだけど、コードの意味がほとんど分からなかった…」

こんな悩み、ありますよね。実はゲームのプログラムは、特別な魔法でできているわけではありません。中身を分解すると、入門で習う変数・if文・for文・リスト・関数の組み合わせです。

この記事では、ゲームの仕組みを「動かす→描く」「リストで管理」「if文で当たり判定」の3つに分けて、Pythonの標準機能だけで1つずつ動かしてみます。最後に、それを組み合わせたミニシューティング(文字だけ版)も作ります。対象は、Pythonを始めたばかり〜文法をひととおり読んだ方です。一緒に見ていきましょう!

ゲームは「動かす → 描く」のくり返し

retro arcade game
retro arcade game / Photo by James Collington via Pexels

アクションゲームの画面は、パラパラ漫画と同じです。1コマごとに、

  1. 動かす:キャラクターや敵の位置(数字)を更新する
  2. 描く:今の位置で画面を描き直す

を高速にくり返しています。この「くり返し」をゲームループと呼びます。イメージとしては、1秒間に何十回も for 文や while 文が回っている感じです。

まずは横に5マスの画面で、キャラクター(@)を左右に往復させてみます。

# ゲームの基本:「動かす → 描く」をくり返す
WIDTH = 5    # 画面の横幅(マスの数)
x = 0        # キャラクターの位置
dx = 1       # 1回に動く量(右向き)

for frame in range(1, 9):
    # ① 動かす:位置を更新する
    x = x + dx
    if x == WIDTH - 1 or x == 0:   # 端に着いたら向きを反転
        dx = -dx

    # ② 描く:今の位置で画面を作り直す
    screen = ["."] * WIDTH
    screen[x] = "@"
    print(f"{frame}コマ目: {''.join(screen)}")
キャラクターが端で反転しながら往復する
キャラクターが端で反転しながら往復する

ポイントをまとめるとこんな感じです👇

  • キャラクターの位置は、ただの変数 x(数字)
  • 「動かす」は x = x + dx の足し算。dx を -dx にすると逆向きに進む
  • 「端に着いたら反転」は if文
  • 「描く」は、リスト screen を毎回作り直して print しているだけ

本物のゲームでは print の代わりにウィンドウへ絵を描きますが、「位置を数字で持って、足し算で動かして、毎コマ描き直す」という考え方はまったく同じです。

敵や弾は「リスト」で管理する

シューティングゲームでは、画面に弾が何十発も飛んでいますよね。1発ごとに変数を作っていたらキリがありません。そこで使うのがリストです。

弾のy座標(上下の位置。0が画面のいちばん上)をリストに入れて、毎コマ「撃つ → 全部動かす → 画面の外に出たものを消す」をくり返します。

# 弾は「リスト」でまとめて管理する
bullets = []          # 画面にある弾のy座標(0が画面のいちばん上)

for frame in range(1, 6):
    bullets.append(6)                         # 毎コマ、y=6(自機の位置)から1発撃つ
    bullets = [y - 2 for y in bullets]        # 全部の弾を上に2マス動かす
    bullets = [y for y in bullets if y >= 0]  # 画面の外に出た弾は消す
    print(f"{frame}コマ目: 弾 {len(bullets)}発 → {bullets}")

実行結果:

1コマ目: 弾 1発 → [4]
2コマ目: 弾 2発 → [2, 4]
3コマ目: 弾 3発 → [0, 2, 4]
4コマ目: 弾 3発 → [0, 2, 4]
5コマ目: 弾 3発 → [0, 2, 4]

ここが重要です👇

  • append で弾を増やす
  • [y - 2 for y in bullets] で全部の弾をまとめて動かす(リスト内包表記。for文で1つずつ書き換えても同じです)
  • [y for y in bullets if y >= 0] で画面の外に出た弾を消す

3コマ目からは、撃つ1発と消える1発がつり合って、画面の弾が3発のまま一定になっていますね。敵キャラも同じで、「敵のリスト」に出現・移動・消滅を書けば、何体いても同じコードで動きます。

当たり判定は「if文」

「弾が敵に当たったか」は、2つの四角形が重なっているかを調べるだけです。それぞれの位置(x, y)と大きさ(幅 w・高さ h)を辞書で持って、関数にまとめます。

# 当たり判定は「if文」:2つの四角が重なっているか調べる
def is_hit(a, b):
    return (a["x"] < b["x"] + b["w"] and b["x"] < a["x"] + a["w"] and
            a["y"] < b["y"] + b["h"] and b["y"] < a["y"] + a["h"])

bullet = {"x": 12, "y": 30, "w": 2, "h": 6}
enemies = [
    {"name": "スライム", "x": 10, "y": 28, "w": 8, "h": 8},
    {"name": "コウモリ", "x": 40, "y": 10, "w": 8, "h": 8},
]

for enemy in enemies:
    if is_hit(bullet, enemy):
        print(f"{enemy['name']}に命中!")
    else:
        print(f"{enemy['name']}には当たっていない")

実行結果:

スライムに命中!
コウモリには当たっていない

条件が長く見えますが、やっていることは「左右で重なっている、かつ、上下で重なっている」の2つです。

  • a["x"] < b["x"] + b["w"]:aの左端が、bの右端より左にある
  • b["x"] < a["x"] + a["w"]:bの左端が、aの右端より左にある
  • この2つが両方 True なら左右で重なっている。上下(y と h)も同じ考え方

これ、実行せずに答えられますか? 弾の x を 12 から 30 に変えると、スライムには当たらなくなります。数字を変えて試してみると、当たり判定の感覚がつかめますよ。

組み合わせると「ミニシューティング」になる

ここまでの3つを組み合わせて、文字だけのミニシューティングを作ってみます。キーボードで操作する代わりに、自機(A)が自動で敵(V)の真下へ移動して撃つようにしました。

# 変数・リスト・for・if・関数だけで作る「ミニシューティング」(自動で遊ぶ版)
W, H = 7, 6                  # 画面の幅と高さ(マス)
player_x = 3                 # 自機の位置(いちばん下の行)
bullets = []                 # 弾 [x, y] のリスト
enemies = [[1, 0], [5, 1]]   # 敵 [x, y] のリスト
score = 0

def draw():
    rows = [["."] * W for _ in range(H)]
    for x, y in enemies:
        rows[y][x] = "V"
    for x, y in bullets:
        rows[y][x] = "|"
    rows[H - 1][player_x] = "A"
    for row in rows:
        print("".join(row))

for frame in range(1, 12):
    # ① 動かす:自機はいちばん下にいる敵の真下へ1マス近づき、真下に来たら撃つ
    if enemies:
        target = max(enemies, key=lambda e: e[1])[0]
        if target > player_x:
            player_x += 1
        elif target < player_x:
            player_x -= 1
        else:
            bullets.append([player_x, H - 1])
    bullets = [[x, y - 1] for x, y in bullets if y - 1 >= 0]   # 弾は毎コマ上へ1マス
    if frame % 3 == 0:
        enemies = [[x, y + 1] for x, y in enemies]               # 敵は3コマに1回、下へ1マス

    # ② 当たり判定:弾と敵が同じマスなら両方消してスコア加算
    for b in bullets[:]:
        if b in enemies:
            bullets.remove(b)
            enemies.remove(b)
            score += 100
            print(f"{frame}コマ目: x={b[0]}, y={b[1]} で命中! スコア {score}")

print("--- 11コマ目の画面 ---")
draw()
print("残りの敵:", len(enemies), "体 / スコア:", score)
ミニシューティングの実行結果(11コマ分)
ミニシューティングの実行結果(11コマ分)

使っている文法を並べると、こうなります👇

ゲームの部品 使っている文法
画面の大きさ・自機の位置・スコア 変数
弾と敵(何個あってもOK) リスト(リストの中に [x, y] のリスト)
1コマずつ進める(ゲームループ) for文
敵の方へ動く・真下で撃つ・命中したか if文
画面を描く 関数(def draw())

どれも、入門で最初に習う文法ばかりですよね。ゲームを作るための特別な文法は、ひとつも使っていません。

ゲームを作りたいなら、まず何を身につける?

ここまで見てきたとおり、ゲームづくりで毎回使うのは次の文法です。

  1. 変数と計算:位置・速さ・スコアを数字で持って、足し算で動かす
  2. if文:端で反転する、当たったら消す、スコアが目標を超えたらクリア
  3. for文・while文:ゲームループ、敵を1体ずつ調べる
  4. リストと辞書:敵・弾・アイテムをまとめて管理する
  5. 関数:「当たり判定」「描く」など、何度も使う処理に名前をつける

画面にウィンドウを出して絵を描く部分は、ゲーム用のライブラリが担当してくれます。ただ、ライブラリが助けてくれるのは「描く」「キーを読む」ところまで。何をどう動かすかを書くのは、結局この5つの文法です。

逆に言えば、ライブラリの解説を読んで分からなかったのは、ライブラリが難しいからではなく、リストやif文がまだ手になじんでいなかっただけということが多いんです。急がば回れで、まず文法を「自分で書ける」ところまで固めるのが、いちばんの近道ですよ。

まとめ

  • ゲームは「動かす(位置を足し算で更新)→ 描く」のくり返し。これがゲームループ
  • 敵や弾はリストで管理する。増やす・まとめて動かす・消すの3つでOK
  • 当たり判定は、四角形が重なっているかを調べるif文
  • 変数・if文・for文・リスト・関数だけで、ミニシューティングが動く
  • ゲームを作りたいなら、まずこの5つの文法を自分で書けるところまで身につけるのが近道

今回のコードは、すべてPythonの標準機能だけで動きます。数字を変えたり、敵を増やしたりして、ぜひ遊びながら試してみてください🚀

\ Pythonでゲームを作りたい方へ /

筆者はいま、入門を終えた人向けに、画面の中でキャラクターが動き、キーボードで操作するゲームを作るコースを制作中です。その土台になる基本文法は、無料の入門コース「作って学ぶPythonプログラミング入門」(全7章52レッスン)で、数当てゲームやじゃんけんを作りながら身につけられます。無料登録された方には、ゲームコースの公開を最初にメールでお知らせします。

→ 無料の入門コースに登録しておく

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る
徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

もしも

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

電子工作とプログラミングを同時に学べる

Amazonで見る
実践Claude Code入門―現場で活用するためのAIコーディングの思考法

もしも

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

AIコーディングの現場活用法を学ぶ一冊

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。