MonoGameを使ってWindows/Androidでソースコードを共有しよう

初めまして、Namazuです。
これはXamarin Advent Calendar2016の14日目の記事です。
今回はMonoGameのお話をしたいと思います。

# MonoGameとは？
XNAを移植したゲームフレームワークです。使用する言語はC#
XNAはMicroSoftが開発したゲームエンジンで、WindowsやWindowsPhone、Xboxにおいてソースコードをほとんど共通にして動作させることが可能なフレームワークです。

#### ソースコードを共有！
なんか素晴らしい響きですがXNAでは対応するプラットフォームが少なすぎますよね？？
そこでMonoGameの出番です。MonoGameの対応するプラットフォームは以下の通り！！

- iOS
- Android
- Windows
- Mac OS X
- Linux
- Windows Store Apps
- Windows Phone 8
- PlayStation Mobile
- OUYA

大体ゲームを作ろうとして困ることはないほどの数です。
とくに、AndroidとiOS、Mac OS Xに対応してくれているのがとてもありがたいです。

# MonoGameを最大限生かすために

さて、それではMonoGameの利点を最大化するためにはどうするか。
ズバリ、この二つを組み合わせて使うことです！

- Xamarin
- Visual Studio

### 出ました！！！！Xamarin！！！！！！！！
XamarinでAPI等を提供してもらって、MonoGameの仕組みとVisual StudioのSharedProjectを活かすと…？
![pico1_03.png](https://qiita-image-store.s3.amazonaws.com/0/146329/b445b130-5627-1bae-1c20-86f712819d61.png)
![pico2_03.png](https://qiita-image-store.s3.amazonaws.com/0/146329/4e419374-4077-ff02-0677-18742e5fd09d.png)
![piko3_03.png](https://qiita-image-store.s3.amazonaws.com/0/146329/bc5b7f9d-5d8a-9d3d-6f0e-571a1afdf80e.png)


### 複数プラットフォームでソースコードをほとんど共有化！！

### やったぜ！！

### さらにリソースの読み込みも共有化できちゃう！！

# 実際に書いてみる

流石にゲーム作るのは大変なので画像表示するだけで許してください。
今回は、WindowsとAndroidで同じコードで動かしてみます。

- Xamarin
- Visual Studio
- MonoGame

のインストールは各自で行ってください。
（多分これ読んでる人たちプロだから大丈夫だと信じてる）

それでは、VisualStudioを起動して
```
 File->New->Project->Installed/Templates/Visual C#/MonoGame->MonoGame Windows Project
```
を作成します。
ProjectNameとSolutionNameは、
Solution
├WindowsProject
├AndroidProject
└SharedProject
という構造を考えて決めてください。
今回は
forAdC
├forWindows
├forAndroid
└SharedProject
という名前をつけました。

しばらくするとエディタの準備が整うので、右側のSolutionExplorerからSolution'forAdC'を右クリックして
```
Add->New Project->Installed/Templates/Visual C#/MonoGame->MonoGame Android Project
```
からAndroid用のプロジェクトを作成して追加してください。
ここでまたプロジェクト名を決めることができます。（デフォルトはGame1）
同様に、
```
Add->New Project->Installed/Templates/Visual C#/Windows/SharedProject
```
から共有用プロジェクトを作成して追加してください。

すると、以下のような画面になるかと思います。
![image](https://qiita-image-store.s3.amazonaws.com/0/146329/92ab9ee3-a480-0509-0c65-dc6850c3b558.png)
まだ中身は何も弄っていません。

それでは、早速まとめましょうか。
forWindowsでは始めにProgram.csを起動しGame1.csを呼び出す形になっています。
forAndroidでは初めにActivity1.csを起動しGame1.csを呼び出す形になっています。
Game1.csの内容はほぼ同一ですので、これをまとめることができます。

Game1.csをSharedProjectに移動してそれを各プロジェクトから呼び出す形にしましょう。

forWindowsかforAndroidのどちらかからGame1.csをSharedProjectにドラッグ&ドロップでコピーしましょう。
そして、SharedProject以下のGame1.csのnamespaceを「SharedProject」（SharedProjectのプロジェクト名と同一）にします。

その後forWindowsとforAndroidのGame1.csを削除してください。

この時点でforWindowsのProgram.csを見てみると、
```
new Game1()
```
の部分でエラーが出ています。参照すべきGame1.csが見つからないからですね。
SolutionExplorerのforWindowsを右クリックし、Add ReferenceからSharedProjectを追加します。
その後SharedProjectをインポートします。
```
using SharedProject;
```
ここまで正しく書いてもSharedProjectが見つからないというエラーが出ることもありますが、一度ソリューションを閉じて再度開いてみると直ります。ソリューションファイルを読み込み直さなくても正常にビルドできます。

これで前準備が整いました。ビルドしてみてください。
青い画面が表示されたら勝ちです。

それでは、画像を追加しましょうか。

コードを書く前に、画像を準備しておかなければなりません。
MonoGameではコンテンツ（リソース）は別途ビルドする必要があります。

forWindowsのContent->Content.mgcbをエクスプローラで開きダブルクリックし、MonoGame Pipelineを起動します。
File->Newから新しいmgcbファイルを作成します。
場所は実はどこでも良いのですが、共有化してる感じを出すためにエクスプローラーでforAdCフォルダ直下にContentフォルダを作り、その下にContent.mgcbを新しく作成してください。
![image](https://qiita-image-store.s3.amazonaws.com/0/146329/290fd62f-297c-61cb-431a-abe9051f0138.png)
その後、MonoGame Pipelineの画面が少しおかしいので引っ張って直します。
直したあとはこんな感じになります。
![image](https://qiita-image-store.s3.amazonaws.com/0/146329/4f9c6881-2972-5bae-2175-6c99d0ad40df.png)
その後、Add Existing Itemから追加したい画像ファイルを選択してください。
追加する際はCopy the file to the directoryを選択してください。

そしてBuildからビルドします。
※Add Existing Item(ファイルのアイコン)、Build（歯車のアイコン）はツールバーから選択できます。
こんな感じになれば成功です。
![image](https://qiita-image-store.s3.amazonaws.com/0/146329/d8603ddb-17ff-3520-5cb4-c3d7c5a9af3c.png)
成功したらMonoGame Pipelineは閉じてしまって構いません。

それでは新しく作成したContent.mgcbをforWindows,forAndroidで読み込めるようにしましょう。
まずはforWindowsについて、Content以下にあるContent.mgcbを削除してください。
そして、SourceExplorer上でContentフォルダを右クリックしてAdd->Add Existing Itemから先ほど作成したContent.mgcbを追加してください。その際、「Add」ではなく「Add as a link」を選択するようにしてください。
するとSourceExplorerにリンクとしてのContent.mgcbが表示されますので、右クリックしてPropertyのBuild ActionをMonoGameContentReferenceに設定してください。
forAndroidでも同様の作業を行ってください。

それではコードを書き換えます。
Game1.csを以下のように書き換えてください。（コピペで構いません）
なお、Namazuとあるところは追加した画像のファイル名(拡張子なし)としてください。

```
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace SharedProject
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D texture;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            graphics.IsFullScreen = false;
            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 480;
            graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
        }

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            texture = Content.Load<Texture2D>("Namazu");

            // TODO: use this.Content to load your game content here
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            spriteBatch.Begin();
            spriteBatch.Draw(texture, new Rectangle(0, 0, 400, 400), Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
```

さて、ここまでで必要な作業は終了です。
実際に表示してみましょう。
forWindows
![image](https://qiita-image-store.s3.amazonaws.com/0/146329/b1f3264d-8917-c3ff-3ad4-722d626239e8.png)

forAndroid
![5662.png](https://qiita-image-store.s3.amazonaws.com/0/146329/9558dbe1-ff43-8dc9-59d2-582d4016a3de.png)

### できたー！！！！！！

ということで今回やることは以上です。
お付き合いありがとうございました。


# MonoGameの抱える問題

- 日本語文献が少ない
- Androidの文献が少ない

くらいでしょうか？
XNAのdocumentを読んでも具体的な実装方法が分からず試行錯誤、なんてこともしょっちゅうです。
もう少し日本語で分かりやすくしてくれれば日本でも普及していくと思うのですが…
私も日本語文献の一助になればと思いブログを書いておりますのでよろしければそちらもご覧ください。

- Monogameを使ってAndroidのゲームを作ろう　その１：https://trapti.tech/blog/1540/
- Monogameを使ってAndroidのゲームを作ろう　その２：https://trapti.tech/blog/1612/
- Monogameを使ってAndroidのゲームを作ろう　その３：https://trapti.tech/blog/1641/

# 参考文献

- 僕の考えた最強のゲームフレームワーク『MonoGame』を試す：http://giginet.hateblo.jp/entry/2013/10/29/121619
- Xamarin+VisualStudio+MonoGameでWindowsとAndroidの共有プロジェクトを作る：http://nnf.deci.jp/194/
- MonoGame Content Project Demo：https://www.youtube.com/watch?v=vBsb6CgAnEs