Javaな日々

NO JAVA, NO LIFE.

コンテナViewControllerを実装してみる

iOS5から実装された機能,コンテナViewControllerを使って,View Controllerの中にView Controllerを配置したい時のメモ.

例として今回はTab Bar ControllerをView Controllerの上に配置してみます.

環境

手順

  1. Storyboardを使ってTab Bar Controllerを配置します.

    f:id:yksris:20121027051611p:plain


  2. 配置したTab Bar ControllerのStoryboard IDをインスペクタから“ContainerTabBarController”とします.また,SizeはFreeFormにしておきます.

    f:id:yksris:20121027054525p:plain


  3. コンテナViewControllerを配置するView ControllerにViewを配置します.これは後にコンテナViewControllerを配置するスペースになります.

  4. 3. で配置したViewをViewControllerクラスのヘッダに関連付けます.

    #import <UIKit/UIKit.h>
    
    @interface ViewController : UIViewController
    @property (weak, nonatomic) IBOutlet UIView *ContainerViewControllerSpace;
    
    @end
    


  5. ViewController.mのviewDidLoadを以下のように処理を追加.

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        UITabBarController *menuViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"ContainerTabBarController"];
        [self addChildViewController:menuViewController];
        [menuViewController didMoveToParentViewController:self];
        [_ContainerViewControllerSpace addSubview:menuViewController.view];
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    


ドラッグ&ドロップ可能なImage Viewをコードで作成

上に更にコンポーネントを置いていきたいので,Image Viewをドラッグ可能にしました.ゲームなどで不特定多数の画像をView上に表示させたい時に便利だと思います.
(Quartz CoreフレームワークのLayerを利用する方法では上にコンポーネントを追加するのは難しいですが,処理が速くアニメーションを多用する場合などでは扱いやすいです.)

コード

コードはXcode 4.5にてARC有効状態で作成した場合の例です.
DraggableImageView.h/.m の詳細は参考サイトを参照してください.

DraggableImageView.h
#import <UIKit/UIKit.h>

@interface DraggableImageView : UIImageView {
    CGPoint startLocation;
}

@end
DraggableImageView.m
#import "DraggableImageView.h"

@implementation DraggableImageView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
    startLocation = [[touches anyObject] locationInView:self];
    [[self superview] bringSubviewToFront:self];
}

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
    CGPoint pt = [[touches anyObject] locationInView:self];
    CGRect frame = [self frame];
    
    frame.origin.x += pt.x - startLocation.x;
    frame.origin.y += pt.y - startLocation.y;
    
    [self setFrame:frame];
}

@end
ViewController.m
#import "ViewController.h"
#import "DraggableImageView.h"

@interface ViewController () 

@end

@implementation ViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    
    DraggableImageView *img;
    img = [[DraggableImageView alloc] initWithImage:[UIImage imageNamed:@"sample.png"]];
    img.userInteractionEnabled = YES;
    [self.view addSubview:img];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

JavaでWaveファイルを再生

Javaで音声ファイルを再生しようと模索していたら JMF(2003年最終リリース)とか JLayerサードパーティでしかも最終リリースが2008年)だとか,怪しいものしか出てこないのでAppletのAudioClipで再生しちゃおうというもの.

import java.applet.Applet;
import java.applet.AudioClip;

public class Main {

    public static void main(String args[]) {

        AudioClip audioClip = Applet.newAudioClip(Main.class.getResource("./sample.wav"));
        audioClip.play();
        // audioClip.stop();
    }
}

// JOGLとかJMFは息吹き返して欲しいなあと思う今日この頃

フレームレートを固定する

久しぶりにコンピュータ倶楽部に顔を出してみたら学祭で展示するゲーム制作の進度がやばいらしく,ゲームとか作ったことのない自分がJava音ゲーを開発している子のところにヘルプに行った.
音ゲーはフレームレート(fps)を固定しないと譜面がずれて大変なことになるらしい(当たり前).

方法

画面描画をwhileループで回していると,計算量や環境,処理時間の差によってフレームレートが変化する.ここで,処理時間+αの時間毎にループするようにしてループ毎の時間を均一化,つまりフレームレートを固定する.
例えばフレームレートを60fpsで固定するときは

1000[ms] / 60[frame] = 16.666…[ms/frame]

1ループにかかる時間が16.666…msとなるように処理の後にsleepするようにする.

以下,参考サイトで見つけたJavaでの実装例.
ところどころで小数点以下の値による誤差を小さくするためにビット演算(高速なため)が使われている.

long error = 0;  
int fps = 60;  
long idealSleep = (1000 << 16) / fps;  
long oldTime;  
long newTime = System.currentTimeMillis() << 16;  

while (true) {  
    oldTime = newTime;  
    
    // ここに1フレームの処理を書く
      
    newTime = System.currentTimeMillis() << 16;  
    long sleepTime = idealSleep - (newTime - oldTime) - error;
    if (sleepTime < 0x20000) sleepTime = 0x20000;
    oldTime = newTime;
    Thread.sleep(sleepTime >> 16);
    newTime = System.currentTimeMillis() << 16;
    error = newTime - oldTime - sleepTime;
} 

工大祭2012

TSUBAME 2.0

IMG_0626

IMG_0623

計算工学専攻の研究室見学

「何年生?」と聞かれて「高専 3 年生です」と答えると,「おぉ!俺も高専から来たんやて!」という反応が多かった.意外と高専から東工大に編入した先輩が多くてびっくりした.

計算工学専攻権藤研究室

ポインタ解析から重大なエラーを回避できるようにするアルゴリズムにアンダーソンのアルゴリズムがある.ただ,このアルゴリズムは非常に計算量が多く,リソースも多く使うため,大規模なプログラム解析には使えない.
→「じゃあこの処理を効率良く計算するために小さく分割して,分散されたノードで効率よく計算しよう」という研究について解説してもらった.

計算工学専攻佐藤研究室

高専から編入した先輩に,Twitter bot を使ってユーザーに広告を送りつけて稼ごうという「趣味」について解説してもらった.「この商品を買った人はこんなものも買ってます」のアルゴリズムや広告表示の仕組みなどをざっくりと聞けた.
人工知能の研究室ってどんな研究してるのかなーと見に行った自分としては,聞きたいことが聞けなかった感じ.

計算工学専攻横田研究室

RAID ライクな,スケーラブルで自立したストレージシステムの研究について解説してもらった.

計算工学専攻吉瀬研究室

一番おもしろかったのは,パイプライン処理についての研究.パイプライン,スーパーパイプライン,スーパースカラはオーソドックス.そこでとある回路の出力(ALU だったっけ…?)に回路をつなげることで,より複雑なパイプライン処理を実現できるようにした,またそれについて実際に回路を組んでパフォーマンス測定をしてみたよって研究でした.

計算工学専攻鈴村研究室情報工学

データをディスクに落とさず直接メモリに読み込んで処理し,その出力を最終的にディスクに落とす,という処理の形の研究をしていた.鈴村先生は IBM の関係者らしく,IBM の製品を使って研究をしているのだとか.

計算工学専攻佐伯研究室

開発工程の 4 段階において各段階の作業の効率化の研究をしていた.保守の段階ではソフトウェアの構造を解析,例えば加算する処理はプログラムの中のどのようなメソッドを経て実行されているかを解析して(Java にそういう仕組があるらしい)プログラムの保守をしやすくするというような研究をしていた.

大容量のSQLファイルをMySQLにインポートする

とあるプロジェクトで100MB(自分的に割と大容量)のSQLファイルを引き継いだので,それをさくらのレンタルサーバーにインポートしてみます.

環境

手順

phpMyAdminであらかじめインポート先のデータベースを作成しておく.
mysqlコマンドを叩いてもいいと思います.)

PuTTYで自分のサーバーに接続.

% ssh [自分のドメイン].sakura.ne.jp

作業しやすいように,カレントディレクトリにインポートするSQLファイルをアップロードしておきます.

mysqlコマンドを叩いてログイン.

% mysql --host=mysql[自分のデータベースサーバーの番号].db.sakura.ne.jp --user=[ユーザー名] --password=[パスワード]

作成しておいたデータベースを選択.

mysql> use db_example

SQLファイルを読み込む.

mysql> \. example.sql

加速度センサの値のノイズ除去

Androidで加速度センサを使ったアプリを書いていて,センサのノイズに悩まされた.
加速度センサの値をそのまま使うとセンサ自体の精度や感度による誤差と小さなブレによって大きなノイズが入る.センサを安定した水平な机に置いていてもセンサの値が常に大きくブレてしまう.

このノイズを除去するために,ローパスフィルタという仕組みがある.

最終的な値X = ひとつ前のXの値 * 0.9 + センサの値 * 0.1

こうすることで高周波な細かいブレが平均化されて,値の推移が滑らかになる.
値の推移の速さはひとつ前のXの値とセンサの値の比率を変えれば変更できる.また,値の精度をもっと高くしたい場合は使う過去の値を増やせばいい.

実際にAndroidでコードを書いてみるとこんな感じ.

public class MainActivity extends Activity implements SensorEventListener {
    
    private SensorManager sensorManager;
    private float x, y, z = 0;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    }
    
    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            x = (float) (x * 0.9 + event.values[0] * 0.1);
            y = (float) (y * 0.9 + event.values[1] * 0.1);
            z = (float) (z * 0.9 + event.values[2] * 0.1);
        }
    }
}