Cocos2d を使ってみる

1. エグゼクティブサマリー

Cocos2d は2次元ゲームのフレームワークであり,Python で動作する. (Cocos2d から派生した Cocos2d-x は iOS や Android でも動き,普及している.)

このWebページでは,次の基本的なことを,見本プログラムで演習する.

関連する資料:Cocos2d の概要 [PDF], [パワーポイント]

関連する資料:ゲームエンジン[PDF], [パワーポイント]

関連する資料:Cocos2d のイベントハンドラ,アクション

関連する外部ページhttps://www.cocos.com/endoc.html

2. 前準備(必要ソフトウェアの入手)

ここでは、最低限の事前準備について説明する。機械学習や深層学習を行う場合は、NVIDIA CUDA、Visual Studio、Cursorなどを追加でインストールすると便利である。これらについては別ページ https://www.kkaneko.jp/cc/dev/aiassist.htmlで詳しく解説しているので、必要に応じて参照してください。

Python 3.12 のインストール(Windows 上) [クリックして展開]

以下のいずれかの方法で Python 3.12 をインストールする。Python がインストール済みの場合、この手順は不要である。

方法1:winget によるインストール

管理者権限コマンドプロンプトで以下を実行する。管理者権限のコマンドプロンプトを起動するには、Windows キーまたはスタートメニューから「cmd」と入力し、表示された「コマンドプロンプト」を右クリックして「管理者として実行」を選択する。

winget install --scope machine --id Python.Python.3.12 -e --silent --disable-interactivity --force --accept-source-agreements --accept-package-agreements --override "/quiet InstallAllUsers=1 PrependPath=1 Include_pip=1 Include_test=0 Include_launcher=1 InstallLauncherAllUsers=1"

--scope machine を指定することで、システム全体(全ユーザー向け)にインストールされる。このオプションの実行には管理者権限が必要である。インストール完了後、コマンドプロンプトを再起動すると PATH が自動的に設定される。

方法2:インストーラーによるインストール

  1. Python 公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンから Windows 用インストーラーをダウンロードする。
  2. ダウンロードしたインストーラーを実行する。
  3. 初期画面の下部に表示される「Add python.exe to PATH」に必ずチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから python コマンドを実行できない。
  4. 「Install Python 3.xx for all users」にチェックを入れ、「Install」をクリックする。

インストールの確認

コマンドプロンプトで以下を実行する。

python --version

バージョン番号(例:Python 3.12.x)が表示されればインストール成功である。「'python' は、内部コマンドまたは外部コマンドとして認識されていません。」と表示される場合は、インストールが正常に完了していない。

AIエディタ Windsurf のインストール(Windows 上) [クリックして展開]

Pythonプログラムの編集・実行には、AIエディタの利用を推奨する。ここでは、Windsurfのインストールを説明する。Windsurf がインストール済みの場合、この手順は不要である。

管理者権限コマンドプロンプトで以下を実行する。管理者権限のコマンドプロンプトを起動するには、Windows キーまたはスタートメニューから「cmd」と入力し、表示された「コマンドプロンプト」を右クリックして「管理者として実行」を選択する。

winget install --scope machine --id Codeium.Windsurf -e --silent --disable-interactivity --force --accept-source-agreements --accept-package-agreements --custom "/SP- /SUPPRESSMSGBOXES /NORESTART /CLOSEAPPLICATIONS /DIR=""C:\Program Files\Windsurf"" /MERGETASKS=!runcode,addtopath,associatewithfiles,!desktopicon"
powershell -Command "$env:Path=[System.Environment]::GetEnvironmentVariable('Path','Machine')+';'+[System.Environment]::GetEnvironmentVariable('Path','User'); windsurf --install-extension MS-CEINTL.vscode-language-pack-ja --force; windsurf --install-extension ms-python.python --force; windsurf --install-extension Codeium.windsurfPyright --force"

--scope machine を指定することで、システム全体(全ユーザー向け)にインストールされる。このオプションの実行には管理者権限が必要である。インストール完了後、コマンドプロンプトを再起動すると PATH が自動的に設定される。

関連する外部ページ

Windsurf の公式ページ: https://windsurf.com/

必要なライブラリのインストール [クリックして展開]

管理者権限コマンドプロンプトで以下を実行する。管理者権限のコマンドプロンプトを起動するには、Windows キーまたはスタートメニューから「cmd」と入力し、表示された「コマンドプロンプト」を右クリックして「管理者として実行」を選択する。

pip install -U cocos2d pyglet

Windows での cocos2d, pyglet のインストールの詳細は,別ページ »で説明している.

3. 実行のための準備とその確認手順(Windows 前提)

3.1 プログラムファイルの準備

第5章に掲載するソースコードをテキストエディタ(メモ帳,spyder 等)に貼り付け,以下のファイル名で保存する(文字コード:UTF-8).

ファイル名内容
text_display.pyテキスト表示
keyboard_event.pyキーボードのイベント
mouse_event.pyマウスのイベント
layer_switch.py画面切り替え(画面のレイヤ分け)

3.2 実行コマンド

コマンドプロンプトでファイルの保存先ディレクトリに移動し,以下を実行する.

python text_display.py
python keyboard_event.py
python mouse_event.py
python layer_switch.py

3.3 動作確認チェックリスト

確認項目期待される結果
text_display.py の起動時640x480 のウィンドウが開き,「Hello,World!」が画面中央付近(座標 400, 240)に表示される
keyboard_event.py でキーを押す押されているキーの名前が「Keys: 」に続いて画面に表示される.タイトルバーに押下中のキー数が表示される
keyboard_event.py で複数のキーを同時に押す同時に押されている全キーの名前がカンマ区切りで表示される
keyboard_event.py でキーを離す離したキーの名前が表示から消える
mouse_event.py でマウスを動かす「Mouse is at x,y」の形式でマウス座標が表示される
mouse_event.py でマウスボタンを押すラベルの表示位置がクリック座標に移動する
mouse_event.py でマウスをドラッグするドラッグ中もマウス座標の表示が更新される
layer_switch.py の起動時紫色の背景(Layer00)が表示され,タイトルバーに「Current: Layer00」と表示される
layer_switch.py でキーを押すLayer00(紫)と Layer01(赤)が切り替わり,タイトルバーも連動して変わる
各プログラムの終了右上の「x」をクリックするとプログラムが終了する

4. 概要・使い方・実行上の注意

4.1 テキスト表示

結果を確認したら,右上の「x」をクリックして終了する.

* 演習問題: 「Hello World!」のところを書き換えて,表示されるテキストを変えてみなさい.実行ボタンを押して確認すること.

* 演習問題: 「font_size = 32」のところを書き換えて,フォントサイズを変えてみなさい.実行ボタンを押して確認すること.

4.2 キーボードのイベント

キーの押下・解放イベントが発生すると,self.keys_being_pressedに「現在押されているキー(複数可)」の情報が格納される.

キーの押下と解放を試す.複数のキーの同時押下も試す.タイトルバーに現在押されているキーの数が表示される.

結果を確認したら,右上の「x」をクリックして終了する.

* 演習問題: 上の手順を行いなさい.

4.3 マウスのイベント

マウスの移動やボタンの押下を試す.

結果を確認したら,右上の「x」をクリックして終了する.

* 演習問題: 上の手順を行いなさい.

4.4 画面切り替え(画面のレイヤ分け)

キーを押して画面の切り替わりを確認する.タイトルバーに現在のレイヤ名が表示される.

結果を確認したら,右上の「x」をクリックして終了する.

* 演習問題: 上の手順を行いなさい.

5. ソースコード

5.1 テキスト表示(text_display.py)

import cocos
from cocos import scene
from cocos.layer import Layer
from cocos.director import director

class MyActor(cocos.text.Label):
    def __init__(self, text, x, y, size, rgba):
        super().__init__(
            text,
            font_name="Times New Roman",
            font_size=size,
            anchor_x='center',
            anchor_y='center',
            color=rgba
        )
        self.position = cocos.euclid.Vector2(x, y)

class Layer00(Layer):
    is_event_handler = True
    def __init__(self):
        super().__init__()
        self.myactor = MyActor("Hello,World!", 400, 240, 32, (0, 200, 255, 255))
        self.add(self.myactor)

director.init(width=640, height=480)
director.run(scene.Scene(Layer00()))

5.2 キーボードのイベント(keyboard_event.py)

import cocos
from cocos import scene
from cocos.layer import Layer
from cocos.director import director
from pyglet.window import key

class MyActor(cocos.text.Label):
    def __init__(self, text, x, y, size, rgba):
        super().__init__(
            text,
            font_name="Times New Roman",
            font_size=size,
            anchor_x='center',
            anchor_y='center',
            color=rgba
        )
        self.position = cocos.euclid.Vector2(x, y)

class Layer00(Layer):
    is_event_handler = True

    def __init__(self):
        super().__init__()
        self.myactor = MyActor("Hello,World!", 400, 240, 32, (0, 200, 255, 255))
        self.keys_being_pressed = set()
        self.update_text()
        self.add(self.myactor)

    def update_text(self):
        key_names = [key.symbol_string(k) for k in self.keys_being_pressed]
        self.myactor.element.text = "Keys: " + ", ".join(key_names)
        director.window.set_caption("Pressed: %d keys" % len(self.keys_being_pressed))

    def on_key_press(self, key, modifiers):
        self.keys_being_pressed.add(key)
        self.update_text()

    def on_key_release(self, key, modifiers):
        self.keys_being_pressed.discard(key)
        self.update_text()

director.init(width=640, height=480)
director.run(scene.Scene(Layer00()))

5.3 マウスのイベント(mouse_event.py)

import cocos
from cocos import scene
from cocos.layer import Layer
from cocos.director import director

class MyActor(cocos.text.Label):
    def __init__(self, text, x, y, size, rgba):
        super().__init__(
            text,
            font_name="Times New Roman",
            font_size=size,
            anchor_x='center',
            anchor_y='center',
            color=rgba
        )
        self.position = cocos.euclid.Vector2(x, y)

class Layer00(Layer):
    is_event_handler = True

    def __init__(self):
        super().__init__()
        self.position_x = 0
        self.position_y = 0
        self.myactor = MyActor("Hello,World!", 0, 0, 32, (0, 200, 255, 255))
        self.add(self.myactor)

    def update_text(self, mouse_x_pos, mouse_y_pos):
        self.myactor.element.text = 'Mouse is at %d,%d' % (mouse_x_pos, mouse_y_pos)
        self.myactor.x = self.position_x
        self.myactor.y = self.position_y

    def on_mouse_motion(self, x, y, dx, dy):
        self.update_text(x, y)

    def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
        self.update_text(x, y)

    def on_mouse_press(self, x, y, buttons, modifiers):
        self.position_x, self.position_y = director.get_virtual_coordinates(x, y)
        self.update_text(x, y)

director.init(width=640, height=480)
director.run(scene.Scene(Layer00()))

5.4 画面切り替え(layer_switch.py)

import cocos
from cocos import scene
from cocos.layer import ColorLayer
from cocos.director import director

class MyActor(cocos.text.Label):
    def __init__(self, text, x, y, size, rgba):
        super().__init__(
            text,
            font_name="Times New Roman",
            font_size=size,
            anchor_x='center',
            anchor_y='center',
            color=rgba
        )
        self.position = cocos.euclid.Vector2(x, y)

class Layer00(ColorLayer):
    is_event_handler = True

    def __init__(self):
        super().__init__(155, 89, 182, 1000)
        self.myactor = MyActor("Layer00", 400, 240, 32, (0, 200, 255, 255))
        self.add(self.myactor)
        director.window.set_caption("Current: Layer00")

    def on_key_press(self, key, modifiers):
        director.replace(scene.Scene(Layer01()))

class Layer01(ColorLayer):
    is_event_handler = True

    def __init__(self):
        super().__init__(231, 76, 60, 1000)
        self.myactor = MyActor("Layer01", 400, 240, 32, (0, 200, 255, 255))
        self.add(self.myactor)
        director.window.set_caption("Current: Layer01")

    def on_key_press(self, key, modifiers):
        director.replace(scene.Scene(Layer00()))

director.init(width=640, height=480)
director.run(scene.Scene(Layer00()))

6. まとめ

6.1 レイヤのクラス定義

Layer クラスまたは ColorLayer クラスを継承してレイヤを定義する.レイヤはシーンの構成単位であり,is_event_handler = True を設定することでイベントを受け取れる.

6.2 ゲームの登場物のクラス定義

cocos.text.Label を継承した MyActor クラスにより,テキスト,フォント,サイズ,色,座標を指定してラベルを生成する.element.text プロパティにより,実行中にラベルの表示テキストを動的に更新できる.

6.3 キーボードのイベントハンドラ

on_key_press と on_key_release により,キーの押下・解放イベントを処理する.self.keys_being_pressed に現在押されているキーの情報が格納される.

6.4 マウスのイベントハンドラ

on_mouse_motion,on_mouse_drag,on_mouse_press により,マウスの移動,ドラッグ,クリックの各イベントを処理する.director.get_virtual_coordinates でウィンドウ座標を仮想座標に変換する.

6.5 レイヤの切り替え

director.replace により,現在のシーンを新しいシーンに切り替える.複数のレイヤを定義し,キー押下で画面が切り替わる仕組みにより,画面のレイヤ分けを実現する.