Android4.4において新機能の歩数計機能がリリースされました。
そこで今回はこの機能を利用し、1990年代後半にヒットしたおもちゃの「ドラゴンクエスト あるくんです」(以下「あるくんです」)のようなゲームを作ってみたいと思います。


 

「ドラゴンクエスト あるくんです」とは

「あるくんです」はスライムをプレーヤーが実際に歩きながら育てるゲームです。

当時、「たまごっち」や「デジタルモンスター」などの育成型携帯ゲーム機が流行し、それら育成型のゲームと、実際に「歩く」という行為の相性が非常によく、人気となりました。

「あるくんです」では、歩いている途中には敵がでてくることがあります。また、歩くと「なじみ度」と呼ばれるゲージが上がって、スライムが進化をしたり、異なるマップに入り地形がかわったりします。

開発する機能の選定

その他にも細かい要素がありますが、今回は開発する機能を以下の4点にしぼりたいと思います。

  1. 歩数をカウントする(Sensorなど)
  2. スライム・地形がアニメーションする(SurfaceView, Canvasなど)
  3. 敵が出現する(Dialogなど)
  4. 効果音が出る(SoundPoolなど)

機能要件が決まったので、ここからは1点ずつ開発していきます。全体のソースコードファイルは本文最後にて共有いたしますので、簡単に説明していきます。

1.歩数をカウントする

歩数をカウントする際にはSensorを利用します。さらにSensorManagerも利用し、Sensorを取得します。Android4.4ではSensor.TYPE_STEP_COUNTERという変数を使うことで歩数が取得できるようになります。
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
countSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
}

if (countSensor != null) {
mSensorManager.registerListener(countSensorListener, countSensor, SensorManager.SENSOR_DELAY_GAME);
} else {
Toast.makeText(this, "このデバイスではステップカウンターを利用できません", Toast.LENGTH_LONG).show();
// 歩数を感知するためのセンサー
mSensorManager.registerListener(shakeSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;
mSensorManager.registerListener(shakeSensorListener,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
Android4.3以下の場合には加速度センサーをうまく利用して歩いた時の振動を検知するようにします。

SensorManager#registerListenerの第三引数とSensorManager#getDefaultSensorの第二引数ではアプリの目的に合わせて感度を変更することができます。

また「あるくんです」では、歩数をカウントする・振動を検知する度に独特の「カチャ」という音がするのが印象的でした。今回はそれも再現していきます。

SensorEventListnerで歩行を検知し、1歩歩いた際に音を鳴らすようにします。この時SoundPoolを使用します。SoundPoolについては後で詳しく説明します。
private final SensorEventListener countSensorListener = new SensorEventListener() {

@Override
public void onSensorChanged(SensorEvent event) {
steps = event.values[0];
if(!isFinishing()){
if(isSoundPoolLoaded){
// ゲームを進行させるための独自メソッド
onStepCounted();
}
}
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}
};

2.スライム・地形がアニメーションする

ゲームなど素早く描画をしたい時にはSurfaceViewを用います。SurfaceViewでは別スレッドを使えるので、高速で描画をすることができます。1のSensorEventListnerで歩行を検知した際にスライムも歩いているような動きを表現するため、SurfaceViewを利用した背景を動かします。

歩数をカウントするとSurfaceViewの背景が動く

歩数をカウントするとSurfaceViewの背景が動くようにする(左:歩行前、右:歩行後)



このときスライムは、その場でネチョネチョ動くようにします。タイマーを利用してImageViewを定期的に変更します。また、一定歩数を歩いたら進化するようにします。
今回使用したスライムをアニメーションさせる画像素材。筆者の手書きである

今回使用したスライムをアニメーションさせる画像素材。筆者の手書きである

private void animateSlime(final int ...resId){
slimeState = 1;
mHandler = new Handler();
mTimer = new Timer(true);
mTimer.schedule( new TimerTask(){
@Override
public void run() {
mHandler.post( new Runnable() {
public void run() {
if(slimeState == 1){
mainImageView.setImageResource(resId[1]);
slimeState = 2;
}else if(slimeState == 2){
mainImageView.setImageResource(resId[0]);
slimeState = 1;
}else{
mainImageView.setImageResource(resId[0]);
slimeState = 1;
}
mainImageView.invalidate();
}
});
}
}, 3000, 3000);
}
 
スライムがネチョネチョ動く

スライムがネチョネチョ動く



3.敵が出現する

一定歩数歩いたら、敵が出現するようにします。Dialogを利用して、敵と戦闘するシーンを表示します。「あるくんです」では、スライムが敵に遭遇した際に、ボタンをおして応援することができたので、今回の開発でもスライムを応援することができるようにします。
敵が出現した時に表示させるダイアログを応援することができる

敵が出現した時に表示させるダイアログ。「応援する」ボタンをつけてスライムを応援することができる


また「あるくんです」では敵が倒れる際、敵が点滅していました。ここでもタイマーを利用して、ImageViewに表示する画像を一定間隔で変更するようにします。

4.効果音が出る

1で少し触れましたが、歩数をカウントするときや敵を倒したとき、進化するときなどには効果音をつけるためにSoundPoolを利用します。SoundPoolは短時間で再生が終了する音源を再生する際に利用することが多いです。逆に、BGMとして使いたい曲であればMediaPlayerを利用して再生や停止をコントロールします。
soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
clearSoundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
if (0 == status) {
isSoundPoolLoaded = true;
}else{
isSoundPoolLoaded = false;
}
}
});

SoundPoolでは、音源を再生する前に音源を明示的に読み込んでおく必要があります。読み込みが完了しているかどうかはsetOnLoadCompleteListenerを利用することでわかります。また、SoundPoolで音源を大量に読み込むとメモリリークの原因になりますので、Activityが破棄される際には、同時にSoundPoolも解放しましょう。
@Override
protected void onDestroy() {
super.onDestroy();
if(soundPool != null){
soundPool.release();
}
if(clearSoundPool != null){
clearSoundPool.release();
}
if(mTimer != null) mTimer.cancel();
mTimer = null;
mHandler = null;
}

おわりに

以上で非常に簡単にですが、「あるくんです」のようなゲームをつくることができました。ソースコードはプロジェクトファイルとしてこちら (Github) にアップロードしてありますので、ご利用ください。

※バックグラウンドでの歩数カウント処理は省略しているため、歩数計を試す際はアプリを起動し、スクリーンを表示したままにしてください。




■容量たっぷり20GB、国内通話5分無料も付いて、2970円(税込)


※記事内容は執筆時点のものです。最新の内容をご確認ください。
※OSやアプリ、ソフトのバージョンによっては画面表示、操作方法が異なる可能性があります。