関連記事
前回作成したアニメーションを使った Android アプリはボールの動きをユーザが操作できるものではありませんでした。今回は加速度センサーを使ってスマートフォンを傾けた方向にボールが転がるようなアプリを作成します。
縦画面固定にする
初めに、スマートフォンを傾けたときに自動で画面が縦横切替してしまわないように縦画面固定の設定をします。縦画面の固定には以下の一文を "AndroidManifest.xml" に追記します。
activity android:screenOrientation="portrait"
- "AndroidManifest.xml" を以下の通り書き換え(赤字の部分を追記)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=
"http://schemas.android.com/apk/res/android"
package="com.example.ball" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name=
"android.intent.action.MAIN" />
<category android:name=
"android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Ball クラスの変更
Ball クラスにボールが転がる速度を表すメンバ変数を追加します。
- "Ball.java" を以下の通り書き換え
public class Ball extends View{ int x, y, radius; float vx, vy; Paint paint; public Ball(Context context) { super(context); radius = 30; vx = vy = x = y = 0; paint = new Paint(); paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.FILL); } protected void onDraw(Canvas canvas){ super.onDraw(canvas); canvas.drawCircle(x, y, radius, paint); } }
加速度センサーの値を取得する
SensorEventListener インタフェースの実装
public class MainActivity extends Activity implements Runnable, SensorEventListener { ... }
SensorManager でセンサーのオブジェクトを取得
SensorManager manager = (SensorManager)getSystemService(SENSOR_SERVICE); List<Sensor> sensors = manager.getSensorList(Sensor.TYPE_ACCELEROMETER);
指定できるセンサーの種類は以下があります。
TYPE_ACCELEROMETER | 加速度センサー |
TYPE_TEMPATURE | 温度センサー |
TYPE_LIGHT | 照度センサー |
TYPE_GRAVITY | 重力センサー |
TYPE_PRESSURE | 圧力センサー |
TYPE_MAGNETIC_FIELD | 地磁気センサー |
TYPE_PROXIMITY | 近接センサー |
TYPE_GYROSCOPE | ジャイロスコープ |
TYPE_LINEAR_ACCELERATION | 直線加速度センサー |
TYPE_ROTATION_VECTOR | 回転ベクトル |
具体的なセンサー値をアプリ内で利用するため onResume() メソッドにセンサー値が変化したことを検知するリスナの登録をします。
@Override
protected void onResume() {
super.onResume();
manager = (SensorManager)getSystemService(SENSOR_SERVICE);
List<Sensor> sensors =
manager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (0 < sensors.size()) {
manager.registerListener(
this, sensors.get(0), SensorManager.SENSOR_DELAY_NORMAL);
}
}
登録したリスナは onPause() メソッドで解除します。
@Override protected void onPause() { super.onPause(); manager.unregisterListener(this); }
加速度センサー値の処理
加速度センサーの値に変化があった場合の処理を onSensorChanged() メソッドに記述します。ここでは x 軸と y 軸方向(スマートフォンを縦に持った場合の水平方向と鉛直方向)のセンサー値を使っています。
@Override public void onSensorChanged(SensorEvent event) { gx = event.values[0]; gy = event.values[1]; }
MainActivity の変更
public class MainActivity extends Activity implements Runnable, SensorEventListener {
SensorManager manager;
Ball ball;
Handler handler;
int width, height, time;
float gx, gy, dpi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
LinearLayout linearlayout = new LinearLayout(this);
linearlayout.setBackgroundColor(Color.GREEN);
setContentView(linearlayout);
time = 10;
handler = new Handler();
handler.postDelayed(this, 3000);
dpi = getResources().getDisplayMetrics().densityDpi;
WindowManager windowManager =
(WindowManager) getSystemService(WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
width = display.getWidth();
height = display.getHeight();
ball = new Ball(this);
ball.x = width / 2;
ball.y = height / 2;
linearlayout.addView(ball);
}
@Override
public void run() {
ball.vx += (float) (-gx * time / 1000);
ball.vy += (float) (gy * time / 1000);
ball.x += dpi * ball.vx * time / 25.4;
ball.y += dpi * ball.vy * time / 25.4;
if (ball.x <= ball.radius) {
ball.x = ball.radius;
ball.vx = -ball.vx / 3;
} else if (ball.x >= width - ball.radius) {
ball.x = width - ball.radius;
ball.vx = -ball.vx / 3;
}
if (ball.y <= ball.radius) {
ball.y = ball.radius;
ball.vy = -ball.vy / 3;
} else if (ball.y >= height - ball.radius) {
ball.y = height - ball.radius;
ball.vy = -ball.vy / 3;
}
ball.invalidate();
handler.postDelayed(this, time);
}
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(this);
}
@Override
protected void onResume() {
super.onResume();
manager = (SensorManager)getSystemService(SENSOR_SERVICE);
List<Sensor> sensors =
manager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (0 < sensors.size()) {
manager.registerListener(
this, sensors.get(0), SensorManager.SENSOR_DELAY_NORMAL);
}
}
@Override
protected void onPause() {
super.onPause();
manager.unregisterListener(this);
}
@Override
public void onSensorChanged(SensorEvent event) {
gx = event.values[0];
gy = event.values[1];
}
@Override
public void onAccuracyChanged(
Sensor sensor, int accuracy) {
}
}
実機にインストールして実行すると、実機を傾けた方向にボールが転がることが確認できます。次はボールを転がす目標を設置してゲームらしく仕上げます。
転がるボールのスピードを遅くすることはできますか?
返信削除もちろんできますよ。
返信削除ボールの速度を計算している箇所を変更するだけです。
上記のMainActivityをそのまま実装すると SensorEventListener インタフェースを追記するところでエラー(Cannot resolve symbol "SensorEventListener" )と出て以降同様なエラーが多数発生するのですが解決策を教えてください。
返信削除前回の”アニメーションを使った Android アプリの作成”では問題なく動作しました。