Xamarin + CocosSharp を使ってみたい ③
iOSは環境がないのでしばらくほっとくとして、勉強を進める。
Xamarin + CocosSharpのゲーム開発に最低限必要そうな要素メモ。
コーディング時にぱっとググれるようにするためのとっかかりを作る一次調査なので、C++のCocos2d-xの情報なども混じりつつ。
データの保存
PCL Storageという便利なライブラリがあるそうな
const string SubFolderName = "SampleData";
const string TextFileName = "Sample.txt";
// ユーザーデータを読み取るメソッド
async Task LoadTextAsync()
{
// ユーザーデータ保存フォルダー
PCLStorage.IFolder localFolder = PCLStorage.FileSystem.Current.LocalStorage;
// サブフォルダーを作成、または、取得する
PCLStorage.IFolder subFolder
= await localFolder.CreateFolderAsync(SubFolderName,
PCLStorage.CreationCollisionOption.OpenIfExists);
// ファイルを取得する
PCLStorage.IFile file = await subFolder.GetFileAsync(TextFileName);
// テキストファイルを読み込む
// ※ファイル冒頭に「using PCLStorage;」が必要
return await file.ReadAllTextAsync();
}
// 定数定義を再掲
//const string SubFolderName = "SampleData";
//const string TextFileName = "Sample.txt";
// ユーザーデータを書き出すメソッド
async Task SaveTextAsync(string text)
{
// ユーザーデータ保存フォルダー
PCLStorage.IFolder localFolder = PCLStorage.FileSystem.Current.LocalStorage;
// サブフォルダーを作成、または、取得する
PCLStorage.IFolder subFolder
= await localFolder.CreateFolderAsync(SubFolderName,
PCLStorage.CreationCollisionOption.OpenIfExists);
// ファイルを作成、または、取得する
PCLStorage.IFile file
= await subFolder.CreateFileAsync(TextFileName,
PCLStorage.CreationCollisionOption.ReplaceExisting);
// テキストをファイルに書き込む
// ※冒頭に「using PCLStorage;」が必要
await file.WriteAllTextAsync(text);
return file.Path;
}
Audio
CCAudioEngine
再生
//BGM .mp3
CCAudioEngine.SharedEngine.PlayBackgroundMusic (filename:"FruityFalls",loop:false);
//SE .wav
CCAudioEngine.SharedEngine.PlayEffect (filename:"Electricity");
プリロード
auto audio = SimpleAudioEngine::getInstance();
// pre-loading background music and effects. You could pre-load// effects, perhaps on app startup so they are already loaded// when you want to use them.
audio->preloadBackgroundMusic("myMusic1.mp3");
audio->preloadBackgroundMusic("myMusic2.mp3");
audio->preloadEffect("myEffect1.mp3");
audio->preloadEffect("myEffect2.mp3");
// unload a sound from cache. If you are finished with a sound and// you wont use it anymore in your game. unload it to free up// resources.
audio->unloadEffect("myEffect1.mp3");
音量
auto audio = SimpleAudioEngine::getInstance();
// setting the volume specifying value as a float
audio->setEffectsVolume(5.0f);
画像表示方法
CCSprite → スプライト
CCSpriteBachNode → パターン描画
TMXTiledMap → BG面
自分でゴリゴリとピクセルバッファにBG面書きたいのだがどうすれば?
画像読込
Spriteに直接読み込むか、TextureCacheに読み込むか。
テクスチャアトラスという効率的な画像の集合データからの切り出し利用もあるようだが、外部ツールが必要でちょっと面倒そう。CCSpriteSheet
とりあえず利用頻度の高いデータはTextureCacheに放り込むのかな。
画像バッファ
CCRenderTexture
CCRenderTexture* texture = CCRenderTexture::create(width, height);
ピクセルバッファ的に使えそう。
これにSpriteとか描画しまくってBG面作ればいいのかしら。
利用例
画像バッファへの基本的な描画命令
画像描画、線描画、矩形描画、文字列描画など。
CCDrawNodeクラス
DrawPoint、DrawLine、DrawRect、DrawStringなどが使えそう。
昔のゲームをベタ移植する際にはこのへんが重要かなぁ。
CCDrawNodeひとつで複数のプリミティブの描画が可能ぽい。
for (int i = 0; i < 8; i++)
{
drawNode.DrawCircle (
center: new CCPoint (i*15, 0),
radius: 20,
color: CCColor4B.White);
}
毎フレームCCRenderTextureにBG面を更新して描くのにはClear()メソッドでも呼べばいいのかな。あと画像とか混じる場合に描画順番はどうやって制御したものか。
画像バッファの画面反映
CCRenderTexture.BeginWithClear()
CCNode.Visit()
CCRenderTexture.End()
CCRenderTexture texture = new CCRenderTexture(ContentSize, ContentSize);
texture.Sprite.Position = new CCPoint(ContentSize.Center.X, ContentSize.Center.Y);
AddChild(texture.Sprite);
title.Texture.IsAntialiased = false;
CCDrawNode dnode = new CCDrawNode();
texture.BeginWithClear(CCColor4B.Orange);
{
title.Position = new CCPoint(0, 0);
title.Visit();
title.Position = new CCPoint(ContentSize.Center.X, ContentSize.Center.Y);
title.Visit();
dnode.DrawRect(new CCRect(ContentSize.Center.X, ContentSize.Center.Y, 50, 50), CCColor4B.Green);
dnode.DrawRect(new CCRect(ContentSize.Center.X + 50, ContentSize.Center.Y, 50, 50));
dnode.DrawRect(new CCRect(ContentSize.Center.X + 100, ContentSize.Center.Y, 50-1, 50-1),
CCColor4B.Transparent,0.1f, CCColor4B.Yellow);
dnode.Visit();
}
texture.End();
CCRenderTextureの確認のついでにCCDrawNodeをテスト。DrawRectがなんか外枠がY軸だけ1ドットずれる……すっきりしない。
座標系は左下基点、Spriteなどのオブジェクトの座標指定は中心座標のようだ。
CCRenderTexture内に描いたCCDrawNodeにおける座標は左下だった。
フレーム制御(60FPS)
CCMoveToクラスなどでスプライトのアクションを設定するようだ。
更新間隔と目的地を設定するとか。ほほーなるほど。
面白そうだけど、今回は昔ながらの作り方をしたい。
固定FPSでフレームごとの処理とかはできるんだろうか?
→ 第二引数なしのCCNode.Schedule()で毎フレーム処理できそう。
勝手に60FPSになってるぽいけど、どこかで設定できるんだろうか。
class TestLayer : CCLayerColor
{
CCRenderTexture texture ;
CCSprite title;
CCDrawNode dnode;
Random rnd = new Random();
protected override void AddedToScene()
{
base.AddedToScene();
texture = new CCRenderTexture(ContentSize, ContentSize);
texture.Sprite.Position = new CCPoint(ContentSize.Center.X, ContentSize.Center.Y);
AddChild(texture.Sprite);
title.Texture.IsAntialiased = false;
dnode = new CCDrawNode();
//毎フレーム実行
this.Schedule(t => this.mainloop());
}
private void mainloop()
{
dnode.Clear();
texture.BeginWithClear(CCColor4B.Orange);
{
title.Position = new CCPoint(0, 0);
title.Visit();
title.Position = new CCPoint(ContentSize.Center.X + rnd.Next(50),
ContentSize.Center.Y + rnd.Next(50));
title.Visit();
dnode.DrawRect(new CCRect(ContentSize.Center.X, ContentSize.Center.Y, 50, 50),
CCColor4B.Green);
dnode.DrawRect(new CCRect(ContentSize.Center.X + 50, ContentSize.Center.Y, 50, 50));
dnode.DrawRect(new CCRect(ContentSize.Center.X + 100, ContentSize.Center.Y, 50, 50),
CCColor4B.Transparent, 0.1f, CCColor4B.Yellow);
dnode.Visit();
}
texture.End();
}
}
これ勝手にダブルバッファリングになってるんだろうか。
バックグラウンド処理
// This function will be called when the app is inactive. When comes a phone call,// it's be invoked toovoid AppDelegate::applicationDidEnterBackground() {
Director::getInstance()->stopAnimation();
// if you use SimpleAudioEngine, it must be pause
// SimpleAudioEngine::getInstance()->pauseBackgroundMusic();}
// this function will be called when the app is active againvoid AppDelegate::applicationWillEnterForeground() {
Director::getInstance()->startAnimation();
// if you use SimpleAudioEngine, it must resume here
// SimpleAudioEngine::getInstance()->resumeBackgroundMusic();}
タッチ入力の検知
var eventListener = new CCEventListenerTouchOneByOne();
// OnTouchBegan で true を返却しないと、OnTouchEndedが発動しない。
eventListener.OnTouchBegan = (t, e) => true;
eventListener.OnTouchEnded = (t, e) =>
{
// 移動先のシーン(ゲーム画面)を作成
var newScene = new CCScene(GameView);
var gameLayer = new GameLayer();
newScene.AddChild(gameLayer);
// シーン切り替え時の効果を設定
CCTransitionScene transitionScene = new CCTransitionFade(4.0f, newScene);
// ゲーム画面へシーン切り替え
Director.ReplaceScene(transitionScene);
};
AddEventListener(eventListener, this);
その他
ドキュメント日本語訳
Cocos2d-x APIリファレンス
CocosSharp APIリファレンス
CocosSharp Guides