iPad専用アクションゲーム「スライムは投げる」

最近のエントリー

スーファミのラリーゲーム、ジャレコの「ビッグラン」より、2面(砂漠ステージ)のBGMをアレンジしてみました。

NIのWEST AFRICAという専用楽器をいろいろ使ってみたんですが、雰囲気出ましたかね。
http://www.native-instruments.com/jp/products/komplete/orchestral-cinematic/west-africa/

1面のアレンジもありますので、ついでに聴いていってください。

というわけでV-METALで作ってみた第8弾です。

今回はグラディウスII -GOFERの野望-より「Maximum Speed」の微アレンジをお送りします。

実はゲームはほとんどやっていなくって、PC-E版のゲームCDをコンポに突っ込んでよく作業用BGMにしていました。
好きな曲は沢山ありますが、これはその中でものすごく好きだった一曲です。

ミックスが相変わらずダンゴですが、大音量でおききくださいませ。

こんにちは、たかぼーPです。
初音ミクV3発売を記念して久々にカバー曲を作ってみました。
お聞き苦しい点は多々あるかと思いますがヘッドフォン等で大音量でお聞きください。

▼ニコニコ

▼YouTube

音 : たかぼーP (https://twitter.com/takabosoft)
イラスト : endlesscat様(http://piapro.jp/endlesscat)よりお借りいたしました。
動画 : aknk様 (https://twitter.com/aknk) にご協力いただきました。
原曲 : http://www.youtube.com/watch?v=IxxstCcJlsc

(さらに…)

一つ前の投稿と関連していますが、例えば巨大な画像をロードしてUIImageViewに貼ったとして、何かしらInstrumentsのグラフに大きな変化が見られるかと思ったんです。
ところが実際にInstrumentsを動かしてみると、UIImageのメモリ消費量は48byte…ってまあそりゃあCGImageとかラップしてるだけのクラスでしょうから実体は別のところにあるんだろうって事は予想がつきますね。

で….実体はどこにあるんでしょう…。
(たぶんOpenGLのテクスチャか何かになっていると思うのですが。)

#Activity Monitorにはそれなりに反応が有るっぽいんですが…

ARCのおかげでメモリリークの心配も無くなりヒャッハーしていたところ、メモリが枯渇するという問題に打ち当たりました。

よくARCでも以下の話は耳(目)にしますね。

  • autoreleaseオブジェクトがループ処理などで溜まり、メモリが枯渇する(@autoreleasepoolで回避)
  • [UIImage imageNamed:]が画像をキャッシュするから避けた方がよい
  • 相互参照などでメモリがリークしてしまう(弱参照などで回避)

この辺は自分でも気をつけて開発をしていたつもりなのですが、動作テストを行っているうちに、「ゆっくりと操作しているうちは問題無いのに、素早く操作をするとメモリが枯渇する」という挙動がみられました。

というわけで、ARCの挙動を確認すべく、簡単なサンプルを作ってみました。

#import "ViewController.h"

#define ImageSize CGSizeMake(2000, 2000)

@implementation ViewController
{
    int _click;
    UIImageView *_imageView;
}

- (void)loadView
{
    [super loadView];
    self.view.backgroundColor = [UIColor whiteColor];
    self.view.multipleTouchEnabled = YES;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"%d", ++_click);
    
    // 以前作ったものを破棄
    if (_imageView != nil) {
        [_imageView removeFromSuperview];
        _imageView = nil;
    }
    
    // でかい画像を作る
    UIGraphicsBeginImageContext(CGSizeMake(2000, 2000));
    [[UIColor colorWithHue:(float)rand() / RAND_MAX saturation:1 brightness:1 alpha:1] set];
    CGRect rc = {0};
    rc.size = ImageSize;
    UIRectFill(rc);
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    // ImageViewで貼る
    _imageView = [[UIImageView alloc] initWithImage:img];
    _imageView.frame = CGRectMake(50, 50, 300, 300);
    [self.view addSubview:_imageView];
}

@end

ソースを見ていただければ一目瞭然ですが、タッチすると大きなサイズのUIImageを作って、UIImageViewにはめ込んでビューに追加するというものです。
タップ二度目以降は、前回のUIImageViewをremoveFromSuperviewしてnilしているので、参照カウンタが0になり、UIImageViewもUIImageもARCにより解放されるであろうと思って組んだものです。
(要はUIImageViewとUIImageは最大1つしか存在しないつもりで書いたプログラムです。)

実際にiPad2(iOS6.1.3)で動かしてみると、ゆっくりとタップしている場合は何回タップしてもメモリが枯渇する事はありませんが、両手を使って(マルチタッチ対応なので)素早く連打すると、だいたいカウンタ40ぐらいでメモリが枯渇してアプリがクラッシュします。

こういった挙動を見ると、「CPUが暇な時に何か解放する処理が走っている」と考えるのが自然だと思うのですが、そういった挙動が果たして公式な動作として存在するのかどうか。いや、有るならば本当にメモリが枯渇しそうになったときにアプリが一瞬止まっても構わないので溜まっているメモリを強制的に解放する術がないのか(むしろ勝手にやってくれないのか)など、疑問は尽きません。

この辺、お詳しい方がいらっしゃいましたら、メールまたはツイッター(@takabosoft)などでご教示願えると助かります。
(なんだかすごく初歩的な話のような気がしてならないですが。)

ちなみに、今回のテストプログラムに限っては以下の一行を入れると素早く操作しても枯渇しないで済みます。

    // 以前作ったものを破棄
    if (_imageView != nil) {
        _imageView.image = nil; // この一行を入れる
        [_imageView removeFromSuperview];
        _imageView = nil;
    }