アプリ置き場

アプリ置き場

http://www.moreread.net/

Xamarin + CocosSharp を使ってみたい ⑤

部分描画(画像の一部を切り出して描画する)
Sprite.TextureRectInPixels = new CCRect(sposx, sposy, sw, sh);
Sprite.ContentSize = new CCSize(sw, sh);
 
文字列の折り返し
CCLabel.Dimensions = new CCSize(w, h);
 
仮想キーパッド(てきとう)
protected override void AddedToScene()
{
var eventListener = new CCEventListenerTouchOneByOne();
eventListener.OnTouchBegan = CCEventListener_TouchBegan;
eventListener.OnTouchCancelled = CCEventListener_TouchEnded;
eventListener.OnTouchEnded = CCEventListener_TouchEnded;
AddEventListener(eventListener, this);
}
 
Dictionary<int, uint> keyDic = new Dictionary<int, uint>();
private Boolean CCEventListener_TouchBegan(CCTouch touch, CCEvent touchEvent)
{
if (button_left.BoundingBox.ContainsPoint(touch.Location))
{
keyDic[touch.Id] = BUTTON_LEFT;
pad.buttons |= BUTTON_LEFT;
}
elseif (button_right.BoundingBox.ContainsPoint(touch.Location))
{
keyDic[touch.Id] = BUTTON_RIGHT;
pad.buttons |= BUTTON_RIGHT;
}
return true;
}
 
private void CCEventListener_TouchEnded(CCTouch touch, CCEvent touchEvent)
{
if (keyDic.ContainsKey(touch.Id))
{
pad.buttons &= ~keyDic[touch.Id];
}
}
 
private void CCEventListener_TouchMoved(CCTouch touch, CCEvent touchEvent)
//TODO
}
 
iPhone実機の接続
なかなかiPhone実機で動かせなくてイライラ。3~4時間かかってしまった。
罠回避ポイント。
  • Info.plistの配置ターゲット
  • .iOSプロジェクト設定のビルド→サポートアーキテクチャ
  • iPhone認証後のMacエージェントの切断、再接続
  • バンドル識別子変更後のソリューションクリーンビルド
  • 他いろいろあったけど忘れた
とはいえなんとか環境は整ったので、あとは作り込むのみ。
 
iPhone実機でマルチタッチが効かない
View.MultipleTouchEnabled =true;
 
iPhone実機で透過PNGが透過されない
ググるiOSでは8bit pngは透過しない?まじか。いや、32bitでも透過されない場合があるぞ。
どうもirfanViewで作ったPNGがよろしくないようだ。透過色、背景色の設定によるんだろうか?
あたらめてirfanViewPNG変換をいろいろやってみると、色がおかしくなったりしてる。PNG変換まわりはなんかおかしい。標準仕様外の最適化でもしてるんじゃろか。違うソフトで変換するかー。
 
あと.iOSプロジェクトのプロパティにあるPNG画像を最適化するにチェックいれると透過できない場合があったのでこれも注意。
 
描画が重い

 
どうしよう、実機でもカックカク。
メインループは60回まわってきてても画面の描画が反映されてるのはかなり少なそう。ダメージを受けたときのエフェクトとして、1フレームごとに表示/非表示の点滅をしたら、消えっぱなしに。
いろいろオーバーヘッドあるけどバッファの解像度は320x180とめっさ小さいので、iPhone7なら余裕だろうと思ってたんだけどなぁ。
 
ちょいとしらべてみるとDrawNodeでDrawRectangleしまくってるのが遅い。画像描画したほうがましだった。描画自体が遅いのか、毎フレームのノードの生成が遅いのか、生成と破棄ともなうGCが遅いのかは調べてないけど。
がんばって最適化するかー。
 
描画のずれ
iPhoneで画像の描画が1ドットずれる。上側1ドットが表示されず、下側1ドットが2ドットに引き延ばされてる。0.5ドットずれてるとかそういうアレだろうか?厳密なドット単位の処理がきついなぁ。とりあえず0.5f足したらなおった気がする。
 
 
 

Xamarin + CocosSharp を使ってみたい ④

我慢できずに中古のMac miniを購入
APPLE Mac mini (2.6GHz Dual Core i5/8GB/1TB/Intel Iris) MGEN2J/A
6万円なり。てか新品でも7万やないか。新品でもよかったな……。
傷もなく良品でテカテカひかってるからまぁいいや。
アルミの削りだしボディはかっこいい。

なにやら画像が乱れて、ジジジッっという異音がしていたが、Thunderboltな口から古いDisplayPort⇔HDMI変換アダプタを経由してディスプレイと接続していたせいかもしれない。しらんけど。HDMIで直接つないだら直ったきがする。
さてもっかいMacをセットアップだ。
 
座標反転
Xamarinを試すまえにC#の標準ライブラリ(と幾何かのWin32API)だけで簡単なアクションゲームを作ってたので移植を試みる。描画まわりはSystem.Drawingだけという男らしい造りだ。
 
とりあえず前回の調査でCCRenderTextureとやらを使えばなんとかなりそうな感触を得ていたのだが、どう考えても描画まわりのロジック全部、Y座標系を逆にするのが面倒すぎる。CocsSharpは左下が基点となる。
いろいろ調べてみたところ、スケールを-1にすればいけそう。
 
Sprite.ScaleY = -1;
 
線描画、矩形描画等はCCRenderTextureにそのまま描画し、画像はYスケールを-1にしてから描画、描画完了したCCRenderTextureをYスケール-1で設置すれば、左上基点の座標系でいける。
 
グラフィックまわりのラッパー的なものをCCRenderTextureを使ってごりごり書いたらなんとなく動いた。Xamarinしゅごい。けど、表示がいろいろおかしい。

 
まず色がおかしかったのだが、CCColor3B、CCColor4Bのコンストラクタの引数の型がfloatで0~1.0ぽい。0~255つっこんだら、もれなく黒か白になってた。ちゃんとByte型のやつもあったのでキャストしたらなおりました。

 
なんかくっそ重いなぁ。大丈夫かなぁ。
画像を切り出して部分描画するところもうまくいってないなぁ。
タッチ入力もよくわからんなぁ。先は長い。
 

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);
 
CCSprite title = new CCSprite("/Resources/Images/Title/Title.png", null);
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 = new CCSprite("/Resources/Images/Title/Title.png", null);
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
 
 
 
 

Xamarin + CocosSharp を使ってみたい ②

拡大処理について
 
古いmac miniを引っ張り出してOSをアップしている間に、AndroidのほうでCocosSharpの勉強をしてみる。
 
内部解像度を指定すれば、あとは勝手にハードウェアに合わせて拡大してくれるようだ。超便利。
var gameView = sender as CCGameView;
gameView.DesignResolution = new CCSizeI(320, 180);
gameView.ResolutionPolicy = CCViewResolutionPolicy.ShowAll;
 
低解像度のバッファを想定して下記の画像を表示した。

が、いい具合に勝手にスムージングされている。
nearest neighborで拡大はできないのか?Webで情報がみつけられない。
 
 
そしてがんばってインテリセンス眺めてたら、なんかそれっぽいパラメータを見つけた。
ccsprite.Texture.IsAntialiased = false;

う~ん?たぶん目的を達成した気がする。
 
 
 
mac miniのセットアップ
 
とりあえず引っ張り出してきたmac miniのOSをアップデートした。
ちなみに一緒に買って放置されてたキーボードとマウスの電池は奇跡的に液漏れしてなかった。
 
2009年モデルのmac miniOS X El Capitanとやらまでしか入らないらしい。
そしてきゃぴたんはXcode 8.2までしか使えないらしい。
大丈夫なのか。。。
 
SierraMac mini Mid 2010以降が必要
 
WindowsのVisualStudio上からmacにリモートで接続してデバッグするようだ。
とりあえずXamarinがmac上にも必要らしいので、入れてみる。
 
XamarinのページにいくとXamarin Studioが見当たらない。
もうVisualStudioからしか利用できないのかな?
VisualStudioのインストールを進めるとXcode9が必要とか不穏なメッセージが流れる。
 
そして……
 
うん、ダメっぽい。Xcodeが古いって怒られる。
Xamarin Live Playerもダメだった。Build Errorとか出る。
 
新型がうわさされる時期にmac miniとか買いとうない。
されどノートはいらないんだよなー。中古で2014年モデル買ってくるか……。
結構いいお値段するなぁ。
 
 

Xamarin + CocosSharp を使ってみたい

久しぶりにゲームを作ろうと思ったけど浦島太郎状態。
できればWindowsAndroidiOSクロスプラットフォーム開発がしたい。
さらに言えばJavaとかC#でコード書きたい。
 
そして、グーグル先生からVisualStudio+Xamarin+CocosSharpという啓示を受けたのだった。
とりあえずVisualStudio2017がタダで使えるようだ。ふむふむ。
ということで、メモった作業経過を少しばかりブログに残してみようと思う。
 

 作業メモ

Hello World的なものに取り掛かるが、セットアップにいろいろとひっかかる。
CocosSharpがなかなか入らず。。
Web上に情報すくなすぎぃ。。アメリカ語は読めません。

上記設定でインストールに成功した。
ソリューションを右クリック→NuGet→CocosSharpを検索してインストール。

なんとか入ったと思ったが今度はAndroidエミュレータが動かない。

ずっとこのまんま。起動失敗してるぽい。
Android SDK Managerからアップデートを行って、その後エミュレータを作り直したら起動はした。

が、画面はずっと真っ黒なまま。。
API Level25で作ってるはずが、26がインストールされてないぞとかエラーでててイミフ。
とりあえず26も入れてみる。
そしてIA版のほうが速そうなのでIA版を作って起動してみる。
 
そしたら今度はHAXMないって言われたのでダウンロードしてきて入れてみる。
Android SDK Managerからも関連項目が見えたが、なぜか利用できないようだ。
直接入れる。

おお、がんばれ!

やったー!つД`)・゚・。・゚゚・*:.。..。.:*・゚
でも作ったアプリ起動しないよ……?
 
なんかうまく動かないしまだ重いしなので、Androidバージョン4.4で作り直す。

 
ここを参考に画像を出すだけのプログラムを書いてみる。貴重な情報大変ありがたい。
 
が、OpenTKの参照がうんぬんでエラーいわれてビルドできない。
参照追加しようとしてみるが、どれやねんくそ。//心が荒んできた
大量にあったけど2回目で当たり引いた。
試行錯誤した末にできた参照のゴミだろうか。。。

そしてようやっと起動!ぱちぱちぱち。

 
次はiOSだなー。iOS版はやっぱmacいるのかー。
ほこりかぶった2009年モデルのmac miniしかないよー……?