Mover una imagen usando el acelerómetro de Android

He leído artículos / tutorial sobre cómo acceder a los valores del acelerómetro del teléfono (aceleración y orientación). Estoy intentando construir una aplicación simple donde puedo mover una imagen de la bola usando estos valores. Aquí está mi código:

import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.view.View; import android.widget.TextView; public class Accelerometer extends Activity implements SensorEventListener { /** Called when the activity is first created. */ CustomDrawableView mCustomDrawableView = null; ShapeDrawable mDrawable = new ShapeDrawable(); int x ; int y ; private SensorManager sensorManager = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Get a reference to a SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); mCustomDrawableView = new CustomDrawableView(this); setContentView(mCustomDrawableView); // setContentView(R.layout.main); } // This method will update the UI on new sensor events public void onSensorChanged(SensorEvent sensorEvent) { { if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { int someNumber = 100; float xChange = someNumber * sensorEvent.values[1]; //values[2] can be -90 to 90 float yChange = someNumber * 2 * sensorEvent.values[2]; x = x + (int)xChange; y = y + (int)yChange; } if (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) { } } } // I've chosen to not implement this method public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } @Override protected void onResume() { super.onResume(); // Register this class as a listener for the accelerometer sensor sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL); // ...and the orientation sensor sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onStop() { // Unregister the listener sensorManager.unregisterListener(this); super.onStop(); } public class CustomDrawableView extends View { public CustomDrawableView(Context context) { super(context); int width = 50; int height = 50; mDrawable = new ShapeDrawable(new OvalShape()); mDrawable.getPaint().setColor(0xff74AC23); mDrawable.setBounds(x, y, x + width, y + height); } protected void onDraw(Canvas canvas) { mDrawable.draw(canvas); invalidate(); } } } 

Estoy consiguiendo una forma ovalada exhibida en la pantalla pero nada sucede después de eso.

Gracias

Utilice este código. Nunca fijaste la ubicación del dibujable después de intializar esa clase. Usted tendrá que hacer algunos cálculos para establecer la ubicación de las bolas correctamente. La forma en que lo hacía era obtener valores de más de 10000 que estaba dibujando el óvalo fuera de la pantalla.

 import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.view.View; public class Accelerometer extends Activity implements SensorEventListener { /** Called when the activity is first created. */ CustomDrawableView mCustomDrawableView = null; ShapeDrawable mDrawable = new ShapeDrawable(); public static int x; public static int y; private SensorManager sensorManager = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Get a reference to a SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); mCustomDrawableView = new CustomDrawableView(this); setContentView(mCustomDrawableView); // setContentView(R.layout.main); } // This method will update the UI on new sensor events public void onSensorChanged(SensorEvent sensorEvent) { { if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // the values you were calculating originally here were over 10000! x = (int) Math.pow(sensorEvent.values[1], 2); y = (int) Math.pow(sensorEvent.values[2], 2); } if (sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION) { } } } // I've chosen to not implement this method public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } @Override protected void onResume() { super.onResume(); // Register this class as a listener for the accelerometer sensor sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL); // ...and the orientation sensor sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onStop() { // Unregister the listener sensorManager.unregisterListener(this); super.onStop(); } public class CustomDrawableView extends View { static final int width = 50; static final int height = 50; public CustomDrawableView(Context context) { super(context); mDrawable = new ShapeDrawable(new OvalShape()); mDrawable.getPaint().setColor(0xff74AC23); mDrawable.setBounds(x, y, x + width, y + height); } protected void onDraw(Canvas canvas) { RectF oval = new RectF(Accelerometer.x, Accelerometer.y, Accelerometer.x + width, Accelerometer.y + height); // set bounds of rectangle Paint p = new Paint(); // set some paint options p.setColor(Color.BLUE); canvas.drawOval(oval, p); invalidate(); } } } 

Aquí está mi aplicación de este problema. La solución de Dymmeh seguía lanzando problemas a mí, así que lo refactoré hasta que lo conseguí trabajando.

 package edu.ian495.accelerometertest; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.view.Menu; import android.widget.ImageView; public class MainActivity extends Activity implements SensorEventListener { private SensorManager sensorManager; private Sensor accelerometer; private long lastUpdate; AnimatedView animatedView = null; ShapeDrawable mDrawable = new ShapeDrawable(); public static int x; public static int y; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main); sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); accelerometer = sensorManager .getDefaultSensor(Sensor.TYPE_ACCELEROMETER); lastUpdate = System.currentTimeMillis(); animatedView = new AnimatedView(this); setContentView(animatedView); } @Override protected void onResume() { super.onResume(); sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME); } @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { x -= (int) event.values[0]; y += (int) event.values[1]; } } public class AnimatedView extends ImageView { static final int width = 50; static final int height = 50; public AnimatedView(Context context) { super(context); // TODO Auto-generated constructor stub mDrawable = new ShapeDrawable(new OvalShape()); mDrawable.getPaint().setColor(0xffffAC23); mDrawable.setBounds(x, y, x + width, y + height); } @Override protected void onDraw(Canvas canvas) { mDrawable.setBounds(x, y, x + width, y + height); mDrawable.draw(canvas); invalidate(); } } } 

He hecho algunos cambios en onSensorCambiar código para mover la pelota en la pantalla. Con el ejemplo en mi caso la pelota no se mueve correctamente y por eso hice los cambios. Este ejemplo funciona bien para mi.

 public void onSensorChanged(SensorEvent sensorEvent) { //Try synchronize the events synchronized(this){ //For each sensor switch (sensorEvent.sensor.getType()) { case Sensor.TYPE_MAGNETIC_FIELD: //Magnetic sensor to know when the screen is landscape or portrait //Save values to calculate the orientation mMagneticValues = sensorEvent.values.clone(); break; case Sensor.TYPE_ACCELEROMETER://Accelerometer to move the ball if (bOrientacion==true){//Landscape //Positive values to move on x if (sensorEvent.values[1]>0){ //In margenMax I save the margin of the screen this value depends of the screen where we run the application. With this the ball not disapears of the screen if (x<=margenMaxX){ //We plus in x to move the ball x = x + (int) Math.pow(sensorEvent.values[1], 2); } } else{ //Move the ball to the other side if (x>=margenMinX){ x = x - (int) Math.pow(sensorEvent.values[1], 2); } } //Same in y if (sensorEvent.values[0]>0){ if (y<=margenMaxY){ y = y + (int) Math.pow(sensorEvent.values[0], 2); } } else{ if (y>=margenMinY){ y = y - (int) Math.pow(sensorEvent.values[0], 2); } } } else{//Portrait //Eje X if (sensorEvent.values[0]<0){ if (x<=margenMaxX){ x = x + (int) Math.pow(sensorEvent.values[0], 2); } } else{ if (x>=margenMinX){ x = x - (int) Math.pow(sensorEvent.values[0], 2); } } //Eje Y if (sensorEvent.values[1]>0){ if (y<=margenMaxY){ y = y + (int) Math.pow(sensorEvent.values[1], 2); } } else{ if (y>=margenMinY){ y = y - (int) Math.pow(sensorEvent.values[1], 2); } } } //Save the values to calculate the orientation mAccelerometerValues = sensorEvent.values.clone(); break; case Sensor.TYPE_ROTATION_VECTOR: //Rotation sensor //With this value I do the ball bigger or smaller if (sensorEvent.values[1]>0){ z=z+ (int) Math.pow(sensorEvent.values[1]+1, 2); } else{ z=z- (int) Math.pow(sensorEvent.values[1]+1, 2); } default: break; } //Screen Orientation if (mMagneticValues != null && mAccelerometerValues != null) { float[] R = new float[16]; SensorManager.getRotationMatrix(R, null, mAccelerometerValues, mMagneticValues); float[] orientation = new float[3]; SensorManager.getOrientation(R, orientation); //if x have positives values the screen orientation is landscape in other case is portrait if (orientation[0]>0){//LandScape //Here I change the margins of the screen for the ball not disapear bOrientacion=true; margenMaxX=1200; margenMinX=0; margenMaxY=500; margenMinY=0; } else{//Portrait bOrientacion=false; margenMaxX=600; margenMinX=0; margenMaxY=1000; margenMinY=0; } } } } 

La clase de vista donde dibujo la pelota

 public class CustomDrawableView extends View { static final int width = 50; static final int height = 50; //Constructor de la figura public CustomDrawableView(Context context) { super(context); mDrawable = new ShapeDrawable(new OvalShape()); mDrawable.getPaint().setColor(0xff74AC23); mDrawable.setBounds(x, y, x + width, y + height); } //Dibujamos la figura protected void onDraw(Canvas canvas) { //Actividad_Principal x,y,z are variables from the main activity where I have the onSensorChange RectF oval = new RectF(Actividad_Principal.x+Actividad_Principal.z, Actividad_Principal.y+Actividad_Principal.z, Actividad_Principal.x + width, Actividad_Principal.y + height); Paint p = new Paint(); p.setColor(Color.BLUE); canvas.drawOval(oval, p); invalidate(); } } 

}

Eso es todo, espero que nos ayude.

Intente usar sensorEvent.values[0] para su xChange y sensorEvents.values[1] para su yChange si desea utilizar el sensor de aceleración, si no utiliza los mismos valores y moverlo a la ( sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION ) if, esto le dará la inclinación del teléfono en lugar de la rapidez con que se mueve a lo largo de un eje.

También es necesario llamar a invalidate(); En la vista cuando establezca o cambie un sensor.

El Sensor.TYPE_ACCELEROMETER devuelve:

 values[0]: Acceleration minus Gx on the x-axis values[1]: Acceleration minus Gy on the y-axis values[2]: Acceleration minus Gz on the z-axis 

El Sensor.TYPE_ORIENTATION devuelve:

values[0] : Azimut, ángulo entre la dirección norte magnética y el eje y, alrededor del eje z (0 a 359). 0 = Norte, 90 = Este, 180 = Sur, 270 = Oeste

values[1] : Paso, rotación alrededor del eje x (-180 a 180), con valores positivos cuando el eje z se desplaza hacia el eje y.

values[2] : Rollo, rotación alrededor del eje y (-90 a 90), con valores positivos cuando el eje x se desplaza hacia el eje z.

Utilice la siguiente biblioteca en lugar de movimiento de desplazamiento

Agregue esta línea en la vista superior de XML

 xmlns:parallax="http://schemas.android.com/apk/res-auto" 

Para el diseño

  <com.nvanbenschoten.motion.ParallaxImageView android:id="@+id/parallex" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/image_hd" parallax:motionTiltSensitivity="2.5" /> 

Para el código en su método onCreate ()

 ParallaxImageView mBackground = (ParallaxImageView) findViewById(R.id.parallex); 

En su método onResume ()

 if(mBackground!=null) mBackground.registerSensorManager(); 

En su método onDestroy ()

 // Unregister SensorManager when exiting mBackground.unregisterSensorManager(); 

Creo que necesitas invalidar tu vista en el método onSensorChanged () oa una velocidad fps específica que tengas que implementar.

  • Unity3D Android acelerómetro y giroscopio controles
  • Imposibilidad de cambiar la velocidad del acelerómetro
  • Cómo obtener tiempo si alguna condición se reunió como giroscopio de lectura
  • Interpretación FFT
  • ¿Qué tan ampliamente apoyado es el acelerómetro en los dispositivos Android?
  • Detectar actividad del usuario (correr, andar en bicicleta, conducir) usando Android
  • ¿Podemos dibujar línea en lienzo android entre dos puntos dados por giroscopio?
  • ¿Cómo uso el acelerómetro Android?
  • Valor de Android: Sensor.getResolution ()
  • Filtro complementario (Gyro + accel) con Android
  • ¿Cómo / Debo implementar un filtro de Kalman para obtener datos precisos de Acelerómetro?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.