はじめに
axmol Engine を使った脱出ゲームを作っています。
この記事では メインシーンに背景画像を表示し、画面内の特定エリアをタップすると別の背景にフェード切替する 実装を紹介します。
廃墟を遠目に見てスタート
↓
廃墟の建物付近をタップして近づく
↓
廃墟の建物の扉前に移動
脱出ゲームにありがちな、建物に近寄る、宝箱に近寄る、といった処理になります。
廃墟の扉付近の背景画像は ChatGPT(DALL·E)で生成し、Content/ 以下に配置しました。
-
bg_title.png… 遠景の幽霊屋敷(タイトルシーンから持ち越し) -
bg_stage_001.png… 屋敷玄関のアップ(ChatGPT で生成)
この後のギミック(ポストのダイヤル錠を開錠 → 鍵をポストから取得して扉を開ける)を想定して、下記ような画像を作成しました。
プロンプト:「20:9のアスペクト比で、月明かりが照らす夜のこの廃墟の扉を、近づいて、正面から描いてくだい 扉には金色の鍵穴を描いてください 少し明るめで、蓋の付いている古びたポストも描いてください ポストには3桁のダイヤル錠を描いてください」
1. MainScene に bg_title.png を表示する
まずは、廃墟から少し離れた場所をスタート地点とするために、タイトルでも使用した背景画像をそのまま使用します。
プロンプト:「メインシーンにタイトル画面の背景画像を描画してください」
テンプレートの HelloWorld.png と「Hello World」ラベルを削除し、
bg_title.png を高さに合わせてスケールしてセンターに配置します。
横はスクリーンからはみ出すことを許容(TitleScene と同じ方針)。
// MainScene.cpp – init()
auto visibleSize = _director->getVisibleSize();
auto origin = _director->getVisibleOrigin();
auto bg = Sprite::create("bg_title.png");
if (bg)
{
bg->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
float scale = visibleSize.height / bg->getContentSize().height;
bg->setScale(scale);
bg->setPosition(Vec2(origin.x + visibleSize.width / 2,
origin.y + visibleSize.height / 2));
bg->setTag(100);
this->addChild(bg, 0);
}
2. bg_stage_001.png を opacity=0 で重ねる
次に、廃墟の扉付近へ移動するような処理を実装します。
プロンプト:「bg_title.png内の添付の箇所がタップされたらフェイドアウトして、bg_stage_001.png をフェイドインして表示して」
bg_stage_001.png を最初から透明(opacity=0)の状態で bg_title の上(z=1)に配置します。
フェードインしたときに即座に表示できるよう、事前にシーンへ追加しておくのがポイントです。
auto bgStage = Sprite::create("bg_stage_001.png");
if (bgStage)
{
bgStage->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
float scale = visibleSize.height / bgStage->getContentSize().height;
bgStage->setScale(scale);
bgStage->setPosition(Vec2(origin.x + visibleSize.width / 2,
origin.y + visibleSize.height / 2));
bgStage->setOpacity(0);
bgStage->setTag(101);
this->addChild(bgStage, 1);
}
3. タップ有効領域の絞り込み
廃墟建物付近をタップが有効な範囲としたかったため、bg_title.pngから建物だけをキャプチャして、Shift+ドラッグでclaudeに渡しつつ下記プロンプトを投げました。
プロンプト:「この添付の画像の箇所のみタップされたらbg_stage_001を表示するように」
bg_title.png の中には屋敷以外に空や木々も映っています。
屋敷部分(画像横幅の 35%〜85% あたり)をタップしたときだけ遷移させます。
convertToNodeSpace() でタッチ座標をスプライトのローカル座標に変換し、
Rect::containsPoint() でヒット判定します。
微妙に想定と異なっていましたが、そのまま進行します。
void MainScene::onTouchesBegan(const std::vector<ax::Touch*>& touches,
ax::Event* event)
{
if (_bgTransitioned || touches.empty())
return;
auto bgTitle = this->getChildByTag(100);
if (!bgTitle)
return;
// タッチ座標をスプライトのローカル座標へ変換
auto local = bgTitle->convertToNodeSpace(touches[0]->getLocation());
auto cs = bgTitle->getContentSize();
// 屋敷エリア:横 35%〜85%、縦全体
ax::Rect houseRect(cs.width * 0.35f, 0, cs.width * 0.50f, cs.height);
if (!houseRect.containsPoint(local))
return;
_bgTransitioned = true;
constexpr float duration = 0.6f;
bgTitle->runAction(FadeOut::create(duration));
if (auto bgStage = this->getChildByTag(101))
bgStage->runAction(FadeIn::create(duration));
}
_bgTransitioned フラグで二重発火を防止しています。
4. タップ有効領域をデバッグ表示する
タップ有効領域をデバッグで確認できるようにボーダーを描いてもらいます。
プロンプト:「タップ有効領域を赤色のボーダーで」
どこが有効エリアか確認するため、DrawNode で赤枠を描画します。
bg の 子ノードとして追加 することで、スプライトのスケール・フェードが自動的に継承されます。
// bg の addChild 直後に追加
auto cs = bg->getContentSize();
auto debugRect = DrawNode::create();
debugRect->drawRect(Vec2(cs.width * 0.35f, 0),
Vec2(cs.width * 0.85f, cs.height),
Color::RED);
bg->addChild(debugRect, 1);
ヘッダーの変更点
二重タップ防止フラグをメンバに追加します。
// MainScene.h
private:
bool _bgTransitioned = false;
成果物
タイトルをタップして遷移したメインシーン
- 見えづらいですが、タップ領域を赤いボーダーでデバッグ出力しています
タップ有効領域(赤いボーダー内)をタップして遷移した扉の前
まとめ
| やったこと | 使った API |
|---|---|
| 背景画像を高さフィットで表示 |
Sprite::create / setScale
|
| 透明スプライトを事前配置 | setOpacity(0) |
| フェード切替 |
FadeOut::create / FadeIn::create
|
| スプライト内座標でヒットテスト |
convertToNodeSpace / Rect::containsPoint
|
| デバッグ枠(子ノード継承) | DrawNode::drawRect |
次は bg_stage_001 上にオブジェクトやヒントを配置していく予定です。



