カテゴリー:
Androidプログラミング入門
- 独りで学べるスマホアプリの作り方 -
閲覧数:325 配信日:2018-05-14 13:11
コード
▼/sample2/MainActivity.java
package biz.answerlead.sample2;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import biz.answerlead.sample2.Drum.Type;
/** メイン画面 */
public class MainActivity extends AppCompatActivity implements OnTouchListener {
/** ドラム音管理オブジェクト */
private final Drum drum = new Drum();
/** ドラム画像横幅 */
private static final int DRUM_WIDTH = 1920;
/** ドラム画像縦幅 */
private static final int DRUM_HEIGHT = 1411;
/** 初期化イベント */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// レイアウト設定
setContentView(R.layout.activity_main);
// ドラム描画領域設定
ImageView drum_image = (ImageView) findViewById(R.id.DrumImage);
drum_image.setOnTouchListener(this);
}
/** アプリ開始時、再開時イベント */
@Override
protected void onResume() {
super.onResume();
// 指定ドラム音の読み込み
drum.load(this);
}
/** アプリ中断時イベント */
@Override
protected void onPause() {
super.onPause();
// アプリ未使用時はメモリ節約のため、ドラム音データを開放
drum.release();
}
/** 画面タッチイベント */
@Override
public boolean onTouch(View v, MotionEvent event) {
// 動作ID
int action = event.getActionMasked();
// ポインタID
int index = event.getActionIndex();
// タッチX座標
double touch_x = event.getX(index);
// タッチY座標
double touch_y = event.getY(index);
// 画面横幅
int wx = v.getWidth();
// 画面縦幅
int wy = v.getHeight();
// 動作IDからログ表示用文字列を設定
String action_name;
switch (action) {
case MotionEvent.ACTION_DOWN:
action_name = "ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
action_name = "ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
action_name = "ACTION_UP";
break;
case MotionEvent.ACTION_POINTER_DOWN:
action_name = "ACTION_POINTER_DOWN";
break;
case MotionEvent.ACTION_POINTER_UP:
action_name = "ACTION_POINTER_UP";
break;
default:
action_name = "OTHER";
break;
}
// ログ出力
Log.v("Touch", String.format(
"A:%20s P:%d/%d X:%5.1f Y:%5.1f",
action_name,
index, event.getPointerCount(),
touch_x, touch_y));
// タッチ開始イベントの場合
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
// 画面と用意した画像の比
double multi;
// 画面の縦横比と用意した画像の縦横比を比べて処理を分岐
if (wx * DRUM_HEIGHT > wy * DRUM_WIDTH) {
// 画面の方が横長な場合は、縦の比率を基準に
multi = (double) DRUM_HEIGHT / wy;
} else {
// 画面の方が縦長な場合は、横の比率を基準に
multi = (double) DRUM_WIDTH / wx;
}
// タッチした座標を画像上での座標に変換
double x = (touch_x - wx / 2.0) * multi + DRUM_WIDTH / 2.0;
double y = (touch_y - wy / 2.0) * multi + DRUM_HEIGHT / 2.0;
// バスドラム部分(円で判定)
if (getDistance(x, y, 960, 960) < 361) {
drum.play(Type.BASS);
}
// ロータム部分
if ((getDistance(x, y, 388, 689) < 261) || (getDistance(x, y, 1532, 689) < 261)) {
drum.play(Type.LOW_TOM);
}
// ハイタム部分
if ((getDistance(x, y, 714, 244) < 196) || (getDistance(x, y, 1206, 244) < 196)) {
drum.play(Type.HI_TOM);
}
// シンバル部分
if ((getDistance(x, y, 288, 127) < 238) || (getDistance(x, y, 1632, 127) < 238)) {
drum.play(Type.CYMBAL);
}
// 座標を情報をデバッグログに表示
Log.d("DEBUG", String.format("画面サイズ(%4d, %4d) 変換前座標(%4.0f, %4.0f) 変換後座標(%4.1f, %4.1f)", wx, wy, touch_x, touch_y, x, y));
}
// 続けてタッチイベントを取得する場合はtrueを返却
// ※falseの場合は1点目のタッチ開始イベントしか掴めない
return true;
}
/** 2点間の距離を求める関数(三平方の定理) */
private double getDistance(double x1, double y1, double x2, double y2) {
return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
}
▼/sample2/Drum.java
package biz.answerlead.sample2;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
/** ドラム音管理クラス */
public class Drum {
/** 再生音種別 */
public enum Type {
CYMBAL,
HI_TOM,
LOW_TOM,
BASS,
}
/** 効果音数 */
private static final int SOUND_NUM = Type.values().length;
/** 読込み済みフラグ */
private boolean loaded = false;
/** 音声管理オブジェクト */
private final SoundPool sound_pool;
/** 効果音IDリスト */
private final Integer[] sound_ids = new Integer[SOUND_NUM];
/** 初期化処理 */
public Drum() {
// 音声管理機能初期化(バージョンにより分岐)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// 5.0未満のSoundPool作成方法
sound_pool = new SoundPool(SOUND_NUM, AudioManager.STREAM_MUSIC, 0);
} else {
// 5.0以降のSoundPool作成方法
// 再生する効果音がどういうものなのか用途とデータ種別を指定する
// 今回は最も近い用途としてUSAGE_GAME(ゲーム用)と、
// CONTENT_TYPE_SONIFICATION(ユーザアクションに合わせて再生されるデータ)を指定
AudioAttributes attr = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build();
// 属性と最大再生音数を指定し、SoundPoolを作成
sound_pool = new SoundPool.Builder()
.setAudioAttributes(attr)
.setMaxStreams(SOUND_NUM)
.build();
}
}
/** 指定ドラム音データ読込み */
public void load(Context context) {
// まだ読込みが完了していなければ
if (!loaded) {
// 効果音読込み
sound_ids[Type.CYMBAL.ordinal()] = sound_pool.load(context, R.raw.cymbal, 1);
sound_ids[Type.HI_TOM.ordinal()] = sound_pool.load(context, R.raw.hi_tom, 1);
sound_ids[Type.LOW_TOM.ordinal()] = sound_pool.load(context, R.raw.low_tom, 1);
sound_ids[Type.BASS.ordinal()] = sound_pool.load(context, R.raw.bass, 1);
// 読込み済みとする
loaded = true;
}
}
/** 全てのドラム音データを開放 */
public void release() {
// 読込み済み効果音を開放
for (int i = 0; i < SOUND_NUM; i++) {
if (sound_ids[i] != null) {
sound_pool.unload(sound_ids[i]);
sound_ids[i] = null;
}
}
// 未読込みに戻す
loaded = false;
}
/** 指定音階の再生 */
public void play(final Type sound) {
// 指定Typeのインデックスを取得
final int index = sound.ordinal();
// 指定音階の有効値チェック、及び指定音階の読込み済みチェック
if (sound_ids[index] != null) {
// 音データを再生
sound_pool.play(
sound_ids[index], // 効果音ID
1.0f, // 左音量
1.0f, // 右音量
0, // 優先度
0, // ループ回数
1 // 再生速度
);
}
}
}