Android(Java)を始める – SurfaceViewで描写 + 加速度センサー

Filed under Android, Java

Androidの勉強中です。

まずは、描画の方法&加速度センサーの利用方法の確認。

クリックで丸が追加され、それぞれが加速度センサーによって重力を与えられ動きます。

Androidで描画する場合はSurfaceViewを使うのが基本ってことでいいんだろうか。

以下、ソースです。

Main.javaのソース。

package jp.sakef;

import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;

public class Main extends Activity implements SensorEventListener
{
	private SensorManager sensorManager;
	private Sensor accelerometer;
	private MainView view;

	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		// 画面を縦表示で固定
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

		view = new MainView(this);
		setContentView(view);

		//センサーマネージャの取得
		sensorManager=(SensorManager)getSystemService(Context.SENSOR_SERVICE);

		//センサーの取得
		List<Sensor> list;
		list=sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
		if (list.size()>0) accelerometer=list.get(0);
	}

	//アプリの開始
	protected void onResume()
	{
		//アプリの開始
		super.onResume();

		//センサーの処理の開始
		if (accelerometer!=null) sensorManager.registerListener(this,accelerometer,SensorManager.SENSOR_DELAY_FASTEST);
	}

	//アプリの停止
	protected void onStop()
	{
		//センサーの処理の停止
		sensorManager.unregisterListener(this);

		//アプリの停止
		super.onStop();
	}    

	//センサーリスナーの処理
	public void onSensorChanged(SensorEvent event)
	{
		//加速度の取得
		if (event.sensor==accelerometer)  view.setAcce(-event.values[0]*0.2f, event.values[1]*0.2f);
	}

	//精度変更イベントの処理
	public void onAccuracyChanged(Sensor sensor,int accuracy){}

	// 破棄の際に実行
	public void onDestroy()
	{
		super.onDestroy();
	}
}

MainView.javaのソース。

package jp.sakef;

import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MainView extends SurfaceView implements SurfaceHolder.Callback, Runnable
{
	private static double e = 0.8;
	private static double d = 0.99;
	private float gx;
	private float gy;
	private Paint paint;
	private SurfaceHolder holder;
	private Thread thread;
	private ArrayList<Circle> container;
	private int width;
	private int height;

	public MainView(Context context)
	{
		super(context);
		holder = null;
		thread = null;
		container = new ArrayList<Circle>();
		paint = new Paint();
		paint.setAntiAlias(true);
		gx = gy = 0;

		// getHolder()メソッドでSurfaceHolderを取得。さらにコールバックを登録
		getHolder().addCallback(this);
	}

	//SurfaceView生成時に呼び出される
	public void surfaceCreated(SurfaceHolder holder)
	{
		this.holder = holder;
		thread = new Thread(this);
	}

	//SurfaceView変更時に呼び出される
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
	{
		if(thread != null )
		{
			this.width  = width;
			this.height = height;
			thread.start();
		}
	}

	//SurfaceView破棄時に呼び出される
	public void surfaceDestroyed(SurfaceHolder holder)
	{
		thread = null;
	}

	//スレッドによるSurfaceView更新処理
	public void run()
	{
		while (thread != null)
		{
			//描画処理
			Canvas canvas = holder.lockCanvas();
			canvas.drawColor(Color.argb(255, 0, 0, 0));
			int size = container.size();

			// 簡易衝突計算
			for(int i=0 ; i<size ; i++)
			{
				for(int j=0 ; j<size ; j++)
				{
					if(j<=i) continue;

					Circle a = container.get(i);
					Circle b = container.get(j);
					float ab_x = b.x - a.x;
					float ab_y = b.y - a.y;
					float tr = a.radius + b.radius;

					if(ab_x*ab_x + ab_y*ab_y < tr*tr)
					{
						float len = (float)Math.sqrt(ab_x*ab_x + ab_y*ab_y);
						float distance = (a.radius + b.radius) - len;
						if(len>0) len = 1 / len;
						ab_x *= len;
						ab_y *= len;

						distance /= 2.0;
						a.x -= ab_x * distance;
						a.y -= ab_y * distance;
						b.x += ab_x * distance;
						b.y += ab_y * distance;

						// 衝突後の速度を計算
						float ma = (float) ((b.m / (a.m + b.m))*(1 + e)* ((b.dx - a.dx)*ab_x + (b.dy - a.dy)*ab_y));
						float mb = (float) ((a.m / (a.m + b.m))*(1 + e)* ((a.dx - b.dx)*ab_x + (a.dy - b.dy)*ab_y));
						a.dx += ma*ab_x;
						a.dy += ma*ab_y;
						b.dx += mb*ab_x;
						b.dy += mb*ab_y;
					}
				}
			}

			// 計算をボールに反映
			for(int i = 0 ; i < size ; i++)
			{
				Circle a = container.get(i);
				a.dx *= d;
				a.dy *= d;
				a.dx += gx;
				a.dy += gy;
				a.x += a.dx;
				a.y += a.dy;

				if(a.x < a.radius)
				{
					a.x = a.radius;
					a.dx *= -1;
				}
				if(a.y < a.radius)
				{
					a.y = a.radius;
					a.dy *= -1;
				}
				if(a.x > width-a.radius)
				{
					a.x = width-a.radius;
					a.dx *= -1;
				}
				if(a.y > height-a.radius)
				{
					a.y = height-a.radius;
					a.dy *= -1;
				}
				paint.setColor(Color.argb(255, a.cr, a.cg, a.cb));
				canvas.drawCircle(a.x, a.y, a.radius, paint);
			}
			holder.unlockCanvasAndPost(canvas);
		}
	}

	// クリック時のイベント
	public boolean onTouchEvent(MotionEvent event)
	{
		if(event.getAction() == MotionEvent.ACTION_DOWN)
		{
			float x = event.getX();
			float y = event.getY();
			float dx = (float)(Math.random()*10-5);
			float dy = (float)(Math.random()*10-5);
			float ran = (float)Math.random();
			float r = ran*20+5;
			float m = ran*10+10;
			int cr = 255;
			int cb = (int)(255 * Math.random());
			int cg = (int)(255 * Math.random());
			container.add(new Circle(r, x, y, dx, dy, m, cr, cg, cb));
		}
		return true;
	}

	// 加速度の更新
	public void setAcce(float gx, float gy)
	{
		this.gx = gx;
		this.gy = gy;
	}
}

Circle.javaのソース。

package jp.sakef;

public class Circle
{
	public float radius;
	public float x;
	public float y;
	public float dx;
	public float dy;
	public float m;
	public int cr;
	public int cg;
	public int cb;

	public Circle(float radius, float x, float y, float dx, float dy, float m, int cr, int cb, int cg)
	{
		this.radius = radius;
		this.x = x;
		this.y = y;
		this.dx = dx;
		this.dy = dy;
		this.m = m;
		this.cr = cr;
		this.cg = cg;
		this.cb = cb;
	}
}

One Comment

  1. Ossein
    Posted 2011/10/24 at 06:40 | Permalink

    Great tutorial!
    Thank you.
    Could you tell me how can I define a custom area instead of whole screen for the surfaceview?

Post a Comment

Your email is never published nor shared.