Android - Objekt bewegen mit Hilfe des Bewegungssensors
lima-city → Forum → Programmiersprachen → Java
abfrage
auto
bewegen
bewegung
bildschirmrand
blocken
code
figur
format
geschwindigkeit
hardware
import
klasse code
kreisen
optimieren
point
private figur
radius
sensor
spielfigur
-
Hallo zusammen,
ich versuche gerade einen Kreis, der am Anfang in der Mitte des Bildschirms ist, durch Bewegen des Smartphones nach links oder nach rechts zu bewegen.
Ich präsentiere euch einfach mal meinen Code und fange mit der Activity Klasse an:
import android.app.Activity; import android.hardware.SensorManager; import android.os.Bundle; import android.view.WindowManager; public class GameActivity extends Activity { SensorManager sm; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); sm = (SensorManager) getSystemService(SENSOR_SERVICE); setContentView(new GameView(this, sm)); } }
Dort wird ein SensorManager erstellt, der an die GameView Klasse, welche als Layout genutzt wird, weitergegeben wird. Das habe ich so gemacht, da ich es nicht hinbekommen habe, den SensorManager in der GameView Klasse zu erstellen. Hier ist die GameView Klasse:
import java.util.ArrayList; import java.util.Random; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Point; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.view.SurfaceHolder; import android.view.SurfaceView; public class GameView extends SurfaceView implements SensorEventListener { private SurfaceHolder surfaceHolder; private GameLoopThread theGameLoopThread; private Figur spielfigur; private Sensor accelerometer; @SuppressLint("WrongCall") public GameView(Context context, SensorManager sm) { super(context); accelerometer = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); sm.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL); theGameLoopThread = new GameLoopThread(this); surfaceHolder = getHolder(); surfaceHolder.addCallback(new SurfaceHolder.Callback() { public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; theGameLoopThread.setRunning(false); while (retry) { try { theGameLoopThread.join(); retry = false; } catch (InterruptedException e) { } } } public void surfaceCreated(SurfaceHolder holder) { theGameLoopThread.setRunning(true); theGameLoopThread.start(); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } }); spielfigur = new Figur(this); } @SuppressLint("WrongCall") @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.DKGRAY); spielfigur.drawMe(canvas); } @Override public void onSensorChanged(SensorEvent event) { try { Thread.sleep(16); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } int moveX =(int) -event.values[0]; spielfigur.setXSpeed(moveX*20); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub } }
Die Klasse erbt von der Klasse SurfaceView und implementiert das Interface SensorEventListener. Dort werden halt die Bewegungen wahr genommen und dementsprechend die Bewegungsgeschwindigkeit angepasst. Außerdem sorgt sie für das Zeichnen. Damit der Kreis sich schneller bewegt, multipliziere ich den x Wert des Sensors noch mit 20. Hier ist jetzt meine Klasse für den Kreis bzw für die Figur:
import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; public class Figur implements Drawable { private float x; private float y; private float radius = 20; private int xSpeed = 0; private Paint paint; private GameView gameView; private boolean oneTime = false; public Figur(GameView gameView){ this.gameView = gameView; paint = new Paint(); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.RED); } @Override public void drawMe(Canvas canvas) { if(!oneTime){ oneTime = true; x = canvas.getWidth()/2; y = canvas.getHeight()/2; } moveAndCheckCollision(); canvas.drawCircle(x, y, radius, paint); } public void moveAndCheckCollision() { // Kollision mit Rand if(x > gameView.getWidth() - radius - xSpeed || x - radius + xSpeed < 0){ xSpeed = 0; } x += xSpeed; } public void setXSpeed(int xSpeed){ this.xSpeed = xSpeed; } }
Dann hier noch die Thread Klasse:
import android.annotation.SuppressLint; import android.graphics.Canvas; public class GameLoopThread extends Thread { static final long FPS = 20; private GameView theView; private boolean isRunning = false; public GameLoopThread(GameView theView) { this.theView = theView; } public void setRunning(boolean run) { isRunning = run; } @SuppressLint("WrongCall") @Override public void run() { long TPS = 1000 / FPS; long startTime, sleepTime; while (isRunning) { Canvas theCanvas = null; startTime = System.currentTimeMillis(); try { theCanvas = theView.getHolder().lockCanvas(); synchronized (theView.getHolder()) { theView.onDraw(theCanvas); } } finally { if (theCanvas != null) { theView.getHolder().unlockCanvasAndPost(theCanvas); } } sleepTime = TPS - (System.currentTimeMillis() - startTime); try{ if(sleepTime > 0){ sleep(sleepTime); } else{ sleep(10); } } catch (Exception e){ } } } }
Den größten Teil davon, zum Beispiel die Thread Klasse oder die GameView Klasse habe ich aus einem Tutorial. Das mit dem Sensor und der Figur habe ich dann dazu gepackt. Ich bin jetzt noch nicht ganz zufrieden damit^^ Der Kreis bewegt sich zwar schon recht flüssig, aber es könnte noch besser gehen. Und wenn man das Handy sehr stark neigt, dann bleibt der Kreis schon etwas vor dem Bildschirmrand stehen, da die Geschwindigkeit ja dann ziemlich hoch ist und somit die if Abfrage in der moveAndCheckCollision() Methode eintrifft und die Geschwindigkeit auf 0 gesetzt wird. Was mich noch stört ist, das der Spielraum, in der die Geschwindigkeit 0 ist, sehr groß ist. Das heißt, ich kann das Handy in beide Richtungen um ca 10°-20° drehen, ohne dass sich der Kreis bewegt. Das sollte feiner werden, also er sollte sich schon früher bewegen.
Ich würde mir also gerne Verbesserungsvorschläge von euch anhören, wie ich diese Bewegung optimieren könnte. Wäre cool wenn sich der ein oder andere mal Zeit nimmt und drüber guckt.
Viele Grüße -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage