macOSでOpenGLプログラミング(1-4. ゲーム終了時の処理を行う)

macOSでOpenGLプログラミングの目次に戻る

はじめに

前回は、ディスプレイ・リンクを使ってゲーム更新用のループを作成しました。しかしまだ明示的にディスプレイ・リンクを停止する処理を書いていなかったので、今回はゲーム終了時の処理について解説し、ディスプレイ・リンクのクリーンアップ処理も追加しましょう。

1. AppDelegate.mを編集する

アプリケーション終了時には、AppDelegateクラスのapplicationShouldTerminate:メソッドがコールバックされて、本当にアプリケーションを終了して良いかどうかを尋ねてきます。今回のように、ディスプレイ・リンクの処理を停止させたり、ゲーム実行中に作成したテクスチャなどのメモリを解放したりといった処理を行いたい場合には、このメソッドをオーバーライドして、必要なクリーンアップの処理を行ったあと、NSTerminateNowをリターンして「今すぐ終了していいですよ」と返事を返します。

ここでは、MyGLViewクラスのオブジェクトにアクセスするためのsharedInstanceメソッドを使って、ディスプレイ・リンクを停止させるstopDisplayLinkメソッドを呼び出しています。これらのMyGLViewクラスのメソッドについては、後述しています。

なお、MyGLViewクラスにアクセスするために、先頭にMyGLView.hファイルのimport文を追加していますので、ここも忘れないようにしてください。また、最初からAppDelegateクラスに用意されているメソッドは、今後のゲーム開発ではあまり使わなさそうなので、削除しています。

AppDelegate.m
#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:メソッドが呼ばれます。

WindowController.m(一部)
@implementation WindowController

...

- (void)windowWillClose:(NSNotification *)notification
{
    [NSApp terminate:self];
}

...

@end

3. MyGLViewクラスにメソッドを追加する

まずMyGLView.hを編集して、次のように2つのメソッドを宣言します。MyGLViewクラスのインスタンスにアクセスするためのsharedInstanceメソッド(static)と、ディスプレイ・リンクの停止処理を行うためのstopDisplayLinkメソッドです。

MyGLView.h
#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()関数を使って明示的に解放してやる必要があります。

MyGLView.m
#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


次の記事:macOSでOpenGLプログラミング(1-5. ゲーム処理を書くためのC++クラスを作る)

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.