はじめに
前回は、ディスプレイ・リンクを使ってゲーム更新用のループを作成しました。しかしまだ明示的にディスプレイ・リンクを停止する処理を書いていなかったので、今回はゲーム終了時の処理について解説し、ディスプレイ・リンクのクリーンアップ処理も追加しましょう。
1. AppDelegate.mを編集する
アプリケーション終了時には、AppDelegateクラスのapplicationShouldTerminate:
メソッドがコールバックされて、本当にアプリケーションを終了して良いかどうかを尋ねてきます。今回のように、ディスプレイ・リンクの処理を停止させたり、ゲーム実行中に作成したテクスチャなどのメモリを解放したりといった処理を行いたい場合には、このメソッドをオーバーライドして、必要なクリーンアップの処理を行ったあと、NSTerminateNow
をリターンして「今すぐ終了していいですよ」と返事を返します。
ここでは、MyGLViewクラスのオブジェクトにアクセスするためのsharedInstance
メソッドを使って、ディスプレイ・リンクを停止させるstopDisplayLink
メソッドを呼び出しています。これらのMyGLViewクラスのメソッドについては、後述しています。
なお、MyGLViewクラスにアクセスするために、先頭にMyGLView.hファイルのimport文を追加していますので、ここも忘れないようにしてください。また、最初からAppDelegateクラスに用意されているメソッドは、今後のゲーム開発ではあまり使わなさそうなので、削除しています。
#import "AppDelegate.h"
#import "MyGLView.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
{
[[MyGLView sharedInstance] stopDisplayLink];
return NSTerminateNow;
}
@end
2. WindowController.mを編集する
テンプレートからアプリケーションを作成した時点でのデフォルトの動作としては、ウィンドウが閉じられても、アプリケーション自体は実行が続いている状態になっています。そこでウィンドウのデリゲートであるWindowControllerクラスに処理を追加して、ウィンドウが閉じられたらアプリケーションも終了するようにコードを書きます。
次のようなwindowWillClose:
メソッドを、WindowController.mファイルの中に追加します。「NSApp」というのは、アプリケーション全体の操作を行うためのNSApplicationクラスのインスタンスにアクセスするために用意されているグローバル変数です。この変数に対してterminate:
メソッドを呼び出すことで、アプリケーションの終了がリクエストされ、結果として、1の手順で追加したapplicationShouldTerminate:
メソッドが呼ばれます。
@implementation WindowController
...
- (void)windowWillClose:(NSNotification *)notification
{
[NSApp terminate:self];
}
...
@end
3. MyGLViewクラスにメソッドを追加する
まずMyGLView.hを編集して、次のように2つのメソッドを宣言します。MyGLViewクラスのインスタンスにアクセスするためのsharedInstance
メソッド(static)と、ディスプレイ・リンクの停止処理を行うためのstopDisplayLink
メソッドです。
#import <Cocoa/Cocoa.h>
@interface MyGLView : NSOpenGLView
+ (MyGLView *)sharedInstance;
- (void)stopDisplayLink;
@end
次にMyGLView.mを編集します。staticなinstance
変数を追加して、MyGLViewクラスのインスタンスを保持して、必要に応じてsharedInstance
メソッドでリターンできるようにします。instance
変数は、initWithFrame:
メソッドで処理化が終わった時点で instance = self;
というコードで初期化しています。
そしてstopDisplayLink
メソッドでは、ディスプレイ・リンクの実行をストップさせるCVDisplayLinkStop()
関数を呼び出してから、ディスプレイ・リンクを解放するCVDisplayRelease()
関数を呼び出します。Core Videoフレームワークのディスプレイ・リンクは、ARCでは管理されませんので、CVDisplayLinkRelease()
関数を使って明示的に解放してやる必要があります。
#import "MyGLView.h"
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl3.h>
static MyGLView *instance = nil;
@implementation MyGLView {
NSOpenGLContext *glContext;
CVDisplayLinkRef displayLink;
float value;
bool hasDisplayLinkStopped;
}
+ (MyGLView *)sharedInstance
{
return instance;
}
...
- (instancetype)initWithFrame:(NSRect)frame
{
...
self = [super initWithFrame:frame pixelFormat:pixelFormat];
if (self) {
instance = self;
[self setWantsBestResolutionOpenGLSurface:YES];
}
return self;
}
...
- (void)stopDisplayLink
{
CVDisplayLinkStop(displayLink);
CVDisplayLinkRelease(displayLink);
}
@end
5. おわりに
今回は、ウィンドウが閉じられたタイミングでの処理も含めて、アプリケーションの終了時の処理を追加しました。これでディスプレイ・リンクを停止させて解放することができましたので、安心してゲームの開発に専念できます。
次からはいよいよOpenGLでの描画処理の実装に入っていきましょう。
ここまでのプロジェクト:MyGLGame_step1-4.zip