用SurfaceView实现Android游戏摇杆

这段时间研究自定义控件,遂想起游戏里的摇杆的实现挺有意思,于是来自己写一套熟悉熟悉,关于SurfaceView的特性网上也有很多,故不赘述,反正绘图用起来挺爽就是了,永远的告别了JAVA GUI手动实现双缓冲的时代了……

  1 import com.game.graphics.utils.MathUtils;
2
3 import android.content.Context;
4 import android.graphics.Canvas;
5 import android.graphics.Color;
6 import android.graphics.Paint;
7 import android.graphics.PixelFormat;
8 import android.graphics.Point;
9 import android.graphics.PorterDuff.Mode;
10 import android.util.AttributeSet;
11 import android.view.MotionEvent;
12 import android.view.SurfaceHolder;
13 import android.view.SurfaceView;
14 import android.view.SurfaceHolder.Callback;
15
16 public class Rudder extends SurfaceView implements Runnable,Callback{
17
18 private SurfaceHolder mHolder;
19 private boolean isStop = false;
20 private Thread mThread;
21 private Paint mPaint;
22 private Point mRockerPosition; //摇杆位置
23 private Point mCtrlPoint = new Point(80,80);//摇杆起始位置
24 private int mRudderRadius = 20;//摇杆半径
25 private int mWheelRadius = 60;//摇杆活动范围半径
26 private RudderListener listener = null; //事件回调接口
27 public static final int ACTION_RUDDER = 1 , ACTION_ATTACK = 2; // 1:摇杆事件 2:按钮事件(未实现)
28
29 public Rudder(Context context) {
30 super(context);
31 }
32
33 public Rudder(Context context, AttributeSet as) {
34 super(context, as);
35 this.setKeepScreenOn(true);
36 mHolder = getHolder();
37 mHolder.addCallback(this);
38 mThread = new Thread(this);
39 mPaint = new Paint();
40 mPaint.setColor(Color.GREEN);
41 mPaint.setAntiAlias(true);//抗锯齿
42 mRockerPosition = new Point(mCtrlPoint);
43 setFocusable(true);
44 setFocusableInTouchMode(true);
45 setZOrderOnTop(true);
46 mHolder.setFormat(PixelFormat.TRANSPARENT);//设置背景透明
47 }
48
49 //设置回调接口
50 public void setRudderListener(RudderListener rockerListener) {
51 listener = rockerListener;
52 }
53
54 @Override
55 public void run() {
56 Canvas canvas = null;
57 while(!isStop) {
58 try {
59 canvas = mHolder.lockCanvas();
60 canvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);//清除屏幕
61 mPaint.setColor(Color.CYAN);
62 canvas.drawCircle(mCtrlPoint.x, mCtrlPoint.y, mWheelRadius, mPaint);//绘制范围
63 mPaint.setColor(Color.RED);
64 canvas.drawCircle(mRockerPosition.x, mRockerPosition.y, mRudderRadius, mPaint);//绘制摇杆
65 } catch (Exception e) {
66 e.printStackTrace();
67 } finally {
68 if(canvas != null) {
69 mHolder.unlockCanvasAndPost(canvas);
70 }
71 }
72 try {
73 Thread.sleep(30);
74 } catch (InterruptedException e) {
75 e.printStackTrace();
76 }
77 }
78 }
79
80 @Override
81 public void surfaceChanged(SurfaceHolder holder, int format, int width,
82 int height) {
83
84 }
85
86 @Override
87 public void surfaceCreated(SurfaceHolder holder) {
88 mThread.start();
89 }
90
91 @Override
92 public void surfaceDestroyed(SurfaceHolder holder) {
93 isStop = true;
94 }
95
96 @Override
97 public boolean onTouchEvent(MotionEvent event) {
98 int len = MathUtils.getLength(mCtrlPoint.x, mCtrlPoint.y, event.getX(), event.getY());
99 if(event.getAction() == MotionEvent.ACTION_DOWN) {
100 //如果屏幕接触点不在摇杆挥动范围内,则不处理
101 if(len >mWheelRadius) {
102 return true;
103 }
104 }
105 if(event.getAction() == MotionEvent.ACTION_MOVE){
106 if(len <= mWheelRadius) {
107 //如果手指在摇杆活动范围内,则摇杆处于手指触摸位置
108 mRockerPosition.set((int)event.getX(), (int)event.getY());
109
110 }else{
111 //设置摇杆位置,使其处于手指触摸方向的 摇杆活动范围边缘
112 mRockerPosition = MathUtils.getBorderPoint(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()), mWheelRadius);
113 }
114 if(listener != null) {
115 float radian = MathUtils.getRadian(mCtrlPoint, new Point((int)event.getX(), (int)event.getY()));
116 listener.onSteeringWheelChanged(ACTION_RUDDER,Rudder.this.getAngleCouvert(radian));
117 }
118 }
119 //如果手指离开屏幕,则摇杆返回初始位置
120 if(event.getAction() == MotionEvent.ACTION_UP) {
121 mRockerPosition = new Point(mCtrlPoint);
122 }
123 return true;
124 }
125
126 //获取摇杆偏移角度 0-360°
127 private int getAngleCouvert(float radian) {
128 int tmp = (int)Math.round(radian/Math.PI*180);
129 if(tmp < 0) {
130 return -tmp;
131 }else{
132 return 180 + (180 - tmp);
133 }
134 }
135
136 //回调接口
137 public interface RudderListener {
138 void onSteeringWheelChanged(int action,int angle);
139 }
140 }

  

为了以后计算这些角度啊弧度什么的数学相关的计算,定义了一个Math工具类方便以后使用

 1 import android.graphics.Point;
2
3 public class MathUtils {
4 //获取两点间直线距离
5 public static int getLength(float x1,float y1,float x2,float y2) {
6 return (int)Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2));
7 }
8 /**
9 * 获取线段上某个点的坐标,长度为a.x - cutRadius
10 * @param a 点A
11 * @param b 点B
12 * @param cutRadius 截断距离
13 * @return 截断点
14 */
15 public static Point getBorderPoint(Point a, Point b,int cutRadius) {
16 float radian = getRadian(a, b);
17 return new Point(a.x + (int)(cutRadius * Math.cos(radian)), a.x + (int)(cutRadius * Math.sin(radian)));
18 }
19
20 //获取水平线夹角弧度
21 public static float getRadian (Point a, Point b) {
22 float lenA = b.x-a.x;
23 float lenB = b.y-a.y;
24 float lenC = (float)Math.sqrt(lenA*lenA+lenB*lenB);
25 float ang = (float)Math.acos(lenA/lenC);
26 ang = ang * (b.y < a.y ? -1 : 1);
27 return ang;
28 }
29 }

  

将自定义的控件加入到Layout文件里,在这里定义摇杆的大小和位置

 1 <?xml version="1.0" encoding="utf-8"?>
2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent">
6 <ImageView
7 android:layout_width="fill_parent"
8 android:layout_height="fill_parent"
9 android:scaleType="fitXY"
10 android:src="@drawable/xx"/>
11 <RelativeLayout
12 android:id="@+id/ctrls"
13 android:layout_width="fill_parent"
14 android:layout_height="fill_parent">
15 <com.game.demo.views.Rudder
16 android:id="@+id/rudder"
17 android:layout_width="480dip"
18 android:layout_height="160dip"
19 android:layout_alignParentBottom="true"
20 android:layout_centerHorizontal="true"/>
21 </RelativeLayout>
22 </FrameLayout>

  

Activity代码,OnCreate方法里的实现,Android屏幕右方是0°,逆时针一圈360°,跟Java绘图还是一样的

  

 1       setContentView(R.layout.main);
2 Rudder rudder = (Rudder) findViewById(R.id.rudder);
3 rudder.setRudderListener(new RudderListener() {
4
5 @Override
6 public void onSteeringWheelChanged(int action, int angle) {
7 if(action == Rudder.ACTION_RUDDER) {
8 //TODO:事件实现
9 }
10 }
11 });

  

附上效果图

用SurfaceView实现Android游戏摇杆_第1张图片

用SurfaceView实现Android游戏摇杆_第2张图片

你可能感兴趣的:(用SurfaceView实现Android游戏摇杆)