ゲームのタスクシステム

ゲームの場合、イベントドリブンで動くだけでなく、敵キャラが勝手に動くなどの処理を行う必要があります。

これらは、1秒間に60回程、割り込み処理が起こり、その間に一通りの処理をして、待機状態にする事で、一定速度で移動したりする事ができます。
割り込みは、毎回同じメソッドが呼ばれるので、その先でゲームや敵の状態でいろいろと分岐させなくてはなりません。

この時、switch〜case文で分岐させると、物に因ってはかなり長くなり、その分岐で処理時間を食ってしまいますし、コードが読み難くなります。

Objective-Cでは、メソッド名を変数として保存し、その保存していたメソッド名のメソッドに制御を移す、という事ができます。Cの関数ポインタのようなものです。

これを利用して、割り込みが来ると、「割り込み用メソッド名」のメソッドに制御を移すようにすれば、処理の中で、この「割り込み用メソッド名」を書き換えると、次の割り込みでは、書き換えたメソッド名のメソッドが呼ばれ、次の割り込みの制御ができます。

分かりにくいので、例をあげると。

敵に弾が当たったから、次の割り込みは、敵の爆発処理をしたい。

これが、

敵に弾が当たったから、「割り込み用メソッド名」に「敵の爆発処理のメソッド名」を入れておこう。

という事になるんですね。
すると、次の割り込みでは、「敵の爆発処理のメソッド」に制御が移る、という仕組みです。

機能としては、下のようになります。

・すぐに指定したメソッドの実行
・一定割り込み後に、指定したメソッドに制御を移す。
 それまでは、何もしない。
・一定割り込み後に、指定したメソッドに制御を移す。
 それまで、今のメソッドを繰り返す。
・一定割り込み後に、指定したメソッドに制御を移す。
 それまでは、何もしない。
 待っている間にシグナルが来ると、指定したメソッドに制御を移す。
・一定割り込み後に、指定したメソッドに制御を移す。
 それまで、今のメソッドを繰り返す。
 その間にシグナルが来ると、指定したメソッドに制御を移す。

さて、ソースファイルです。

//
//  TRDelayObject.h
//
//  Created by turu on 2014/05/03.
//  Copyright (c) 2014年 turu3net. All rights reserved.
//

#import

@interface TRDelayObject : NSObject

// オブジェクトを作成するクラスメソッド
+ (instancetype) delayObjectWithTargetObject:(id)targetObject
targetMethod:(SEL)targetMethod;
// 制御したいオブジェクトの割り込み処理内に、このメソッドを記載
- (void) action;
// すぐに指定したメソッドの実行し、次からそのメソッドに制御を移す
- (void) doMethod:(SEL) method;
//  次の割り込みで処理を行うメソッドを空にします
- (void) refreshNextTargetMehod;
// 一定割り込み後に、指定したメソッドに制御を移す。
// それまで、今のメソッドを繰り返す。
- (void) runAndReadyForDelayWithNextTargetMethod:(SEL) nextTargetMethod
delay:(NSInteger) delay;
// 一定割り込み後に、指定したメソッドに制御を移す。
// それまでは、何もしない。
- (void) stopAndReadyForDelayWithNextTargetMethod:(SEL) nextTargetMethod
delay:(NSInteger) delay;
// 一定割り込み後に、指定したメソッドに制御を移す。
// それまで、今のメソッドを繰り返す。
// 待っている間にシグナルが来ると、指定したメソッドに制御を移す。
- (void) runAndReadyForDelayBySignalWithNextTargetMethod:(SEL) nextTargetMethod
delay:(NSInteger) delay;
// 一定割り込み後に、指定したメソッドに制御を移す。
// それまでは、何もしない。
//  待っている間にシグナルが来ると、指定したメソッドに制御を移す。
- (void) stopAndReadyForDelayBySignalWithNextTargetMethod:(SEL) nextTargetMethod
delay:(NSInteger) delay;
// シグナルを送る
- (void) signal;

@end



//
//  TRDelayObject.m
//
//  Created by turu on 2014/05/03.
//  Copyright (c) 2014年 turu3net. All rights reserved.
//

#import "TRDelayObject.h"
#import "define.h"

@interface TRDelayObject()

@property (readwrite, nonatomic) BOOL delayFlag;
@property (readwrite, nonatomic) BOOL waitFlag;
// mode selecter
@property (readwrite, assign, nonatomic) id targetObject;
@property (readwrite, assign, nonatomic) SEL targetMethod;
// next mode selecter for waitForAction
@property (readwrite, assign, nonatomic) SEL nextTargetMethod;
@property (readwrite, nonatomic) NSInteger delayCount;

- (instancetype) initWithTargetObject:(id)targetObject
targetMethod:(SEL)targetMethod;

@end

@implementation TRDelayObject

+ (instancetype) delayObjectWithTargetObject:(id)targetObject
targetMethod:(SEL)targetMethod
{
return [[[self alloc] initWithTargetObject:targetObject
targetMethod:targetMethod] autorelease];
}

- (instancetype) initWithTargetObject:(id)targetObject
targetMethod:(SEL)targetMethod
{
self = [super init];
if (self)
{
_targetObject = targetObject;
_targetMethod = targetMethod;
}
return self;
}

- (void) action
{
if (_delayFlag)
{
if (--_delayCount<=0)
{
_targetMethod = _nextTargetMethod;
[self refreshNextTargetMehod];
}
}
if (_targetMethod != (SEL)NULL)
{
[_targetObject performSelector:_targetMethod];
}
}

- (void) doMethod:(SEL) method
{
_targetMethod = method;
[_targetObject performSelector:_targetMethod];
}

- (void) refreshNextTargetMehod
{
_nextTargetMethod = (SEL)NULL;
_delayFlag = NO;
_delayCount = 0;
}

- (void) runAndReadyForDelayWithNextTargetMethod:(SEL) nextTargetMethod
delay:(NSInteger) delay
{
if (_nextTargetMethod != nextTargetMethod)
{
_delayCount = delay;
_nextTargetMethod = nextTargetMethod;
_delayFlag = YES;
}
}

- (void) stopAndReadyForDelayWithNextTargetMethod:(SEL) nextTargetMethod
delay:(NSInteger) delay
{
_delayCount = delay;
_nextTargetMethod = nextTargetMethod;
_delayFlag = YES;
_targetMethod = (SEL)NULL;
}

- (void) runAndReadyForDelayBySignalWithNextTargetMethod:(SEL) nextTargetMethod
delay:(NSInteger) delay
{
_waitFlag = YES;
[self runAndReadyForDelayWithNextTargetMethod:nextTargetMethod
delay:delay];

}

- (void) stopAndReadyForDelayBySignalWithNextTargetMethod:(SEL) nextTargetMethod
delay:(NSInteger) delay
{
_waitFlag = YES;
[self stopAndReadyForDelayWithNextTargetMethod:nextTargetMethod
delay:delay];
}

- (void) signal
{
if (_waitFlag)
{
    _waitFlag = NO;
_targetMethod = _nextTargetMethod;
[self refreshNextTargetMehod];
}
}

@end

次は、制御を行いたいクラスの方の記述です。

// 制御を行うオブジェクト
@property (readwrite, nonatomic, retain) TRDelayObject* modeController;

// 初期化などを行う所で、制御用のオブジェクト作成します。
{
_modeMethod = @selector(stageFirstDirection);
self.modeController = [TRDelayObject delayObjectWithTargetObject:self
targetMethod:_modeMethod];
}

// 制御を行いたいクラスの割り込み処理が来る所
- (void) action
{
// シグナルを送るかどうかの判定
if ([self canStartMusic])
{
// シグナルを送る
[_modeController signal];
}
// 制御オブジェクトの割り込み処理を呼び出す
[_modeController action];
}

// 制御オブジェクトから呼び出されるメソッドの記述例です
- (void) first
{
// ここに処理を記述します。

//上に書いた処理を1度行った後、 60フレーム(割り込み)後、secondメソッドに制御を移します。
[_modeController stopAndReadyForDelayWithNextTargetMethod:@selector(second)
delay:60];
}

- (void) second
{
// ここに処理を記述します。

//上に書いた処理を毎回行った後、 60フレーム(割り込み)後、secondメソッドに制御を移します。
[_modeController stopRunReadyForDelayWithNextTargetMethod:@selector(first)
delay:60];
}

こんな感じで、まるでBasicのジャンプ命令みたいに使えます。

noteだと、インデントが無くなってしまうみたいですね。Xcodeにコピペして見ると、見やすくなると思います。

例によって、このプログラムは現状のまま提供され、バグ不具合がない事は保証されません。

これは、投げ銭用です。
この下に記事はありません。

ここから先は

0字

¥ 100

期間限定 PayPay支払いすると抽選でお得に!

宜しければ、ゲーム制作などのクリエーター活動のサポートをお願い致します。