2014/05/17 STAFF BLOG

 KRPanoスクリプトを使ったゲーム制作。前回はパドルが動くところまで作成しましたが、今回は一気にゲームを仕上げます。まずは完成品をご覧ください。

スカッシュゲーム。クリックでスタート。壁に跳ね返るたびに得点が加算される。
自分で作っておきながら、結構難しい。3000点あたりから厳しい。

 ボールと得点表示、スタートとコンティニューが追加されて、ひと通りゲームとしての形が出来上がりました。ソースコードが長くなってしまったので全てを掲載することはできませんが、全部で270行程度のコードに過ぎません(実ステップはもっと少ない)。
 工夫のポイントとしては、「1:壁面に当たるたびにスピードが早くなる」、「2:ボールをパドルで受ける角度によって跳ね返り角度が変化する」といったところです。どちらかというとKRPano特有の工夫というよりも、スカッシュゲーム一般の話題かもしれませんが。
 ボールのスピードについては、以下の定義のようにボールのレイヤーに追加のプロパティを持たせています。

<!-- ボール -->
<layer name="ball"
	url="ball.png"
	width="30" height="30"
	align="topleft"
	edge="topleft"
	zorder="55"
	enabled="false"
	visible="true"
	vector_x="1"
	vector_y="1"
	speed="1.0"
	x="0"
	y="0"
/>

 この中のvector_x,vector_y,speedというプロパティはKRPano標準のものではなく、今回のプログラムで独自に追加したものです。vector_x,vector_yでボールの進行方向のベクトルを保持し、speedに単位時間あたりの移動量をセットします。前回のプログラムでメインループ処理をasyncloopで実装しましたので、単位時間というのは1/60秒になります(理論的には)。壁面に当たるたびに、このspeed値を増やすことで、だんだんとボールが早くなる動きを実現しています。
 2の跳ね返り角度については、少しロジックが複雑です。世間のブロック崩しでは大体2パターンに実装がわかれます。よくあるのが、どんな角度であたってもボールの跳ね返りは常に一定であるタイプ。そして、もうひとつはパドルの端で受けるほど跳ね返り角度が急になるタイプです。往年の名作アルカノイドなどは2番めのパターンで実装されているようです。
 今回のプログラムでは第3のパターンとして、より自然なロジックを実装します。ボールの動きに対して、パドルが同じ方向に動きつつ衝突した場合は角度がより急になり、ボールと反対の向きにパドルが動いていると角度が穏やかになるというアルゴリズムです。パドルの動きによってボールに回転を加えるようなイメージですね。
 まずはパドルの動きを記憶する仕組みです。

<!-- パドル移動 -->
<action name="relocatePaddle">
	sub( paddleX, mouse.stagex, 40 );
	sub( layer[paddle].movement, paddleX, layer[paddle].x );
	copy( layer[paddle].x, paddleX );
</action>

 パドル移動時のハンドラで、前回座標との差分を取得します。このゲームではパドルはマウスに追従するため、特に慣性がかからないので、移動は瞬間の差分だけで捉えています。次に衝突時の判定処理です。

<!-- パドルが右方向へ移動中 -->
if( layer[paddle].movement GT 0,
	if( layer[ball].vector_x GT 0,
		<!-- ボールが右方向へ移動中ならば、右方向へ加速する -->
		div( movement_rate, layer[paddle].movement, 40 );
		if( movement_rate GT 1.0, set( movement_rate, 1.0 ) );
		add( layer[ball].vector_x,movement_rate, 1.0 );
		,
		<!-- ボールが左方向へ移動中ならば、右方向へ減速する -->
		div( movement_rate, layer[paddle].movement, 40 );
		if( movement_rate GT 1.0, set( movement_rate, 1.0 ) );
		sub( layer[ball].vector_x, 1.0, movement_rate );
		decelerateBall();
	);
);

<!-- パドルが左方向へ移動中 -->
if( layer[paddle].movement LT 0
	if( layer[ball].vector_x LT 0,
		<!-- ボールが左方向へ移動中ならば、左方向へ加速する -->
		div( movement_rate, layer[paddle].movement, 40 );
		if( movement_rate LT -1.0, set( movement_rate, -1.0 ) );
		add( layer[ball].vector_x,movement_rate, -1.0 );
		,
		<!-- ボールが右方向へ移動中ならば、右方向へ減速する -->
		div( movement_rate, layer[paddle].movement, 40 );
		if( movement_rate LT -1.0, set( movement_rate, -1.0 ) );
		sub( layer[ball].vector_x, -1.0, movement_rate );
		decelerateBall();
	);
);

 KRPanoの条件分岐文にはクセがあるため、少々読みにくいのですが、上記のコードではボールとパドルの動く方法の組み合わせによってvector_xの値を設定しています。向きが揃えば大きい値になり、逆向きならば小さい値になるイメージですね。また減速効果を高めるために、逆向き時にはdecelerateBall()という関数を呼んでいます。この関数の中身はspeed値を下げる実装になっています。

 KRPanoスクリプトでは、工夫次第でパノラマとは全く関係のないゲームを作ることまで出来てしまいます。QuickTimeVRが誕生して十数年が経過していますが、パノラマVRコンテンツの表現手法はホットスポットや写真のポップアップ表示、バーチャルツアーといったコンテンツが殆どで、画期的な表現というのはあまり目にすることがありません。言語としてのKRPanoは、今回示したように極めて柔軟な表現力を持っていますので、弊社でもパノラマVRコンテンツにどんどん新しい表現を取り込んでいきたいと考えております。