вторник, 22 мая 2012 г.

Играем с акселерометром в Android

И ещё одно замечательное устройство в нашем Android-девайсе дождалось своего примера использования. Использование акселерометра занимает особое место в приложениях (особенно в играх) для Android. Камерой и микрофоном мы могли бы пользоваться и в ноутбуке, а вот этим устройством - вряд ли. Только смартфоном можно размахивать из стороны в сторону в игровом процессе, и тут не обойтись без снятия данных с датчика ускорения. Сам процесс получения данных с акселероматра очень прост и не заслуживает отдельной статьи, поэтому мы сделаем небольшую игру, построенную на использовании акселерометра.
Принцип игры будет заключаться как раз в "размахивании" смартфоном: нужно будет махнуть сильнее чем противник, желательно не разбив аппарат при этом ;)
Как и у всякой приличной игры будет возможность сохранить свои достижения и т.п. Итак, приступим:

Вот код нашего единственного класса:

import java.math.BigDecimal;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
 
public class SwayActivity extends Activity implements SensorEventListener {
 
 private TextView ass;
 private EditText mymax;
 private SensorManager mSensorManager;
    private Sensor mAccelerometerSensor;
    private double gravity_const = 9.7;
    private EditText recordName;
    private SharedPreferences prefs;
    private static final String PREFS_RECORD = "records"; 
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        if(sensors.size() > 0) {
            for (Sensor sensor : sensors) {
                if(Sensor.TYPE_ACCELEROMETER == sensor.getType()) {
                    mAccelerometerSensor = sensor;
                    break;
                }
            }
        }
 
        prefs = getSharedPreferences("default", Context.MODE_PRIVATE);
 
        LinearLayout root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);
 
        ass = new TextView(this);
        ass.setTextSize(24);
        ass.setGravity(Gravity.CENTER);
        ass.setText("You result is:");
        root.addView(ass, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
 
        mymax = new EditText(this);
        mymax.setTextSize(22);
        mymax.setFocusable(false);
        mymax.setGravity(Gravity.CENTER);
        mymax.setTextColor(Color.RED);
        mymax.setText("0.0");
        root.addView(mymax, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
 
        LinearLayout buttons = new LinearLayout(this);
        buttons.setBackgroundColor(Color.GRAY);
        buttons.setGravity(Gravity.CENTER);
        buttons.setPadding(10, 5, 10, 5);
 
        Button next = new Button(this);
        next.setText("Reset");
        next.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    mymax.setText("0.0");
   }
  });
        buttons.addView(next, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
 
        Button save = new Button(this);
        save.setText("Save");
        save.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    recordName = new EditText(SwayActivity.this);
    recordName.setHint("You name is...");
    AlertDialog.Builder builder = new AlertDialog.Builder(SwayActivity.this);
    builder.setView(recordName)
       .setTitle("Save record")
          .setCancelable(false)
          .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
               String data = prefs.getString(PREFS_RECORD, "");
               if (data.length()>0){
                data += "|";
               }
               prefs.edit()
                 .putString(PREFS_RECORD, data+recordName.getText()+" - "+mymax.getText())
                 .commit();
               startActivity(new Intent(SwayActivity.this, SwayActivity.class));
               finish();
              }
          })
          .setNegativeButton("No", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int id) {
                   dialog.cancel();
              }
          }).create().show();
   }
  });
        buttons.addView(save, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
 
        root.addView(buttons, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
 
        TextView recordCaption = new TextView(this);
        recordCaption.setText("Saved results:");
        recordCaption.setTextSize(20);
        recordCaption.setGravity(Gravity.CENTER);
        recordCaption.setPadding(5, 10, 5, 10);
 
        root.addView(recordCaption, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
 
        // show records
        String data = prefs.getString(PREFS_RECORD, "");
        if (data.length()>0) {
         ScrollView sw = new ScrollView(this);
         LinearLayout ll = new LinearLayout(this);
         ll.setOrientation(LinearLayout.VERTICAL);
         String[] ss = data.split("\|");
         for (int i=ss.length-1; i>=0; i--) {
          String s = ss[i];
          TextView tw = new TextView(this);
          tw.setText(s);
          ll.addView(tw, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
         }
         sw.addView(ll, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
         root.addView(sw, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
        }
 
        setContentView(root);
    }
 
    @Override
    protected void onPause() {
        mSensorManager.unregisterListener(this);
        super.onPause();
 
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, mAccelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
    }
 
 @Override
 public void onSensorChanged(SensorEvent event) {
        float x = event.values[SensorManager.DATA_X];
        float y = event.values[SensorManager.DATA_Y];
        float z = event.values[SensorManager.DATA_Z];
        double rez = new BigDecimal(Math.sqrt(Math.pow(x, 2)+Math.pow(y, 2)+Math.pow(z, 2))-gravity_const).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        double max = 0.0;
        try {
         max = Double.parseDouble(this.mymax.getText().toString());
        } catch (Exception e) {
   e.printStackTrace();
  }
        if (rez>max) {
         this.mymax.setText(String.valueOf(rez));
        }
 }
 
 @Override
 public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}

Во-первых мы получаем список всех доступных сенсоров с помощью SensorManager и перебираем их, проверяя тип, пока не найдём акселерометр. Потом рисуем интерфейс. В методе onResume вешаем текущий класс слушателем на найденный сенсор.  Убираем слушатель в методе onPause.
Чтобы слушать "сенсорные" события, наш Activity должен реализовать интерфейс SensorEventListener и, соответственно, метод onSensorChanged, в котором из SensorEvent-а мы и получаем значения ускорения по трём осям. Вычисляя среднее квадратичное значение ускорения, проверяем текущее максимальное и наращиваем его, если оно превышено. Когда пользователю надоест размахивать смартфоном, подвергая риску дорогой девайс, даём ему возможность задать своё имя для сохранения рекорда. Для простоты используем для хранения результатов SharedPreferences.
Вот собственно и всё. Как видите, размяться в дружном офисном коллективе можно и с игрой в две сотни сток кода.


Комментариев нет:

Отправить комментарий