星一のはてなブログ

星一です。

自分と RPG ツクール、 20 年の思い出

この記事は「ねとけん Advent Calendar」 20 日目の記事です。

自分が RPG ツクール Super Dante (スーパーファミコン版) に触れてから 20 年が経つ。この記事では、いままで触れたツクールと作ったゲームについて、思い出せる範囲で適当に語る。なお自分は 20 年間エターなり続けたので、まともに完成したゲームはほとんどない。以下、触れたことのあるツクールをほぼ時系列順で述べる (前後しているところもある)。

RPG ツクール Super Dante (SFC)

自分が一番最初に触れた RPG ツクール。たしか攻略本でソフトの存在を先に知った。 RPG が作れるというだけで衝撃的だった。今考えると、魔法のダメージが固定値だけだったりであんまりなのだが、当時はあまり気にしていなかった。

「(タイトル不詳)」

一番最初に作った RPG はたしかシリアス路線だったが、なんの目的もなく主人公が旅立ち、町の人に話しかけるといきなり仲間になったりなど、支離滅裂だった。未完。

「魔王」

シューベルトの魔王を聞いて感動した主人公が、魔王を倒しに行く RPG。町を出るとすぐ魔王がいる。未完。

RPG ツクール 2 (SFC)

RPG ツクール Super Dante の順当な進化版。「ドンドコドンドコ」 BGM やボスの BGM が有名。

「(タイトル不詳)」

4 つ島があって、島ごとにボスを倒すとなぜか隣の島にワープする。まともなストーリーもなく、それゆえ主人公が移動する動機が思いつかなかったのだと思われる。ラスト前のダンジョンの壁に「納豆」が隠されているが、使用効果は忘れた。ほぼ完成。

「(タイトル不詳)」

友達と一緒に作った。正座している婆さんが戦闘で突撃してくるのが印象的で、それ以外覚えていない。未完。

RPG ツクール 3 (PS1)

この頃ゲーム禁止令を食らっていたのであまりやる機会がなかったが、一応触れた。このころのマップエディタの壁と天井の仕組みが、 VX 以降に使われているような気がする。あと魔法に属性の概念がやっと入った。

RPG ツクール 4 (PS1)

サイドビュー戦闘。容量が厳しかったり戦闘が分かりづらかったり、あまり出来がよくなかった印象がある。

烈海王フンッ、ハッ」

中国拳法の達人烈海王が、サンボの達人セルゲイ・タクタロフ (5 人くらいいる) に対して転蓮花をかまして倒す。最初のフィールドにウロウロしているので話しかけるだけで倒せる。アクターのデフォルトに烈海王っぽいキャラがいたから作ったのだと思われる。一応完成。

RPG ツクール GB (GB)

ゲームボーイ版のツクール。 GB だけあって容量が少なかった。高校受験終わって暇だったのでずっとこれで遊んでいた。

「終わらない悪夢」

2 の 48 乗回、人に話しかけないと終わらないゲーム。最後の人のセリフは「ずるするな」。当時の友達にやらせた感想は、 16 ステップ目で「もういい」。

RPG ツクール 95 (PC)

PC 版初のツクール。中学入学記念に買ってもらった。完全網羅ガイドブックは未だに所持している。ツクールの出来としては、 2000 以降に比べるといまいちだが、当時の自分としては PC でツクールが使えるというだけで大変よかった。

「(タイトル不詳)」

We Are The World の BGM を戦闘曲にしただけの RPGMIDI が使えたので浮かれていたのだと思う。家族の感想は「BGM が合わない」。未完。

「MAZE」

ゼルダ風ダンジョンゲーム。当時フロッピー 10 枚くらい。この頃から、自分は迷路ゲームを作るのに向いているのだと悟り始める。そういえばマリオメーカーでもしばらく迷路ばかり作っていた。

RPG ツクール 2000 (PC)

高校受験を終えて買った。解像度が 95 より下がったものの、非常に完成度が高く、現在の MV に至るまで UI がほとんど変わっていない。なおこの作品がきっかけで、ホームページ運営をはじめて、 PerlPHP を覚えて頑張ったりした。

「シモネタクエスト」

なんかいろいろどうしようもない RPG。未完。

「MAZE 2」

MAZE をさらに複雑化したもの。割と好評で、有志によってリメイク版も作られた。自分がツクールで作っていろいろな人にまともにプレイされた、ほぼ唯一の作品。

「MAZE 3」

MAZE 2 とは趣向を変えた、でもやっぱり迷路ゲーム。面倒臭すぎてあまり評判がよくなかったと思われる。

「Sticks」

棒引きで AI と対戦するゲーム。 AI は最善手しか打ってこないので、大体勝てない。

RPG ツクール 2003 (PC)

大学受験終えての久々のツクール。 PC 版初のサイドビュー。バグだらけでできが悪かった。

RPG ツクール XP (PC)

Ruby スクリプトインタプリタが搭載されており、ゲーム自体は Ruby で定義されている。これがきっかけで Ruby を覚えた。これで作ったゲームはなく、スクリプトをいじって遊んでいた (敵に回復アイテムを投げつけられるようにしたり、魔法の単体・全体を選択できるようにしたりするなど)。

この頃から自分でツクールを作りたいという欲望が出始める。

RPG ツクール VX (PC)

XP から「自分でツクールを作りたい」という志向が強くなっていき、あまりツクール自体に触れなくなった。なおこの志向は MV で頓挫することになる。

RPG ツクール VX Ace (PC)

VX のマイナーチェンジ。「特性 (Trait)」が採用されたのが大きな違いだという認識。なお諸事情により 2 本持っている。

RPG ツクール MV (PC)

Ruby ではなく JavaScript が採用された。完成度の高さから、「自分でツクールを作りたい」欲望は霧散した。

不労所得クエスト (仮)」

やる気のない村の若者が、突然勇者だと言われていやいや魔王を倒しに行く RPG。今作ってるよ!

音楽つくーるかなでーる (SFC)

RPG ツクールではないので番外編。作曲ソフト。これもエターなったというかまともに曲が完成していない。

「アフリカ」

サンプルで入っていたポップスの音色を全部打楽器に変えた曲。楽器を変えただけなので完成。単なるネタ。

Objective-C++11

この記事は Mac Dev JP Advent Calendar の参加記事 (6 日目) です。

はじめに

この記事では、 Objective-C++ で C++11 を使用する例について紹介します。

Objective-C++ とは

Objective-C++ は、プログラミング言語 Objective-C と C++ とを多重継承したような言語です。お互いの文法がかち合わないので、混在することができます。極稀に文法がコンフリクトしますが、個人的にはそれで困ったことはありません。文法的にほぼ直交し、お互いのオブジェクトを単なるポインタ値とみなしているため、混在させることができるのです。 Objective-C と C++ の機能をオーバーラップさせるようなことはできません。例えば、 Objective-C のクラスを C++ で継承したりするようなことはできません。 Objective-C の ARC を C++ のオブジェクトに適用するといったこともできません。ソースの拡張子は mm が一般的に使われます。

Objective-C++ を利用することで、 C++ の資産を使いつつ Cocoa アプリケーションを開発する、といったことが可能になります。あとは「C++ のヘッダファイルオンリーなライブラリを作りたいのにどうしても Cocoa 使わなきゃいけなくて、でも Cocoa は Objective-C から触らないといけなくて死ぬ」という場合も、 Objective-C++ は有用です。

問題点は、コンパイル時間が遅くなることです。ただでさえ複雑な文法を持つ Objective-C と C++ が混ざることで、コンパイル速度はかなり遅くなります。

Objective-C++ の例

#import <Cocoa/Cocoa.h>

@interface Bar : NSObject
@end

@implementation Bar
- (void)hello {
  NSLog(@"Hello!");
}   
@end

class Foo {
private:
  Bar* bar_;
public:
  Foo(Bar* bar)  
    : bar_(bar) {
  }
  void hello() {
    [this->bar_ hello];
  }
};

int main() {
  Bar* bar = [[Bar alloc] init];
  Foo foo(bar);
  foo.hello();
}

Objective-C の世界と C++ の世界とが見事に入り交じっていることがわかりますね。これを test.mm という名前で保存したとして、次のようにすればコンパイルされ、 test という名前の実行ファイルができます:

clang++ -x objective-c++ -stdlib=libc++ -framework Cocoa -o test test.mm

C++11 とは

C++11 は、 2011 年に ISO で承認された C++ の最新標準規格です。 ISO に承認される前までは C++0x と呼ばれていました。 C++03 に対し大幅な機能追加が行われています。

宣伝

Ebiten (海老天) という 2D ゲームライブラリを作っています。 C++ ヘッダファイルオンリーなライブラリを目指すため、本稿のテーマである Objective-C++11 を活用しています。 API やコンセプトが毎日のように変わるので実用段階には程遠いです。

準備

最新の clang++ が必要になりますが、これは最新の Xcode 4.2 に含まれています。 App Store で落としましょう。でかいので落とすのに毎度とても時間がかかります。ほんとうに何とかして欲しいですね…。ちなみに gcc では、 Objective-C++ は扱えますが、 Objective-C++ と C++11 とを両立させることができません。

clang++ オプション

clang++ に、以下のオプションが必要です:

-x objective-c++ # 言語の指定
-std=c++0x # C++11 での指定。近い将来には -std=c++11 になるはず。というかなっている?
-stdlib=libc++ # 標準ライブラリの指定

標準ライブラリの指定はなんで要るのかよく分からないのですが、指定しないと動きません。

Xcode での使い方

割愛。コンパイラオプション追加すればいけるでしょう。

実際にやってみた

型推論

例えば

NSApplication* app = [NSApplication sharedApplication];
HogehogeController* controller = [[HogehogeController alloc] init];
[app setDelegate:controller];
[app run];

と書いていたのを

auto app = [NSApplication sharedApplication];
auto controller = [[HogehogeController alloc] init];
[app setDelegate:controller];
[app run];

と書けるようになります。長い型名も書かなくて済みます。 id 型と違って、静的に型が定まるものなので、コンパイル時の検査がより強力になります。 C++11 の機能の中で、 Objective-C にも適用でき、かつ実用的である唯一の例だと思います。

範囲 for

// clang++ 3.0 では initializer list が未実装なので、仕方なく要素一個一個追加している
std::vector<std::string> cppArray;
cppArray.emplace_back("Foo");
cppArray.emplace_back("Bar");
cppArray.emplace_back("Baz");
// C++11 の範囲 for
for (auto str : cppArray) {
  cppResult += str;
}
NSLog(@"%@", [[NSString alloc] initWithCString:cppResult.c_str()
                                      encoding:NSUTF8StringEncoding]);

NSString* objcResult = @"";
NSArray* objcArray = [NSArray arrayWithObjects:@"Foo", @"Bar", @"Baz", nil];
// Objective-C の範囲 for
for (NSString* str in objcArray) {
  objcResult = [objcResult stringByAppendingString:str];
}
NSLog(@"%@", objcResult);

二種類の for が混在できます。細かい文法が違います (コロンと in)。とても不気味ですね。

NSArray に C++11 の範囲 for を適用させることは不可能ではないと思いますが、ほとんど意味が無いと思います。やるとしたら std::begin/end の NSArray* による特殊化を行うことになるでしょう。

その他

追加された標準ライブラリ (thread など) も問題なく使用出来ました。

nil の代わりに nullptr を書いたりも出来ました。ただメリットは皆無であり、お互い同じ値である保証は全く無いので、辞めたほうが良いでしょう。

clang++ には C++11 のフル機能が実装されているわけではありません。詳しくは Clang - C++ and C++'11 Status を参照しましょう。例えば 2011 年 12 月 6 日 (日本時間) 現在では、 Initializer List やラムダ式などが使えません。

まとめ

本記事では、 Objective-C++ で C++11 の機能を問題なく使えるよ、ということを示しました。「C++11 の新機能で Objective-C で使うとかっこいい機能」というのが思ったよりもなかったのが残念です。 Objective-C型推論出来てすげーと思って書き始めたものの、他に思ったより面白い例がなく、何が嬉しいのかよく分からない記事になってしまいました。

追伸

はてなブログってスーパー pre 記法に色つけられないのかな?