2015年12月9日水曜日

Cities: Skylinesのmodを作ってみよう

ということで、昨日から作り始めました。

assetじゃないよ。
modとassetをごっちゃになさっている方はそのままブラウザの戻るボタンを押下してくださいませ。

C:SLのmodはC#で書くんだぜ、ということらしいので久しぶりにC#触ったけど、なんだか以前触った時よりものすごく進化していますねえ。びっくりしました。

まあ、別にC#に精通するつもりはないのであんまり深く追っかけないことにして、とりあえずひな形としてIUserModを継承したクラスを作って、NameとDescriptionを返せばとりあえずは体裁が整います。

でもこれだけじゃ意味がないので、UI画面を作るにはUIPanelから継承したクラスを作って、それをLoadingExtensionBaseを継承したクラスメンバのOnLevelLoaded()で、

UIView.GetAView().AddUIComponent( typeof( "UIPanelから継承したクラス" ) )

とするとUI画面ができました。

画面が出てしまえばもうこっちのものなので、今度はその画面に表示するデータをセーブファイルに紛れ込ませる方法は、ISerializableDataExtensionを継承したクラスを作るだけ。

C#のすごいところは、リストを含んでいようがインナークラスを含んでいようが、いとも簡単にシリアライズできてしまったところ。
これは実に驚きました。

うーん、なんて楽なんだ・・・

ポインタがある言語ではクラスや関数が多種類あるけど呼び出し形式もとれるデータ形式も同じだよ、というような場合の処理は関数やメンバ変数へのポインタが大変便利ですが、メモリ管理が自分でできない言語だと多少厄介です。
その点、javaと同様にC#もリフレクションが充実しているようです。
おかげで、メンバ名で直接メンバの値を操作できるような仕組みが実装できました(でもやっぱりポインタのほうが分かりやすいなぁ・・・)。

たとえば、

public class foo{
  public bar piyo ;
  public foo(){
    piyo = new bar();
  }
  public class bar{
    public int hoge;
  }
}

なクラスに"piyo.hoge"というメンバに"文字列で"アクセスしたいなぁ、といったときに

float getValueFromMemberName( object topobj, string member )
{
string[] arrays = member.Split( '.' );
object obj = topobj;
for ( int i = 0 ; i < arrays.Length ; i++ )
{
Type t = obj.GetType();
obj = t.InvokeMember( arrays[i], System.Reflection.BindingFlags.GetField, null, obj, null );
}
return (float)Convert.ChangeType( obj, typeof( float ) );
}
という関数をでっち上げて、topobjに new foo() したオブジェクトを指定して、memberに文字列で"piyo.hoge"と指定してやると、hogeの値が(intなのに)floatで頂戴できるという寸法。
まあ、ポインタが使えない苦肉の策なんですけども、javaとかC#のような言語ならではですねえ。

いまだにCSLのライブラリ群のドキュメントを見つけられていないんですが、VisualStudioのオブジェクトブラウザでメソッドやクラスを眺めているだけでだいたい見当がついちゃったのはこの手の言語ならではでしょうね。

基本的な表示とセーブデータへの私のmod固有のデータのセーブ・ロード方法が分かったので、あとはきちんとUIを作るだけになりました。
ドキュメントが全然ないフレームワークに乗っかっても1日でここまで来るとは思いにもよりませんでした。

あとは、同じようなmodが先に公開されませんように祈りつつコーディング作業を急がなくては。。。

1 件のコメント:

  1. なんと、SkylinesのMODを作ってる日本の人が自分以外にいただと…!?びっくり!
    応援してます、頑張ってください!!

    返信削除