macOSでOpenGLプログラミング（1-2. ウィンドウのリサイズ方法の調整）

[macOSでOpenGLプログラミングの目次に戻る](http://qiita.com/sazameki/items/d060f20f621c658046d9)

# はじめに

[前回](http://qiita.com/sazameki/items/12adb193dc1472c6316a)は、Xcodeのプロジェクトを作成して、OpenGLの基本的な設定を行うところまでの手順を解説しました。

今回は、アプリのウィンドウがリサイズされた時の動作を調整します。

ゲームでは基本的にウィンドウがリサイズできるようにはしませんが、フルスクリーンで表示したいということはしばしばあります（その方が画面リソースが専有できるので処理が多少高速化されるメリットもあります）。そこで、通常の状態ではウィンドウのサイズを固定して、フルスクリーン表示への切り替えは許容するようにします。


# 1. WindowControllerクラスを追加する

ウィンドウのリサイズを制御するためには、ウィンドウがリサイズされたことを通知してもらう必要があります。Storyboardの環境下では、この通知を受け取るもっとも簡単な方法は、独自のWindowControllerクラスを用意して使うことです。

> StoryboardではなくXIBを使用している場合は、AppDelegateクラスにNSWindowDelegateプロトコルを追加して、AppDelegateクラスのインスタンスをウィンドウのデリゲートに指定することで受け取れます。

そこでまず、新しいクラスを作成しましょう。プロジェクト・ナビゲータからMyGLGameフォルダを選択して右クリックし、[New File…]を選択します。

<img width="280" src="https://qiita-image-store.s3.amazonaws.com/0/166309/4d8664ed-5f85-934a-58a9-d3cdf7c92784.png">

表示されたウィンドウで「macOS」の「Cocoa Class」を選択して、「Next」ボタンを押します。

<img width="70%" src="https://qiita-image-store.s3.amazonaws.com/0/166309/b618682f-3e7d-7181-3032-e7cede44e281.png">

次の画面で「Subclass of」の項目に「NSWindowController」と入力し、「Class」の項目に「WindowController」と入力して「Next」ボタンを押し、次の画面では何も変更せずに「Create」ボタンを押して、クラスの作成を完了します。

<img width="70%" src="https://qiita-image-store.s3.amazonaws.com/0/166309/893172c8-c683-3e84-cc39-e2aa065ab138.png">

クラスが作成できたら、WindowController.hとWindowController.mの2つのファイルが追加されます。

<img width="200" src="https://qiita-image-store.s3.amazonaws.com/0/166309/36347b19-7da3-8739-5e17-aa911442e38f.png">


# 2. ヘッダファイルを編集する

WindowController.hを編集して、「NSWindowDelegate」プロトコルの宣言を追加します。

```objc:WindowController.h
#import <Cocoa/Cocoa.h>

@interface WindowController : NSWindowController<NSWindowDelegate>

@end
```


# 3. 実装ファイルを編集する

WindowController.mを編集して、自分をウィンドウ関係のデリゲートとして登録するコードと、リサイズされる時に調整を行うコードを、次のように追加します。

```objc:WindowController.m
#import "WindowController.h"

@interface WindowController ()

@end

@implementation WindowController

- (void)windowDidLoad {
    [super windowDidLoad];

    self.window.delegate = self;
    self.window.frameAutosaveName = @"Main Window";
    [self.window setContentSize:NSMakeSize(640, 480)];
}

- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
{
    if ([self.window styleMask] & NSWindowStyleMaskFullScreen) {
        return frameSize;
    } else {
        NSRect rect = NSMakeRect(0, 0, 640, 480);
        rect = [self.window frameRectForContentRect:rect];
        return rect.size;
    }
}

@end
```

まず「self.window.delegate = self;」で、自分をウィンドウ関係のデリゲートとして登録します。

frameAutosaveNameプロパティに任意の文字列を設定しておくと、ウィンドウ位置が保存されるようになります。ユーザにとっても利便性が高いですし、プログラマとしても、開発中のアプリの画面を左上や左下などに固定しておくと開発効率が高くなるでしょう。

次に `[self.window setContentSize:NSMakeSize(640, 480)];` というコードで、ウィンドウの（内部ビューの）初期サイズを(640, 480)に設定します。

ウィンドウがリサイズされるタイミングで`windowWillResize:toSize:`メソッドが呼ばれますので、ここでフルスクリーンかどうかをチェックして、フルスクリーンでなければ(640, 480)のサイズをリターンして要求サイズを上書きします。なお、(640, 480)のサイズでウィンドウの中身が表示されるようにするためには、ウィンドウのタイトルバーなどを含んだサイズをリターンしなければいけませんので、ここでは `-[NSWindow frameRectForContentRect:]`メソッドを呼び出して、そのための変換を行っています。

こうすることで、ウィンドウモードでは(640, 480)のサイズに固定しながら、フルスクリーンボタンやメニューの[View]-[Enter Full Screen]に対応してフルスクリーンにすることができます。


# 4. Storyboardの編集

最後に、上記の手順で作成したWindowControllerクラスを、Storyboardで使用されるように設定しましょう。

ウィンドウ左端のプロジェクト・ナビゲータで「Main.storyboard」を選択し、「Window Controller Scene」の中の「Window Controller」を選択して、インスペクタの左から3つ目のタブにある「Identity Inspector」で「Custom Class」の「Class」に「WindowController」と入力します。

<img width="560" src="https://qiita-image-store.s3.amazonaws.com/0/166309/d2616903-78f9-2553-86be-136bd5e69fa5.png">

これで自作のWindowControllerクラスが読み込まれて使用されるようになり、内容のサイズが640x480ピクセルに固定され、フルスクリーン実行にも対応できるようになります。実行して確認してみましょう。

　<img width="560" src="https://qiita-image-store.s3.amazonaws.com/0/166309/80dce802-844d-f0ba-62fe-6c3b5af6c182.png">


# 5. まとめ

今回は、ウィンドウのリサイズに対応し、フルスクリーンモードへの変化を許容しながら、ウィンドウモードではリサイズを禁止するようにしました。

なお、**ゲームにおいてはフルスクリーンモードに対応することに意味があります**。それは、フルスクリーンモードにおいては、**他のアプリや他のウィンドウなどの操作に対応しなければいけない可能性が減るので、その処理のためのCPU利用率を減らせる**ということです。フルスクリーンモードでは、他のアプリをまったく気にせずに、フルに効率的な処理が行われるようにチューニングすれば良いということになります。

ここまでのプロジェクト：[MyGLGame_step1-2.zip](http://sazameki.jp/temp/MyGLGame_step1-2.zip)

---
次の記事：[macOSでOpenGLプログラミング（1-3. ゲーム更新用のループを作る）](http://qiita.com/sazameki/items/ff6e2c588a5ac785ad83)