もどる

この記事は「うずら」とAIが協力して作成しました。
なるべく正確さを心がけていますが、最新の公式ドキュメントなどもあわせて確認してみてね!

python2026.3.6

3-3. 輝く銀河:リスト(list)で星空を描画せよ

リスト魔法
星空の実装

1. 3秒でわかるまとめ

今回のゴールは、Pythonの リスト(list) を活用して、Pyxelの画面に複数の星を描画し、キラキラと輝く星空の背景を作り出すことです。

画面   [星][星][星][星]
       [星][星][星][星]
       [星][星][星][星]
リストにたくさんの星の情報を入れて、
一つずつ描画していきます。

2. なぜ星空にリストが必要なのか

前回、私たちは宇宙に飛び立つ自機を動かせるようになりましたね!

しかし、今の宇宙は真っ暗なだけです。
広大な宇宙には、たくさんの星が輝いています。これでは少し寂しいですよね。

もし、画面に星を一つだけ描くなら、座標を一つ覚えておけば十分です。

star_x = 50
star_y = 30
pyxel.pset(star_x, star_y, pyxel.COL_WHITE)

でも、星を10個、20個、あるいは100個描きたい場合はどうでしょうか?
star_x_1, star_y_1, star_x_2, star_y_2... といった変数を、星の数だけ用意するのは大変です。

ここで登場するのが、Pythonの「リスト(list)」です。
データの箱リスト配列 で学んだように、リストは複数のデータを一つにまとめて管理できる魔法の箱でした。
星の情報をリストにまとめて入れることで、たくさんの星を効率よく扱えるようになります。

豆知識

ゲーム開発では、複数の敵、弾丸、パーティクルなど、同じ種類のオブジェクトが大量に登場することがよくあります。
リストは、これらの「群れ」を管理する上で最も基本的なデータ構造です。

3. たくさんの星を準備しよう:リストに情報を追加する

まずは、星の情報をリストに用意するところから始めましょう。
星の情報として、今回は以下の3つを持たせることにします。

  • x 座標:星が画面のどこにあるか
  • y 座標:星が画面のどこにあるか
  • speed:星がどのくらいの速さで動くか(後でスクロールに利用します)

これらの情報を、星の数だけ stars というリストに格納します。

3-1. stars リストの準備

前回のコードに、星を格納するためのリストと、その初期値を設定する部分を追加します。

import pyxel
import random # ① randomモジュールを追加

# ... (中略) ...

# --- 定数設定 ---
SCREEN_WIDTH = 160
SCREEN_HEIGHT = 120
GAME_TITLE = "ASTRO SURVIVOR"
STAR_COUNT = 40 # ② 星の数を定義

# ... (中略) ...

# --- 変数の初期化 ---
# プレイヤー
player_x = SCREEN_WIDTH // 2 - PLAYER_W // 2
player_y = SCREEN_HEIGHT - 20

# ゲームオブジェクトのリスト
stars     = [] # ③ [x, y, speed] を格納する空のリスト

# 星空の準備(ゲーム開始時に一度だけ実行)
# STAR_COUNT の数だけ星を作る
for _ in range(STAR_COUNT): # ④ STAR_COUNTの回数だけループ
    stars.append([
        random.randint(0, SCREEN_WIDTH), # x座標をランダムに
        random.randint(0, SCREEN_HEIGHT), # y座標をランダムに
        random.randint(1, 3) # 星の速さ (1~3) をランダムに
    ])

追加された主な変更点は次の通りです。

  • import random: 星の初期位置をランダムに決めるために、random モジュールをインポートします。
  • STAR_COUNT = 40: 定数として星の数を定義します。
  • stars = []: 星の情報を格納する空のリスト stars を作成します。
  • for _ in range(STAR_COUNT):: STAR_COUNT の回数だけループを回し、星を一つずつリストに追加します。
  • stars.append([x, y, speed]): append メソッドを使って、[x, y, speed] という形式のリストを stars リストの中に追加します。
    • random.randint(0, SCREEN_WIDTH): 画面の横幅内でランダムな x 座標を生成します。
    • random.randint(0, SCREEN_HEIGHT): 画面の高さ内でランダムな y 座標を生成します。
    • random.randint(1, 3): 星の速さを1から3の間のランダムな値にします。これは後で遠近感のあるスクロールに使います。

補足だよ

for _ in range(STAR_COUNT):_ (アンダースコア) は、ループ変数を使わないときに慣習的に使われます。このループでは、単に STAR_COUNT 回繰り返すだけで、現在のループの回数自体は必要ありません。

3-2. draw 関数で星を描画する

stars リストに星の情報が準備できたら、次は draw 関数でそれらの星を実際に画面に描画します。

# 毎フレーム実行される描画処理 (結果を画面に表示する。計算はしない)
def draw():
    pyxel.cls(COL_BLACK)
    
    # 背景の星を描画
    for star in stars: # リストの各星を順番に取り出す
        # star は [x, y, speed] のリスト
        x = star[0] # x座標
        y = star[1] # y座標
        speed = star[2] # speed

        # speed に応じて星の色を変える(遠くの星は暗く)
        color = COL_WHITE if speed > 1 else COL_GRAY
        
        pyxel.pset(x, y, color) # 1ドットの星を描画

    # プレイヤー
    pyxel.rect(player_x, player_y, PLAYER_W, PLAYER_H, COL_ORANGE)
    pyxel.rect(player_x+3, player_y-2, 2, 2, COL_YELLOW)

変更点を見てみましょう。

  • for star in stars:: stars リストの中にある個々の星の情報を、star という変数に一つずつ取り出してループ処理します。
    • star は、例えば [50, 30, 2] のような [x, y, speed] の形式のリストです。
  • x = star[0], y = star[1], speed = star[2]: リストのインデックスを使って、星の x, y 座標と speed を取り出します。
  • color = COL_WHITE if speed > 1 else COL_GRAY: speed の値によって星の色を変えています。
    • speed1 より大きい(つまり 23)なら COL_WHITE (白)。
    • それ以外(speed1)なら COL_GRAY (灰色) になります。これにより、星に少し濃淡が生まれます。
  • pyxel.pset(x, y, color): Pyxelの pset 関数を使って、指定された x, y 座標に color で1ドットの点を描画します。これが星になります。

この時点でのコードを実行すると、画面いっぱいにランダムな白い星が描画されるはずです!
まだ星は動きませんが、宇宙の背景が賑やかになりましたね。

4. 星空を流れるように動かそう!

せっかく宇宙空間にいるのですから、星は流れていくように見せたいですよね。
そのためには、update 関数の中で、各星の y 座標を毎フレーム少しずつ変化させる必要があります。

# 毎フレーム実行される更新処理 (計算などはここで行う。描画は禁止)
def update():
    global player_x, player_y

    # --- 3. プレイヤー操作 ---
    if pyxel.btn(pyxel.KEY_LEFT):  player_x = max(player_x - PLAYER_SPEED, 0)
    if pyxel.btn(pyxel.KEY_RIGHT): player_x = min(player_x + PLAYER_SPEED, SCREEN_WIDTH - PLAYER_W)
    if pyxel.btn(pyxel.KEY_UP):    player_y = max(player_y - PLAYER_SPEED, 0)
    if pyxel.btn(pyxel.KEY_DOWN):  player_y = min(player_y + PLAYER_SPEED, SCREEN_HEIGHT - PLAYER_H)

    # --- 4. 星を動かす ---
    for star in stars: # リストの各星を順番に取り出す
        star[1] += star[2] # y座標にspeedを加算

        # 画面外に出たら上に戻す
        if star[1] > SCREEN_HEIGHT:
            star[0] = random.randint(0, SCREEN_WIDTH) # x座標はランダムに
            star[1] = 0 # 画面の上端に戻す

追加された --- 4. 星を動かす --- の部分を見ていきましょう。

  • for star in stars:: ここでも stars リストをループし、各 star の情報を更新します。
  • star[1] += star[2]:
    • star[1] は星の y 座標です。
    • star[2] は星の speed です。
    • この行で、星の y 座標にその星の speed を加算しています。これにより、speed が大きい星ほど速く下に移動し、遠近感が生まれます。
  • if star[1] > SCREEN_HEIGHT::
    • 星が画面の下端 (SCREEN_HEIGHT) を超えて移動してしまった場合の処理です。
    • star[0] = random.randint(0, SCREEN_WIDTH): 画面の上に戻す際、新しい x 座標をランダムに設定します。
    • star[1] = 0: 星を画面の最上部 (y=0) に戻します。

これで、星が画面を上から下へ、それぞれの速度で流れていくように見えます。
画面の下から消えた星が、また画面の上からランダムな位置に現れることで、途切れることのない星空のスクロールが実現されます。

豆知識

背景スクロールの仕組み
ゲームの背景スクロールは、このように画面外に出たオブジェクトを反対側に戻すことで、無限に続くように見せるテクニックがよく使われます。 これはメモリを節約し、無限にオブジェクトを生成しなくて済む効率的な方法です。

5. 完成コードを動かしてみよう!

これで、自機が動く宇宙空間に、キラキラと流れる星空が追加されました。
今回のコードをまとめて、実際に動かしてみましょう!

import pyxel
import random

# =========================================================
#  ASTRO SURVIVOR
#  - 宇宙シューティングゲーム -
# =========================================================

# --- 定数設定 ---
SCREEN_WIDTH = 160
SCREEN_HEIGHT = 120
GAME_TITLE = "ASTRO SURVIVOR"
STAR_COUNT = 40

# キャラクターのサイズ
PLAYER_W = 8
PLAYER_H = 8
PLAYER_SPEED = 3

# 色の定義
COL_BLACK   = 0
COL_NAVY    = 1
COL_PURPLE  = 2
COL_GREEN   = 3
COL_BROWN   = 4
COL_DBLUE   = 5
COL_LBLUE   = 6
COL_WHITE   = 7
COL_RED     = 8
COL_ORANGE  = 9
COL_YELLOW  = 10
COL_L_GREEN = 11
COL_CYAN    = 12
COL_GRAY    = 13
COL_PINK    = 14
COL_PEACH   = 15


# --- Pyxelの初期化と音の定義 ---
pyxel.init(SCREEN_WIDTH, SCREEN_HEIGHT, title=GAME_TITLE)

# --- 変数の初期化 ---
# プレイヤー
player_x = SCREEN_WIDTH // 2 - PLAYER_W // 2
player_y = SCREEN_HEIGHT - 20

# ゲームオブジェクト
stars     = [] # [x, y, speed]

# 星空の準備
for _ in range(STAR_COUNT):
    stars.append([
        random.randint(0, SCREEN_WIDTH),
        random.randint(0, SCREEN_HEIGHT),
        random.randint(1, 3)
    ])


# =========================================================
#  メインループ (Update & Draw)
# =========================================================

# 毎フレーム実行される更新処理 (計算などはここで行う。描画は禁止)
def update():
    global player_x, player_y

    # --- 3. プレイヤー操作 ---
    if pyxel.btn(pyxel.KEY_LEFT):  player_x = max(player_x - PLAYER_SPEED, 0)
    if pyxel.btn(pyxel.KEY_RIGHT): player_x = min(player_x + PLAYER_SPEED, SCREEN_WIDTH - PLAYER_W)
    if pyxel.btn(pyxel.KEY_UP):    player_y = max(player_y - PLAYER_SPEED, 0)
    if pyxel.btn(pyxel.KEY_DOWN):  player_y = min(player_y + PLAYER_SPEED, SCREEN_HEIGHT - PLAYER_H)

    # --- 4. 星を動かす ---
    for star in stars:
        star[1] += star[2] # y座標にspeedを加算

        # 画面外に出たら上に戻す
        if star[1] > SCREEN_HEIGHT:
            star[0] = random.randint(0, SCREEN_WIDTH) # x座標はランダムに
            star[1] = 0 # 画面の上端に戻す


# 毎フレーム実行される描画処理 (結果を画面に表示する。計算はしない)
def draw():
    pyxel.cls(COL_BLACK)
    
    # 背景
    for star in stars:
        pyxel.pset(star[0], star[1], COL_WHITE if star[2] > 1 else COL_GRAY)

    # プレイヤー
    pyxel.rect(player_x, player_y, PLAYER_W, PLAYER_H, COL_ORANGE)
    pyxel.rect(player_x+3, player_y-2, 2, 2, COL_YELLOW)


pyxel.run(update, draw)

上記のコードを実際にブラウザで動かしてみてください。

実際に動かしてみよう!

矢印キーで宇宙船を操作できます。星が流れていきます!

どうでしょうか?
画面いっぱいに星が流れ、宇宙を航行している気分が味わえるようになりましたね!

今回はリストを使ってたくさんの星を管理し、それらを動かすことで、ゲームの背景を魅力的に演出しました。
リストは、このように「同じ種類のものが複数ある」場合に非常に強力なツールとなります。

次回は、このリストの力をさらに活用して、自機から発射される弾丸を実装していきます。
次回、リスト魔法バスター発射お楽しみに!

最後まで読んでくれてありがとう!🌱
ノートみたいに、いつでも見返してね。