はじめに
こちらの記事は、Axmol Engine なるものを使ってバイブコーディングでどこまでできるかを、検証と勉学を兼ねた試験的な目論見となります!
前回すプラッシュ画面を作成しましたので、今回は続きましてタイトル画面の作成になります。
- 第1回【Axmol Engine】 バイブコーディングで脱出ゲームを作る[ 1 ]:スプラッシュ画面シーンを実装する
- 第2回【Axmol Engine】 バイブコーディングで脱出ゲームを作る[ 2 ]:タイトルシーンを作って画像を表示する(iPhone/Android対応)(今回)
まずは始めに成果物
- 前回の「【Axmol Engine】 バイブコーディングで脱出ゲームを作る[ 1 ]:スプラッシュ画面シーンを実装する」からの続きです。
-
Contentディレクトリへの画像の配置 -
TitleSceneの新規作成(背景・ロゴ・タップボタンの表示) -
SplashSceneからの遷移先をTitleSceneに変更 - 各スプライトの位置調整
完成後のシーンフローはこうなります。
SplashScene(ロゴアニメ) → TitleScene(タイトル画面・タップ待ち) → MainScene
1. Content ディレクトリへの画像配置
EscapeGame/Content/ に以下の3枚を追加しました。
- ChatGPTの画像生成で作成しました。
| ファイル名 | 内容 | サイズ |
|---|---|---|
bg_title.png |
背景画像 | 1870 × 841 |
txt_title.png |
タイトルロゴ | 1536 × 1024 |
btn_tap_to_start.png |
タップ促進ボタン | 539 × 189 |
Axmol は Content/ 以下をリソースルートとして扱うため、コード内では "bg_title.png" のようにファイル名だけで参照できます。
- bg_title.png (タイトル画面背景)
プロンプト:「月明かりだけが照らす夜の廃墟の家を20:9で」
画面幅をいっぱいに表示させたかったので、20:9 のアスペクト比を指定しました(はみ出しは許容)
- txt_title.png(タイトル画面ロゴ)
プロンプト:「この画像に合う、「廃墟からの脱出」というタイトルのロゴを作成してください。テキストのみで、あとは透過で」
- btn_tap_to_start.png(タイトル画面 [ Tap to Start ] のテキストボタン画像)
プロンプト:「この画像に合う、「Tap to Start」というテキストを作成してください テキストのみで、それ以外は透過で」
想定よりも大きな画像になったので、GIMPで手作業にて縮小・トリミングしました
バイブコーディングで実装
プロンプト:
「iPhoneやandroidで画面幅をいっぱいに使いたいです
ResolutionPolicyはFIXED_HEIGHTを指定してください
背景画像は画面外にはみ出ることを許容します」
プロンプト:
「EscapeGame > Content ディレクトリに、タイトル画面用の
bg_title.png (背景画像)
txt_title.png (タイトルロゴ)
btn_tap_to_start.png(タップを促すボタン)
という画像をそれぞれ設置しましたので、
タイトルシーンを作成してそれぞれ表示してください」
Claude Code が行なってくれた作業
2. ResolutionPolicy を FIXED_HEIGHT に変更
デフォルトの SHOW_ALL は画面端に黒帯が入ります。
iPhone/Android の様々なアスペクト比で横幅いっぱいに表示するには FIXED_HEIGHT が適切です。
そのため、背景画像などは20:9などで作成して両サイドのはみ出しを許容して作成するといいかと思われます。
AppDelegate.cpp
// 変更前
renderView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height,
ResolutionPolicy::SHOW_ALL);
// 変更後
renderView->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height,
ResolutionPolicy::FIXED_HEIGHT);
FIXED_HEIGHT では 高さ(720px)を基準にスケールし、幅はデバイスのアスペクト比に応じて広がります。背景画像がデザイン解像度より横に広い場合、左右にはみ出すことになりますが、それで画面を隙間なく埋められます。
3. TitleScene の新規作成
TitleScene.h
#pragma once
#include "axmol/axmol.h"
class TitleScene : public ax::Scene
{
public:
bool init() override;
private:
bool _transitioning = false;
void goToMain();
};
TitleScene.cpp
#include "TitleScene.h"
#include "MainScene.h"
using namespace ax;
bool TitleScene::init()
{
if (!Scene::init())
return false;
auto visibleSize = _director->getVisibleSize();
auto origin = _director->getVisibleOrigin();
Vec2 center = origin + Vec2(visibleSize.width / 2, visibleSize.height / 2);
// 背景: 高さに合わせてスケール(横はみ出し許容)
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(center);
addChild(bg, 0);
}
// タイトルロゴ: 画面幅の50%に収める
auto logo = Sprite::create("txt_title.png");
if (logo)
{
logo->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
float scale = visibleSize.width * 0.5f / logo->getContentSize().width;
logo->setScale(scale);
logo->setPosition(Vec2(center.x, origin.y + visibleSize.height * 0.5f));
addChild(logo, 1);
}
// タップボタン: 画面幅の28%に収めて点滅
auto tapBtn = Sprite::create("btn_tap_to_start.png");
if (tapBtn)
{
tapBtn->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
float scale = visibleSize.width * 0.28f / tapBtn->getContentSize().width;
tapBtn->setScale(scale);
tapBtn->setPosition(Vec2(center.x, origin.y + visibleSize.height * 0.22f));
addChild(tapBtn, 1);
// 点滅アニメーション
auto blink = Sequence::create(FadeTo::create(0.7f, 60), FadeTo::create(0.7f, 255), nullptr);
tapBtn->runAction(RepeatForever::create(blink));
}
// タッチで MainScene へ
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = [this](Touch*, Event*) -> bool {
goToMain();
return true;
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
return true;
}
void TitleScene::goToMain()
{
if (_transitioning)
return;
_transitioning = true;
auto mainScene = utils::createInstance<MainScene>();
_director->replaceScene(TransitionFade::create(0.5f, mainScene));
}
ポイント解説
背景のスケール計算
float scale = visibleSize.height / bg->getContentSize().height;
visibleSize は FIXED_HEIGHT の場合、高さが常にデザイン解像度(720px)になります。背景画像の高さに対する比率でスケールすることで、縦方向を隙間なく埋めます。横幅は元画像が十分広いためはみ出す形になります。
ロゴのスケール計算
float scale = visibleSize.width * 0.5f / logo->getContentSize().width;
visibleSize.width は実行時のデバイス幅(FIXED_HEIGHT 下では端末ごとに異なる)を使うため、どの画面サイズでも「画面幅の50%」が保たれます。
アンカーポイントを明示
bg->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
Axmol の Sprite はデフォルトでも中心がアンカーですが、明示しておくと setPosition の基点が一目でわかります。
タップボタンの点滅
auto blink = Sequence::create(FadeTo::create(0.7f, 60), FadeTo::create(0.7f, 255), nullptr);
tapBtn->runAction(RepeatForever::create(blink));
FadeTo でアルファ値を60(薄い)→255(不透明)と往復させ、RepeatForever で無限ループします。
二重遷移防止
bool _transitioning = false;
void TitleScene::goToMain()
{
if (_transitioning) return;
_transitioning = true;
...
}
タッチイベントが連続して発火しても replaceScene が1回だけ呼ばれるようにフラグで制御します。
4. SplashScene の遷移先を TitleScene に変更
元々 MainScene へ直接遷移していた部分を TitleScene に差し替えます。
SplashScene.cpp
// 変更前
#include "MainScene.h"
...
auto mainScene = utils::createInstance<MainScene>();
_director->replaceScene(TransitionFade::create(0.5f, mainScene));
// 変更後
#include "TitleScene.h"
...
auto titleScene = utils::createInstance<TitleScene>();
_director->replaceScene(TransitionFade::create(0.5f, titleScene));
成果物
- [Tap to Start]が明滅して表示されます
- 画面をタップするとMainSceneに遷移します
まとめ
| 対応内容 | ファイル |
|---|---|
| ResolutionPolicy を FIXED_HEIGHT に変更 | AppDelegate.cpp |
| TitleScene 新規作成 |
TitleScene.h / TitleScene.cpp
|
| SplashScene の遷移先を TitleScene に変更 | SplashScene.cpp |
FIXED_HEIGHT + 背景画像のはみ出し許容という組み合わせにより、iPhone・Android のあらゆる画面サイズで黒帯なしのタイトル画面が実現できます。




