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:インストーラーによるインストール
- Python 公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンから Windows 用インストーラーをダウンロードする。
- ダウンロードしたインストーラーを実行する。
- 初期画面の下部に表示される「Add python.exe to PATH」に必ずチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから
pythonコマンドを実行できない。 - 「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
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 により,現在のシーンを新しいシーンに切り替える.複数のレイヤを定義し,キー押下で画面が切り替わる仕組みにより,画面のレイヤ分けを実現する.