Spritekitを利用したゲームAIの実装改

ディープラーンングなどは及びもつかないものの、 iPhoneアプリにゲームとしてユーザーをもてなす以上、 規模は小さいながらもユーザーの入力に対する反応を返すアルゴリズムを用意すべし、 とて此れを ゲームAI として手元の開発ゲーム バルーンズ・オキュパイ への実装の取っ掛かりを記した記事が2017年10月6日に本ブログに配信した以下の記事でした。

Spritekitを利用したゲームAIもどきの実装

ゲームAI擬きの改善

本記事には此の前記事に紹介したコードを今一歩進めた考察を記す処です。 其の要件としては前記事に於いては キャラクターの出現ポイント検出の処理と移動の処理を任意単位時間、2秒に1回 としており、 此れを同時に処理していたのでユーザーの待ち時間が多くてゲームとして成り立たないので 此れを解決したい、と言うものです。 従って任意単位時間の取り扱いについて考える必要があります。 本ブログには此れに関して2017年10月24日に以下の記事を配信しています。

スポンサーリンク
日付:2014年4月17日
開発機:MacBook Air(11-inch, Mid 2013)
MacOSバージョン:OS X 10.9.2
Xcodeバージョン:5.1
言語:Objective-C
主関連アプリ:Balloons Occupy(邦題:バルーンズ・オキュパイ、バルオキュ)

複数の任意時間に於けるコールバックメソッド

実は此の記事は其れこそゲームAIの改善の為に実装を進めた際の考察を元にしたもので、 前記事から本記事へと論を進め、間を埋めるべくして生まれた記事であるのは、 更に本ブログに遡った2017年3月27日の以下の記事の改善版として題目に 複数 を含む処からも判られるでしょう。

-(void)update:(CFTimeInterval)currentTimeメソッドに於ける任意時間のコールバックメソッド

任意単位時間を複数設けた上で、キャラクター はなまる の移動を扱う任意単位時間と、 バルーン陣地の拡大を扱う任意単位時間に分けて処理し、 後者の方のコールバックメソッド中に キャラクター出現ポイント検出の処理を移行させたのです。

実稼働コード

以上、複雑に見える書きっ振りですが、 実は前記事からほんの形式的な微調整のみの記述で見た目に上手く思惑通りの稼働に成功しています。 後で問題の出る可能性もあり、徹底的に検証した訳ではないので プログラムのリファクタリングは必要になるでしょうが、 コードは以下の様に書いて実稼働を得ました。

- (void)updateWithTimeSinceLastBallonIncrease:(CFTimeInterval)timeSinceLast {
	self.lastBalloonIncreaseTimeInterval += timeSinceLast;
	if (self.lastBalloonIncreaseTimeInterval > 0.3) {
		self.lastBalloonIncreaseTimeInterval = 0;
		/* Called before each frame is rendered */
		if (touchDetect) {
			balloon.xScale *= 1.02;
			balloon.yScale *= 1.02;
		}
		/* 出現ポイントの取り出し */
		if (appearPoints.count > 0) {
			if (collisionDetect) {
				[apperaPoint removeFromParent];
				collisionBalloonOccupyDetect = NO;
				/* 出現ポイントをランダムに設定 */
				int tempAPNum = arc4random_uniform((unsigned int)appearPoints.count);
				SKSpriteNode *aptemp = [appearPoints objectAtIndex:tempAPNum];
				
				aptemp.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:aptemp.size];
				aptemp.physicsBody.categoryBitMask = categoryHanamaru;
				aptemp.physicsBody.contactTestBitMask = categoryBallonOccupy | categoryWhole;
				aptemp.physicsBody.affectedByGravity = NO;
				aptemp.physicsBody.dynamic = NO;
				aptemp.name = [NSString stringWithFormat:@"%d", tempAPNum];
				
				apperaPoint = aptemp;
				
				[self addChild:apperaPoint];
				
				collisionDetect = NO;
			}
		}
	}
}
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {
	self.lastSpawnTimeInterval += timeSinceLast;
	if (self.lastSpawnTimeInterval > 3) {
		self.lastSpawnTimeInterval = 0;
		/* はなまる追加 */
		/* 出現ポイントの取り出し */
		if (appearPoints.count > 0) {
			if (collisionDetect) {
				if (!collisionBalloonOccupyDetect) {
					[hamanaru runAction:[SKAction sequence:@[
						[SKAction moveTo:apperaPoint.position duration:0.5],
						[SKAction waitForDuration:1.0f]
					]]];
				}
			}
		}
	}
}

此のコードに於いては第一の短い任意単位時間、0.3秒間について 出現ポイントオブジェクトの生成と衝突判定とオブジェクト消去を繰り返しており、 第二の長い任意単位時間、3秒間についてはキャラクターはなまるの移動を処理しているだけで 両者を取り持つのはインスタンス変数オブジェクトの apperaPoint のみです。 詰まり第一の短い任意単位時間で繰り返し処理する apperaPoint の偶々第二の長い任意単位時間の タイミングで存在していた位置へキャラクターは動く事になる勘定です。 当初想定していたアルゴリズム、 即ち出現ポイントを保存して第一の短い任意単位時間から第二の長い任意単位時間へ渡す処理、 とは異なりますが特に此れで問題ない処理が見て取れるので良しとしました。

逆張りAI

一つ、本記事で述べた処のゲームAIについて意見を述べれば、 現今主流の人工知能、AIの構成に寄与する統計、確率や巨大なデータなどとは無縁なものの、 其れ等複雑さの極みの返って逆を行くべく、 ユーザーの感情に起伏を齎す為のアルゴリズムが単純であれば単純であるほど ゲームAI製作者として満足を覚えるのはとても面白く思うのです。

Balloons Occupy
無料:カテゴリ: ゲーム: 4+ 評価
バージョン: 3.0
リリース: 2015年1月29日
更新: 2020年9月1日
サイズ : 13 MB
互換性: iOS 8.0 以降のiPhone、iPod touch に対応。および、macOS 11.0以降とApple M1 チップを搭載したMac に対応。