照着PDF做了个摇杆并实现了 摇杆控制角色行走, 在这里贴下代码做下笔记。
首先新建了一个VIEW 继承SurfaceView 实现相关接口
<pre name="code" class="java">
public class PlayerView extends MapView implements Callback,Runnable
相关变量声明与初始化设置
protected final int DIR_LEFT = 0;
protected final int DIR_RIGHT = 1;
private int dir = DIR_RIGHT;
private int robotX,robotY;
private boolean isUp=false,isDown=false,isLeft=false,isRight=false;
//摇杆的圆半径
private float smallCenterX = 120,smallCenterY=120,smallCenterR = 20;
private float BigCenterX = 120,BigCenterY = 120,BigCenterR = 40;
//圆运动角度
private double angle;
public PlayerView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);//设置监听
paint = new Paint();
paint.setColor(Color.BLACK);
setFocusable(true);//设置焦点
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
bitmap = BitmapFactory.decodeResource(this.getResources(),
R.drawable.robot);
bmpX = -bitmap.getWidth()+this.getWidth();
bmpY = this.getHeight() - bitmap.getHeight();
Thread thread = new Thread(this);
thread.start();
//设置摇杆初始位置
smallCenterX = 40;
smallCenterY = this.getHeight()-40;
BigCenterX = 40;
BigCenterY = this.getHeight()-40;
}
private void drawFrame(){
canvas = holder.lockCanvas();
canvas.drawColor(Color.WHITE);
int frameW = bitmap.getWidth()/6; //获得每一帧的宽
int frameH = bitmap.getHeight()/2; //获得每一帧的高
int col = bitmap.getWidth()/frameW; //获得位图列数
int x = cureentFrame%col * frameW;
int y = cureentFrame /col * frameH;
paint.setAlpha(255);//不透明
canvas.save();
//paint.setColor(Color.RED);//设置画笔颜色
//设置每帧可见区域为角色一样大小
canvas.clipRect(robotX,robotY,robotX+bitmap.getWidth()/6,robotY+bitmap.getHeight()/2);
if(dir==DIR_LEFT){
//如果向左移动则设置角色翻转
canvas.scale(-1,1,robotX-x+bitmap.getWidth()/2,robotY-y+bitmap.getHeight()/2);
}
canvas.drawBitmap(bitmap, robotX-x,robotY-y, paint);
canvas.restore();
//摇杆绘制
paint.setAlpha(0x77); //设置摇杆透明度
canvas.drawCircle(BigCenterX, BigCenterY, BigCenterR, paint);//大圆
canvas.drawCircle(smallCenterX, smallCenterY, smallCenterR, paint);//小圆
holder.unlockCanvasAndPost(canvas);
}
计算余弦
/**
* Math.cos 返回余弦
* @param centerX 围绕大圆中心点X
* @param centerY 围绕大圆中心点Y
* @param R 围绕大圆半径
* @param rad 旋转弧度
* 方法: 设置小圆中心点的坐标位置
*/
private void setSmallCircleXY(float centerX,float centerY,float R,double rad){
smallCenterX = (float)(R*Math.cos(rad))+centerX;
smallCenterY = (float)(R*Math.sin(rad))+centerY;
}
剩下的代码直接贴吧 都有注释的
public void logic(){
cureentFrame++;//渲染帧数
if(cureentFrame>=12) //超过12帧 则重置
cureentFrame = 0;
if(isUp)
robotY -=5;
if(isDown)
robotY+=5;
if(isLeft)
robotX-=5;
if(isRight)
robotX+=5;
//angle++;
/*if(angle>=360)
angle=0;
setSmallCircleXY(BigCenterX, BigCenterY, BigCenterR, angle*Math.PI/180);//Math.PI 圆的周长与直径之比
*/ }
/**
* 得到两点之间弧度
* @param px1
* @param py1
* @param px2
* @param py2
* @return
*/
public double getRad(float px1,float py1,float px2,float py2){
float x = px2 - px1;//得到两点X的距离
float y = py1 -py2; //y
//算出斜边长
float Hypotenuse = (float) Math.sqrt(Math.pow(x, 2)+Math.pow(y, 2));
float cosAngle = x/Hypotenuse; //得到角度的余弦值
//通过反余弦获得角度弧度
float rad = (float)Math.acos(cosAngle);
if(py2<py1)
rad = -rad;
return rad;
}
private void stopMove(){
isUp = false;
isDown = false;
isLeft = false;
isRight = false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//用户抬起小圆恢复初始位置
if(event.getAction()==MotionEvent.ACTION_UP){
smallCenterX = BigCenterX;
smallCenterY = BigCenterY;
stopMove();//停止移动
}else{
int pointX = (int)event.getX();
int pointY = (int)event.getY();
//判断用户点击位置是否在大圆内
if(Math.sqrt(Math.pow((BigCenterX-(int)event.getX()),2)+Math.pow((BigCenterY-(int)event.getY()), 2))<=BigCenterR){
smallCenterX = pointX;//让小圆跟随用户点击位置
smallCenterY = pointY;
}else{
setSmallCircleXY(BigCenterX, BigCenterY, BigCenterR, getRad(BigCenterX, BigCenterY, pointX, pointY));
}
double radian = getRad(BigCenterX, BigCenterY, pointX, pointY);
angle = radian/Math.PI*180;
Log.v("角度:", "============>"+angle+" radian:"+radian);
stopMove();
if(angle<-67.5&&angle>-112.5){ //上
isUp = true;
}else if(angle<-22.5&&angle>-67.5){ //右上
isUp=true;
isRight = true;
dir = DIR_RIGHT;
}else if(angle>-167.5&&angle<-112.5){ //左上
dir=DIR_LEFT;
isLeft =true;
isUp = true;
}else if(angle>67.5&&angle<112.5){ //下
isDown = true;
}else if(angle<167.5&&angle>112.5){ //左下
dir=DIR_LEFT;
isDown = true;
isLeft = true;
}else if(angle>-22.5&&angle<22.5){ //右
dir = DIR_RIGHT;
isRight = true;
}else if(angle>22.5&&angle<67.5){//右下
dir=DIR_RIGHT;
isDown = true;
isRight = true;
}else if((angle>-212.5&&angle<-167.5)||(angle<212.5&&angle>167.5)){ //下
dir = DIR_LEFT;
isLeft = true;
}
}
return true;
}
@Override
public void run() {
while (flag) {
long start = System.currentTimeMillis();
drawFrame();
logic();
long end = System.currentTimeMillis();
try {
if (end - start < 50) {
Thread.sleep(50 - (end - start));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}