您的位置:首页 > 移动开发 > Android开发

android 如何使用surfaceview绘制类似游戏手柄的摇杆?

2011-12-26 17:08 711 查看
网上找到比较少关于此类的文章,估计是高手都比较忙,没空分享这样的东西。今天乘有空发表一下。

具体分3步:

1.创建一个holder,可以理解为我们美术生常用的画板架。

surfaceview的原理是在屏幕上不停的画图,通过不断地刷新每次画好的图,形成流畅的动画或其他图像,刷新频率极高,如同早期迪士尼动画一样。

2.Run the canvas! : canvas就是画布,不难理解了吧,我们往canvas 绘制circle ,绘制image,绘制矩形都在这里进行。注意会之前要将画布lock在holder上,画完后再unlock

3.定义onTouch事件,就是定义手指触碰摇杆时应该发生什么行为。重点语句在

mRockerPosition.set((int)event.getX(), (int)event.getY()),mRockerPosition随手指的点坐标改变而改变,令canvas的每次绘制摇杆的位置都有所不同,这就形成了手柄效果。


import com.wincent.wavegenerator.R;
import com.wincent.wavegenerator.activity.WaveGeneratorActivity;
import com.wincent.wavegenerator.test.Rudder2.RudderListener;
import com.wincent.wavegenerator.tools.MathUtils;

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.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import android.view.View;

public class RudderSample extends SurfaceView implements Runnable,Callback{
private float sensorX;
private float sensorY;
private SurfaceHolder mHolder;
private boolean isStop = false;
private Thread mThread;
private Paint  mPaint;
public Point  mRockerPosition; //摇杆位置
public static boolean sensorOn=false;
public int mWheelRadius = 60;//摇杆活动范围半径,难道这个是DP单位?原来是60

public Point  mCtrlPoint;// = new Point(mRudderRadius+mWheelRadius,mRudderRadius+mWheelRadius);//摇杆起始位置
public RudderListener listener = null; //事件回调接口
public int d;
public int orientation=1;
private float sensorXinCirle;
private float sensorYinCirle;
public SensorManager sensorMgr;
private Sensor sensor;
public SensorEventListener lsn;
private Bitmap rudder;
private boolean isDestroyed=false;
private int testRadius;
private Paint paintBlack;
public Point testPoint;
private Point centerPoint=new Point(80,80);
public static final int ACTION_RUDDER = 1 , ACTION_ATTACK = 2; // 1:摇杆事件 2:按钮事件(未实现)

public RudderSample(Context context) {
super(context);
//mCtrlPoint.set(WaveGeneratorActivity.rudderCenter.x,WaveGeneratorActivity.rudderCenter.y);
}

public RudderSample(Context context, AttributeSet as) {

super(context, as);

this.setKeepScreenOn(true);
mHolder = getHolder();
mHolder.addCallback(this);
mThread = new Thread(this);
mPaint = new Paint();
mPaint.setColor(Color.GREEN);//
mPaint.setAntiAlias(true);//抗锯齿
mPaint.setStyle(Paint.Style.STROKE);
//测试代码
paintBlack=new Paint();
paintBlack.setColor(Color.RED);
paintBlack.setAntiAlias(true);

mRockerPosition=new Point();
testPoint=new Point();
mRockerPosition.set(centerPoint.x,centerPoint.y);
mCtrlPoint=new Point();
mCtrlPoint.set(centerPoint.x,centerPoint.y);
//mCtrlPoint.set();

setFocusable(true);
setFocusableInTouchMode(true);
setZOrderOnTop(true);
mHolder.setFormat(PixelFormat.TRANSPARENT);//设置背景透明
rudder =  BitmapFactory.decodeResource(getResources(),R.drawable.rudder);

}

//设置回调接口
public void setRudderListener(RudderListener rockerListener) {
listener = rockerListener;
}

@Override
public void run() {
Canvas canvas = null;

while(!isStop) {
try {
//----11.30修改,加入代码,测试那个圆到底有多大

canvas = mHolder.lockCanvas();
canvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);//清除屏幕
canvas.drawCircle(mCtrlPoint.x, mCtrlPoint.y, testRadius, mPaint); //摇杆可活动范围圆环
drawImage(canvas, rudder, mRockerPosition.x, mRockerPosition.y,rudder.getWidth(), rudder.getHeight(), 0, 0);
//canvas.drawRect(testPoint.x, testPoint.y, testPoint.x+40, testPoint.y+40, paintBlack);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(canvas != null) {
mHolder.unlockCanvasAndPost(canvas);
}
}

try {
Thread.sleep(30);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {

}

@Override
public void surfaceCreated(SurfaceHolder holder) {
isStop = false;
mThread=new Thread(this);
mThread.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isStop = true;
mThread.interrupt();
}

@Override
public boolean onTouchEvent(MotionEvent event) {

if(!sensorOn){
//----int len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY());

int len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY());
if(event.getAction() == MotionEvent.ACTION_DOWN) {
//如果屏幕接触点不在摇杆挥动范围内,则不处理
if(len >mWheelRadius) {
return true;
}
}
if(event.getAction() == MotionEvent.ACTION_MOVE){
if(len <= mWheelRadius) {
//如果手指在摇杆活动范围内,则摇杆处于手指触摸位置
mRockerPosition.set((int)event.getX(), (int)event.getY());//Point
d=len;
}else{
//设置摇杆位置,使其处于手指触摸方向的 摇杆活动范围边缘
mRockerPosition = MathUtils.getBorderPoint(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()), mWheelRadius);

d=60;
}
if(listener != null) {
Log.v("len",event.getX()+","+event.getY());
float radian = MathUtils.getRadian(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()));
double radianUnsigned=(float) MathUtils.angUnsigned;
listener.onSteeringWheelChanged(ACTION_RUDDER,radianUnsigned,d);
Log.v("sensor",d+","+radianUnsigned);
}
}
//如果手指离开屏幕,则摇杆返回初始位置
if(event.getAction() == MotionEvent.ACTION_UP) {
mRockerPosition = new Point(mCtrlPoint);
d=0;
}
return true;
}else{
if(lsn!=null){
float radian = MathUtils.getRadian(mCtrlPoint, new Point((int)sensorXinCirle, (int)sensorYinCirle));
radianUnsigned=(float) MathUtils.angUnsigned;
listener.onSteeringWheelChanged(ACTION_RUDDER,radianUnsigned,d);
Log.v("sensor",d+","+radianUnsigned);
}

}

return true;
}
//获取摇杆偏移角度 0-360°
private int getAngleCouvert(float radian) {
int tmp = (int) Math.round(radian/Math.PI*180);
if(tmp < 0) {
return -tmp;
}else{
return 180 + (180 - tmp);
}
}
int MAX_TOUCHPOINTS=3;
public float radianUnsigned;

public boolean center=false;

//回调接口
public interface RudderListener {
void onSteeringWheelChanged(int action,double radianUnsigned, int d);
}

/**
* 绘制图片
*
* @param		x 屏幕上的x坐标
* @param		y 屏幕上的y坐标
* @param		w 要绘制的图片的宽度
* @param		h 要绘制的图片的高度
* @param		bx图片上的x坐标
* @param		by图片上的y坐标
*
* @return		null
*/

public void drawImage(Canvas canvas, Bitmap blt, int x, int y, int w, int h, int bx, int by)
{
Rect src = new Rect();// 图片
Rect dst = new Rect();// 屏幕

src.left = bx;
src.top = by;
src.right = bx + w;
src.bottom = by + h;
dst.left = x-(w/2);
dst.top = y-(h/2);
dst.right = x + (w/2);
dst.bottom = y + (h/2);
canvas.drawBitmap(blt, src, dst, null);
src = null;
dst = null;
}

public void enableSensor(){
//----周日删除 sensorOn=true;
sensorMgr.registerListener(lsn, sensor, SensorManager.SENSOR_DELAY_GAME);

}
public void disableSensor(){
//----周日删除sensorOn=false;
sensorMgr.unregisterListener(lsn, sensor);
mRockerPosition=new Point(mCtrlPoint);
}
}
下一集,我们专门讲解如何实现多点触碰进行摇杆控制
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: