
Androidの勉強中。
画像がバネみたいに変形するやつ。
研究室に画像をポヨポヨさせる波が来ていたので便乗してみました。
上の写真はエミュレータですが、実機でもちゃんと動きました。
画像の自由変形にはCanvasが持つdrawBitmapMeshメソッドを利用してます。
以下、今回のソースです。
Main.javaのソース。
package jp.sakef;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
public class Main extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(new MainView(this));
}
}
MainView.javaのソース。
package jp.sakef;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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 int segW = 15;
private static int segH = 15;
private static int size = (segW + 1)*(segH + 1)*2;
private SurfaceHolder holder=null;
private Thread thread=null;
private Paint paint;
private Bitmap bmp;
private float[] movePoints;
private float[] firstPoints;
private float[] v;
private float mouseX;
private float mouseY;
public MainView(Context context)
{
super(context);
getHolder().addCallback(this);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.rgb(200, 0, 0));
mouseX = mouseY = -100.0f;
bmp = BitmapFactory.decodeResource(getResources(),R.drawable.img);
}
public void surfaceDestroyed(SurfaceHolder holder)
{
thread = null;
}
public void surfaceCreated(SurfaceHolder holder)
{
this.holder = holder;
thread = new Thread(this);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
// 座標の入った配列を作成
firstPoints = new float[size];
movePoints = new float[size];
v = new float[size];
for(int j=0 ; j<=segH ; j++)
{
for(int i=0 ; i<=segW ; i++)
{
int pos = j*(segW + 1)+i;
firstPoints[2*pos] = movePoints[2*pos] = i*bmp.getWidth()/segW + 20;
firstPoints[2*pos+1] = movePoints[2*pos+1] = j*bmp.getHeight()/segH + 20;
v[2*pos] = v[2*pos+1] = 0.0f;
}
}
if(thread != null) thread.start();
}
public void run()
{
while (thread != null)
{
// 塗りつぶし
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.BLACK);
// 座標計算
for(int i=0 ; i<size ; i+=2)
{
float mx = movePoints[i];
float my = movePoints[i+1];
float theta = (float) Math.atan2(my-mouseY, mx-mouseX);
float d = (float) Math.sqrt((mouseX - mx)*(mouseX - mx)+ (mouseY - my)*(mouseY - my));
// マウスの座標に近い場合はマウスに寄る
if(d < 30 && d >10)
{
movePoints[i] -= Math.cos(theta);
movePoints[i+1] -= Math.sin(theta);
}
// マウスから遠い場合はバネの動き
else if(d >= 30)
{
v[i] += (firstPoints[i] - mx)*0.2f;
v[i+1] += (firstPoints[i+1] - my)*0.2f;
movePoints[i] += v[i];
movePoints[i+1] += v[i+1];
v[i] *= 0.9f;
v[i+1] *= 0.9f;
}
}
// 画像を描画
canvas.drawBitmapMesh(bmp, segW, segH, movePoints, 0, null, 0, null);
holder.unlockCanvasAndPost(canvas);
}
}
// クリック時のイベント
public boolean onTouchEvent(MotionEvent event)
{
if(event.getAction() == MotionEvent.ACTION_UP)
{
mouseX = mouseY = -100.0f;
}
else
{
mouseX = event.getX();
mouseY = event.getY();
}
return true;
}
}