照着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();
- }
- }
-
- }
- 本文作者: reiner
- 本文链接: https://reiner.host/posts/6ada3be1.html
- 版权声明: 转载请注明出处,并附上原文链接