DxLibがいつの間にかPS4とVitaに対応していた件

こんばんは、freddiです。遺伝的アルゴリズムのゲームの方(大富豪)がうまく行きません。
そんなことはどうでもいいのですがなんと、素晴らしいご報告が有ります。

DxLibがなんとPS4とVitaに対応されてました→詳細

いえーい!ぱちぱち!これで制作の幅が増えるね!
と軽々しく言えるわけではなく、

 とはいえ、PlayStation®4 や PlayStation®Vita 用ソフトの開発は株式会社ソニー・コンピュータエンタテインメントと契約をしなければできませんので、 Windows用ソフトのように開発環境とDXライブラリをダウンロードしてすぐに開発、というわけにはいけません。

現在、同人ゲームを PlayStation®プラットフォーム向けに販売する「Play,Doujin!」プロジェクトという企画が存在していて、 2015年10月12日現在で同人ソフトを二作品 PlayStation®プラットフォーム用ソフトとして販売しています。

希望すれば誰でも参加できるというわけではありませんが、

・既に完成しているDXライブラリを使用した Windows用のゲームソフトがあって、それを PlayStation®プラットフォームで販売したい方

・DXライブラリを使用してPlayStation®プラットフォーム用の新規タイトルを開発したい方

は、「Play,Doujin!」プロジェクトへの参加を検討してみてください。
※リンク先から引用
ということだそうです。ちなみにDxlibかどうかは不明ですが、東方のゲームが「Play,Doujin!」にありました。
というわけで興味のある方は参加してみてはどうでしょうか。

freddiでした。

(新入生向け)プログラミングを始めよう!Part.1

はい、来ましたfreddiの気まぐれ連載パート2、いつまで続くでしょうかー?
…流石に新入生向けって書いてるなら続けたほうがいいですよね、できるだけPart1で終わらせますが。

それでは新入生のみなさんはじめまして、こんにちはの方はこんにちは。
いよいよ入学前ですが、気分はどうでしょうか。

たぶんこの大学に入って来る人の中にはプログラミングのpの字も知らない方がいるでしょう。
でもいま予習しようとしても、どうすればいいかわかんないはず(ググればいいとかいわないの)。
と、言うわけで今からでも簡単にプログラミングをする方法を教えますね。

対象はWindowsです。Vista~10までのバージョンを対象にしてます。
うむ、さてさて

参照渡しとかの個人的研究(やっぱりC++)

C++での参照渡しのまとめ。

たとえば、容量のでかいオブジェクトをそのまま引数に渡すと(コピー渡し)、
メモリの容量を余計食うようね!だから参照かポインタを渡そうね!!!
byビャーネたん(C++のママ)

…いや、参照渡し、ポインタ渡しどっちがいいの?????
てかどっちも同じじゃね????
と、思ったので個人的にまとめてみました。

では、引数でポインタを渡す関数の例を。

1
2
3
4
5
//Objectというクラス型のオブジェクトにメンバ(int)mがあるという想定。
//Object *ob;と宣言したらtest(ob);と使う。
void test(Object *ob){
ob->m = 5;
}

この関数では引数にアドレス(ポインタ)を渡す。
そして関数内でアロー演算子でメンバにアクセスして、値を見る(変更する)ことができる。

次に参照渡しバージョンをみましょう。

1
2
3
4
5
//Objectというクラス型のオブジェクトにメンバ(int)mがあるという想定。
//Object ob;と宣言したらtest(ob);と使う。
void test(Object &ob){
ob.m = 5;
}

この関数では引数に普通にオブジェクトを渡す。
そして関数内では.でメンバにアクセスして、値を見る(変更する)ことができる。

やってること結構同じじゃん!!!!!!!!!

ほぼ同じだけど、個人的には参照渡しのほうが見やすいよね!という感じですね。
ただ、自分が用意した「引数が参照渡しの関数」は他人から見ると、
引数が参照渡しかただのコピー渡しかわかんないので、
「引数オブジェクトの中身を変更されるされないがわかんないから危ないよねー」感ありますね。
(リファレンスを作れ!)

ただ、個人的な使い分けとしては値を変えるときにポインタ渡しで、
値を変えたくない時は参照渡しで、という考えです。
そういう時、参照渡しの時は、引数にconstつけてみたらいいかも。

1
2
3
4
5
//Objectというクラス型のオブジェクトにメンバ(int)mがあるという想定。
//Object ob;と宣言したらtest(ob);と使う。
void test(const Object &ob){//引数はこの関数内では、定数にする。
//ob.m = 5; 値を見ることしかできないのでこれだとコンパイルエラー。
}

じゃあ、いろいろ実験してみよう。
以下の様な複素数クラスを定義してみました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//複素数クラス
class complex{
private:
double re,im;//reは実数部、imは虚数部。そのまま読むとreim(霊夢)。
public:
//コンストラクタ
complex(double a,double b):re{a},im{b}{
}
//最初にre、後にim、その後オブジェクト自身のアドレスを表示
void go(){
cout << re << " " << im << " " << this <<endl;
}
};

また、complex向けの+=演算子を作ります。
作り方としては、
a += b;
だと、aが代入先でbが引数となります。
機能としては、complex(複素数)同士で足し算するやつです。
ここでは右辺部をコピー渡しで行きます。

1
2
3
4
5
6
7
8
9
//class complexスコープ(public:)に追記
complex operator+=(const complex a){//コピー渡し
cout << "+= 実行" << endl;
cout << "左辺のオブジェクトのアドレスは" << this <<endl;//そのままの意味
cout << "右辺のオブジェクトのアドレスは" << &a <<endl; //そのままの意味
re += a.re;//実数部計算
im += a.im;//虚数部計算
return *this;
}

そんでもってmain関数は、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main (void){
complex a{1.1,1.2};//1.1 + 1.2iという複素数
complex b{1.0,1.3};//1.0 + 1.3i
//a,bの複素数、それぞれのアドレス表示
a.go();
b.go();
a+=b;//bをコピー渡ししてaにa+bした結果を返す(この時、両辺値のアドレス表示)
//a,bの複素数、それぞれのアドレス表示
a.go();
b.go();
}

簡単にざっくり言うと、コピー渡しで渡していたオブジェクトは、コピーであることの確認。
んで結果は、

1
2
3
4
5
6
7
8
9
bash-3.2$ g++ -std=c++11 main2.cpp
bash-3.2$ ./a.out
1.1 1.2 0x7fff53280660
1 1.3 0x7fff53280650
+= 実行
左辺のオブジェクトのアドレスは0x7fff53280660
右辺のオブジェクトのアドレスは0x7fff532805d0
2.1 2.5 0x7fff53280660
1 1.3 0x7fff53280650

結果から、宣言したオブジェクトのアドレス(4行目)と計算内部のアドレス(右辺のアドレス)が違うのがわかりますね。
コピー渡しをすると、別のアドレスにオブジェクトがコピーされることがわかりますね。

次に、complex向けの+=演算子を変更。
ここでは右辺部を参照渡しで行きます。

1
2
3
4
5
6
7
8
9
//class complexスコープ(public:)に追記
complex operator+=(const complex &a){//コピー渡し
cout << "+= 実行" << endl;
cout << "左辺のオブジェクトのアドレスは" << this <<endl;//そのままの意味
cout << "右辺のオブジェクトのアドレスは" << &a <<endl; //そのままの意味
re += a.re;//実数部計算
im += a.im;//虚数部計算
return *this;
}

結果は、

1
2
3
4
5
6
7
8
9
bash-3.2$ g++ -std=c++11 main2.cpp
bash-3.2$ ./a.out
1.1 1.2 0x7fff53bd4660
1 1.3 0x7fff53bd4650
+= 実行
左辺のオブジェクトのアドレスは0x7fff53bd4660
右辺のオブジェクトのアドレスは0x7fff53bd4650
2.1 2.5 0x7fff53bd4660
1 1.3 0x7fff53bd4650

結果から、宣言したオブジェクトのアドレス(4行目)と計算内部のアドレス(右辺のアドレス)が同じなのがわかりますね。
これから、参照渡しをすると、オブジェクトがコピーされないがわかりますね。

+=を元に、+計算を作りましょう。
使うときは、a = c + b;となるため、c,bが引数です。

1
2
3
4
//これをcomplexのメンバにすると怒られるので、complexスコープ外へ
complex operator+(const complex &c,const complex &d){
return c+=d;//+=した後のcを返す。
}

しかし、これだとコンパイルエラーを吐きます。
なぜならば、ここでの+=演算子はcを変更します、が、
引数上、cは定数です。なので、定数を変えることはできません。
また、constを外すだけだと、cも変わっちゃいますよね…。
ということは、cはコピー渡しでないといけません。
(complexくらいサイズ小さいから大丈夫だけど、サイズの大きいオブジェクトが来ると困る)
ココらへんの解決策の話だと、これまた別の「コピー代入」の話になりますが、それはまた今度。

というわけで修正

1
2
3
4
//これをcomplexのメンバにすると怒られるので、complexスコープ外へ
complex operator+(complex c,const complex &d){
return c+=d;//+=した後のcを返す。
}

メインはこうします。

1
2
3
4
5
6
7
8
9
10
11
int main (void){
complex a{1.1,1.2};
complex b{1.0,1.3};
a.go();
b.go();
a = b + a;
a.go();
b.go();
}

さて、動作させてみましょう。

1
2
3
4
5
6
7
8
9
bash-3.2$ g++ -std=c++11 main2.cpp
bash-3.2$ ./a.out
1.1 1.2 0x7fff54cb7660
1 1.3 0x7fff54cb7650
+= 実行
左辺のオブジェクトのアドレスは0x7fff54cb7600
右辺のオブジェクトのアドレスは0x7fff54cb7660
2.1 2.5 0x7fff54cb7660
1 1.3 0x7fff54cb7650

+=起動メッセージが出てるのは、+のとき+=使ってるからです。
a = b(実行結果で言う左辺) + a(実行結果で言う右辺)と、でも考えてください。
途中コピー渡しになっちゃってますが(4行目のアドレス≠左辺のアドレス(コピー))
bは変わらなかったので良しとしましょう。

…話にオチがないのですが、これで終わりです。

unique_ptrを使った暗黙裏でのオブジェクト解体(C++11以上向け)

こんにちは、前回のSTLの記事を書いても余り意味は無いと思ったので、題名の通りのやつを書きます。

よく、C++のdelete忘れが多くなってきたこの頃、スマートポインタさんを使って、
一定のスコープから抜け出す時、オブジェクト解体をプログラムさんに裏でやらせようと言う魂胆です。

では、まず以下の様なクラスがあるとして、

1
2
3
4
5
6
7
8
9
10
//可読性的な問題でusing namespace std;
//猫のオブジェクト
class ClassNeko{
public:
ClassNeko(string n):voice{n}{} //コンストラクタ
~ClassNeko(){}; //ディストラクタ
void sakebu(){cout << voice << endl;}
private:
string voice;
};

こいつを使う以下の関数を定義したとします。

1
2
3
4
5
6
7
8
void nekoPlay(){
vector<ClassNeko*> neko; //猫のオブジェクトを作るコンテナ(可変配列のようなもの)作成。
//0-1の番号をしゃべる猫のオブジェクト作成
for(int i = 0;i < 5;i++)neko.push_back(new ClassNeko{to_string(i)});
for(int i = 0;i < 5;i++)neko[i]->sakebu();//順に鳴かせる
}

さて、この関数の問題としては、関数内で動的確保して使われた猫のオブジェクトを開放(delete)してないことです。
たとえvectorがするにしても、もし自作のコンテナを使ったとして、
その自作のコンテナが開放作業をしない(ユーザーに任せる)仕様だったらどうでしょう?
猫のデータは、メモリ領域に留まったままだとメモリリークを起こします。

では、どうすればいいでしょう。
普通は以下のようにやりますが、

1
2
//nekoPlay()関数内
for(auto x:v)delete v;

これだと、型の違うオブジェクトをたくさん作ったらたくさん書かないといけないから、
余計行が多くなりますし、そもそもdelete自体忘れるのもありますね。

ここで、スマートポインタさんを使います。

変更は、nekoPlay()内です。

1
2
3
4
5
6
7
8
void nekoPlay(){
//猫のオブジェクトのスマートポインタを作るコンテナ(可変配列のようなもの)作成。
vector<unique_ptr<ClassNeko>> neko;
//0-1の番号をしゃべる猫のオブジェクト(unique_ptr<ClassNeko>にキャスト)作成
for(int i = 0;i < 5;i++)neko.push_back(unique_ptr<ClassNeko>{new ClassNeko{to_string(i)}});
for(int i = 0;i < 5;i++)neko[i]->sakebu();//順に鳴かせる
}//スコープから抜けだしたので、猫オブジェクトは暗黙裏で解体。

ちょっと宣言等が長くなりましたが、どうでしょう。
delete忘れに最適ですね。でも宣言なげえ。

工大祭が近づいてきました

11/21(土)~11/22(日)に九州工業大学にて工大祭が行われます。

C3は模擬店でトーストとソフトドリンクを販売します。

また、トーストとソフトドリンクのセットも販売します。

また、サークル展示では各部員の制作したゲームの展示と制作物を収録したディスクを配布しています。

展示会場は1104講義室となっています。

当日飯塚キャンパスに御来場の際は是非お越しください。

工大祭が近づいてきました

11/23(土)~11/24(日)に九州工業大学にて工大祭が行われます。

C3は模擬店でうどんとソフトドリンクを販売します。

うどんは肉うどんとわかめうどんの2種類を販売する予定です。

また、サークル展示では各部員の制作したゲームの展示と制作物を収録したディスクを配布しています。

展示会場は1104講義室となっています。

当日飯塚キャンパスに御来場の際は是非お越しください。

アニメ「エスカ&ロジーのアトリエ」の第8話の演出(部内向け)

おそらくこの日記を観ているみなさんの中には YouTube やニコニコ動画などの動画サイトを一度は利用したことがある方がいるのではないでしょうか。このキャンパスとりわけ C3 のメンバーも自宅でおのおの好きな動画を観て楽しんでおります。
近年、日本のアニメーションを海外に売り出していこうという試みもちらほらみられます。
それは日本国内でしか放送されなかったアニメーションが、今やインターネットを使って場所や時間を選ばずに観られるからです。ハードウェアの進化、インフラの進化、ソフトウェアの進化、ウェブテクノロジーの進化、どれも今の状況を形成するのに欠かせないものです。

私が最近観たのは「エスカ&ロジーのアトリエ~黄昏の空の錬金術士~ 第8話「アツアツ? 温泉旅行です!」」でした。ニコニコ動画で最新話を無料(期間限定)で観ることができます。すごい世の中になりました。

この「エスカ&ロジーのアトリエ」は、テレビゲーム(コンソールゲーム)が原作のアニメーションです。
ちなみに C3 のメンバーの 7 割の部員がこのアトリエシリーズのファンです。残りの 4 割はディスガイアシリーズのファンで、残りの 3 割はネプテューヌのファン、それ以外はイースシリーズのファンが大半を占めています。

日本のアニメーションは世界的に観ても特殊なのではないか、と思います。毎週のように 24 分の尺のアニメーションが放送されています。放送局や地域にもよりますが、番組数は毎日 3 ~ 10 本の番組が放送されています。アニメーションを作って放送することは到底 1 人ではできません。オープニング・エンディングに流れるスタッフロールを観ただけでも数十人、数百人の人や組織が関わっています。おそらくスタッフロールに載っていない直接関係していないスタッフもいることでしょう。(例えば制作会社の法務担当とか含めても。)

このことから、アニメーションを作るのに考えなければいけないことが見えてきます。例えば、「期間内に作ること」です。制作スピードを落とさないこと、あるいは速度を上げることが重要視されます。一回放送するのにかかるお金、影響、スポンサーの意向もろもろを考慮して、放送を落とさない必要があります。
次に大事なのは「お金をかけすぎないこと」でしょう。アニメーションを作るのにいろんな人が関わります。人を雇ってお給料を払う場面を想像してみてください。一人雇うのにかかるお金とアニメーションの制作に関わる人の数をかけてみただけでも、12話分制作するととても大きなお金が動くことが容易に想像できます。

アニメーションを作っている世界では「速く、安く」作ることが求められているはずです。制作会社ではおそらく今も昔もいろんな試行錯誤をして「期間内に、早く正確に質のいいものを作ろう」と取り組んでいることと思います。CG の普及はここに大きく作用しています。C3 の部室には CG WORLD が常備されており(部員のみなさんはもちろん愛読していることと思いますが)、読むたびにアニメーションにおける CG の導入例が毎号特集されているほどです。

「速く、コストをかけず、それでいて面白いものを」作っていくために、CG を使ったアプローチの他に次のアプローチも挙げておきましょう。
それは「出崎統アプローチ」です。部員の多くが、東映アニメーションが制作した長編アニメーション “AIR 劇場版“ のファンです。私もファンで、この劇場版 AIR を何度も観て、笑いと涙が止まらないほど感動しました。その感動は例えるなら、観終わった後に思わず真っ白な灰になるほど…でした。このアニメーションを監督したのが出崎統氏です。

出崎氏はアニメーションを速く、コストをなるべくかけず、それでいて「観る人を楽しませる」画期的なアニメーション手法を開発しました。その有名なものに「止め絵(ハーモニー)」や「繰り返しショット」があります。実は、先に挙げたエスカ&ロジーのアトリエ第8話でもこの出崎氏を彷彿とさせる演出がこれでもか、と言うほどに取り入れられていました。ハーモニー・繰り返しショットもそうですし、”AIR 劇場版” でもおなじみの「画面分割」も多用されていました。第8話で絵コンテ・演出を担当したのは中野英明氏という方で、出崎手法をふんだんに取り入れることで有名だそうです。おそれいりました。

演出という面で観ていくとまた変わった面白さが見えてきます。そして今回取り上げた出崎氏のアプローチは、日本のアニメーション業界ならでは、あるいはこういった環境でなければ生まれなかったアプローチだと思います。
エスカ&ロジーのアトリエ第8話には他にもいろんな演出が素人目に観てもわかりやすいくらい凝縮されていました。アニメーション制作会社のシャフトの映像作品によく観られる「シャフ度」と呼ばれる構図や、同じくシャフトが担当する作品でよく用いられる下から回り込むカメラも確認できました。
他にも、映画監督のヒッチコックがあみだした「めまいショット」俗にいう「ドリーズーム」も気球のシーンや水晶のカットで見かけることができました。ドリーズームは背景とキャラクターのレイヤーがわかれているセルアニメーションと相性がいいため特にアニメーション作品では多用される傾向にあります。

部内には、ゲームアプリケーションを作成している部員も少なくありません。今回はアニメーションの演出について話しましたが、コンソールゲームを遊ぶときなんかもゲームエフェクトをもう一度確認してみてください。きっと面白い発見ができます。そして面白い発見が出来たら、作成中のゲームに演出やエフェクトを加えてみてください。演出の凝ったゲームを遊べるのを楽しみに、そして Blu-ray では白い湯気と謎の入射光がエンドユーザの望む方向に修正されていることを祈っています。

Roslyn でオリジナル C# を作ろう

先日、.NET の新しいコンパイラーである Roslyn がオープンソースになりました。
つまり、Roslyn をいじれば C# や VB ベースのオリジナル言語が作れちゃいます。

とりあえず、Taking a tour of Roslyn に沿って
Roslyn をビルドしてみましょう。

ビルド環境ですが、
Roslyn は拡張機能として提供されるので VS Express ではできないと思います。
Visual Studio 2013 Professional 以上のエディションを使います。
拡張機能のVSIXパッケージを作成するので VS 2013 SDK が必要です。

まず、Roslyn のビルドには Roslyn が必要です。
プレビューサイトから Roslyn End User Preview をダウンロードします。
Microsoft アカウントでサインインして名前などの入力が必要です。
VSIXパッケージでインストールします。

次に Roslyn のソースコードを入手します。
Git リポジトリなので
git clone https://git01.codeplex.com/roslyn
で入手できます。

Build の Keynote で Anders 氏がデモンストレーションしていた、
«» で挟まれているところを文字列リテラルとする拡張をやってみましょう。
Src\Compilers\CSharp\Source\Parser\Lexer.cs を開きます。
ScanSyntaxToken メソッドの switch 文に文字列リテラルの開始文字として case を追加します。

1
2
3
4
5
6
7
8
9
// Start scanning the token
character = TextWindow.PeekChar();
switch (character)
{
case '\"':
case '\'':
case '«':
this.ScanStringLiteral(ref info);
break;

次に ScanStringLiteral メソッドの if 文に条件を追加します。

1
2
3
4
var quoteCharacter = TextWindow.PeekChar();
if (quoteCharacter == '\'' || quoteCharacter == '"' || quoteCharacter == '«')
{
TextWindow.AdvanceChar();

1
2
3
4
5
else if (ch == quoteCharacter || (ch == '»' && quoteCharacter == '«'))
{
TextWindow.AdvanceChar();
break;
}

コードの変更ができたらビルドします。
結構時間かかります。
ファイルは Binaries/Debug に出力されます。
その場所に Program.cs を作成して先ほど拡張した文字列リテラルを使うプログラムを書いてみましょう。

1
2
3
4
5
6
7
8
9
10
using System.Console;
class Program
{
static void Main(string[] args)
{
WriteLine();
WriteLine(«Welcome to my version of Roslyn!»);
}
}

コンパイラの実行ファイルは rcsc.exe になっています。
rcsc.exe Program.cs
でビルド。エラーもなくビルドできるはずです。
Program.exe を実行すればちゃんと出力されます。

Roslyn で手軽に C# の拡張ができました。
ソースコード全体は非常に量が多いので読んで理解して色々拡張していくのは大変ですが、
興味のある人は試してみてください。

SZ配列

いまいち C3 内で C# が広まらないことを少々嘆いている今日この頃。
すっかり肌寒くなりましたが、いかがお過ごしでしょうか。

今回は SZ 配列(SZ Array)のお話。
SZ とは “single dimension, zero-base” の略です。
1次元で0が下限の配列……要はよく使う普通の配列ですね。
.NET Framework の中間言語である IL には SZ 配列のために特別な命令が用意されているので、
SZ 配列でない配列に比べパフォーマンスが向上します。

検証してみましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var count = 10000;
var watch = new Stopwatch();
var array1D = new int[count * count];
var array2D = new int[count, count];
var jaggedArray = new int[count][];
for (int i = 0; i < count; i++)
{
jaggedArray[i] = new int[count];
}
watch.Start();
for (int i = 0; i < count * count; i++)
{
array2D[0, 0] = 1;
}
watch.Stop();
Console.WriteLine("array2D : {0}ms", watch.ElapsedMilliseconds);
watch.Restart();
for (int i = 0; i < count * count; i++)
{
jaggedArray[0][0] = 1;
}
watch.Stop();
Console.WriteLine("jaggedArray : {0}ms", watch.ElapsedMilliseconds);
watch.Restart();
for (int i = 0; i < count * count; i++)
{
array1D[0] = 1;
}
watch.Stop();
Console.WriteLine("array1D : {0}ms", watch.ElapsedMilliseconds);

100000000回、配列の一要素に値をセットするだけのコードです。
以前の記事で書いた2次元配列・ジャグ配列と、 SZ 配列を比較しました。

実行結果は以下のとおり。
[text]
array2D : 396ms
jaggedArray : 255ms
array1D : 234ms
[/text]
環境によって多少違いはありますが、上から下にいくほど時間がかからないようになるはずです。
2次元配列は SZ 配列ではないので SZ 配列の1.5倍ほどの時間がかかっています。
ジャグ配列は SZ 配列の SZ 配列なので SZ配列とほぼ変わらない時間になっています。
わずかに遅いのは、参照が1回ずつ多くなるためだと思われます。

配列といっても2次元配列やリストなど様々なものがありますが、
SZ 配列で十分な場合はできるだけ SZ 配列を使うことでパフォーマンスの向上が期待できますね。

参考
配列の Address メソッド