详解android studio游戏摇杆开发教程,仿王者荣耀摇杆

最近在做一个山寨版的王者荣耀,刚开始做的时候毫无头绪 摇杆的多点触控做的特别烂

经过几天的思考已完美解决所有问题,下面就和大家分享下这个摇杆的开发思路

若有不正之处,请多多谅解并欢迎指正。

首先这个摇杆要用到较多的数学知识,小编的数学特别烂也就高中水平吧

我们这个摇杆一共就五个按钮,一个移动摇杆、三个技能摇杆和一个普通攻击按钮

最终效果

好了废话少说让我们开始吧

新建一个项目

建好项目之后,我们先新建一个类叫做“画”。也是我们的主View

修改Hua.java的代码

public class Hua extends RelativeLayout implements Runnable{ //继承RelativeLayout 实现Runnable接口

 private Paint p;//画笔

 public Hua(Context context) {
 super(context);
 p=new Paint();
 setBackgroundColor(Color.BLACK);//背景颜色设为黑色
 }

 @Override
 protected void onDraw(Canvas g) {//重写onDraw方法
 super.onDraw(g);
 }

 @Override
 public void run() {

 }
}

接下来我们做移动摇杆

我们要准备一张图片(待会我会把图片都丢在附件里)

首先用ps画一个这样半透明的圆ps部分就不做教程了

把背景隐藏掉 保存为png格式

把我们刚刚制作的图片添加进来

先新建一个类 my.java

public class my { //这个类当一个全局变量使用
 public static int w,h;//屏幕的宽高
 public static float bili;
 public static MainActivity main;
 public static RectF re=new RectF();
 public static int ontouchAlpha=100;//触控区透明度0-255 0为透明,为了测试我们先设为100
}

修改 MainActivity 的代码

public class MainActivity extends AppCompatActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 my.main=this;
 getSupportActionBar().hide();//隐藏标题栏
 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏 隐藏状态栏
 //判断当前是否横屏 如果不是就设为横屏,设为横屏之后会自动调用onCreate方法
 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
 //获取屏幕的宽高
 DisplayMetrics dis = getResources().getDisplayMetrics();
 my.w = dis.widthPixels;
 my.h = dis.heightPixels;
 //获取屏幕分辨率和1920*1080的比例 以便适应不同大小的屏幕
 my.bili = (float) (Math.sqrt(my.w * my.h) / Math.sqrt(1920 * 1080));
 setContentView(new Hua(this));
 } else {
 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 横屏
 }
 }
}

新建类 Move.java

package com.yaogan.liziguo.yaogan;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;

/**
 * Created by Liziguo on 2018/6/15.
 */

public class Move {
 private float x1,y1;//按下时的坐标 大圆
 private float x2,y2;//移动后的坐标 小圆
 private final float r1,r2;//r1大圆的半径 r2小圆的半径
 public float angle;//x1y1指向x2y2的角度 弧度制
 public boolean down=false;//判断是否被按下
 public boolean in=false;//判断小圆是否在大圆里面,简单的说就是防止小圆被脱太远
 public boolean move=false;//判断手指按下后是否移动(MY实际开发中用到,该教程用不到此变量)
 public Bitmap img;//大圆小圆的图片

 public Move(){
 r1 = 480 * 0.5f * my.bili;//乘上一个比例 适应不同大小的屏幕
 r2 = 300 * 0.5f * my.bili;
 img= BitmapFactory.decodeResource(my.main.getResources(),R.mipmap.yaogan);//初始化摇杆图片
 }

 public void down(float xx,float yy){ //摇杆按下后的操作
 if(xx<r1) x1=r1;
 else x1 = xx;

 if(my.h-yy<r1) y1=my.h-r1;
 else y1 = yy;
 //上面的代码是防止按下的位置太靠近屏幕边缘
 //跟x1=xx;y1=yy;区别不大,待会可以改成x1=xx;y1=yy;看看效果有什么不同
 down=true;
 }
 public void move(float xx,float yy){ //按下摇杆后移动的操作
 angle=getAngle(xx,yy);
 in=in(xx, yy);
 move=isMove(xx,yy);
 if (!in) {
 //下面会做解释
 xx= (float) (x1+ Math.sin(angle)*r1*0.7f);
 yy= (float) (y1+ Math.cos(angle)*r1*0.7f);
 }
 x2=xx;
 y2=yy;
 }
 public void up(){ //松开后的操作
 down=false;
 }

 public float getAngle(float xx,float yy){ //获取x1y1指向x2y2的角度
 double angle,k;
 if (y1==yy)//斜率不存在时
 if (x1 > xx)//判断x1指向x2的方向
 angle=-Math.PI/2;
 else
 angle=Math.PI/2;
 else{
 k=(x1-xx)/(y1-yy); //两点的坐标求斜率,至于为什么是(x1-x2)/(y1-y2)不是(y1-y2)/(x1-x2)待会我们再做解释
 if (y1 > yy) {//判断x1y1指向x2y2的方向
 // 用反tan求角度 这个高中好像没学过 既然Math类已经帮我们封装好了就直接拿来用吧
 angle=Math.atan(k) + Math.PI;
 } else {
 angle=Math.atan(k);
 }
 //这段可写可不写 让计算出来的角度属于-PI/2到PI/2
 if(angle>Math.PI)
 angle-=Math.PI*2;
 else if(angle<-Math.PI)
 angle+=Math.PI*2;
 }
 return (float) angle;
 }

 public boolean in(float xx, float yy) { //防止小圆被脱太远 拖动范围不超出r1的70%
 double r = Math.sqrt((x1 - xx) * (x1 - xx) + (y1 - yy) * (y1 - yy));//两点间距离公式
 if (r < r1*0.7f)
 return true;
 else return false;
 }
 public boolean isMove(float xx, float yy) { //判断按下摇杆后 是否移动,如果x1y1 x2y2的距离大于r1*0.15视为移动
 // MY实际开发中用到,该教程用不到此变量
 double r = Math.sqrt((x1 - xx) * (x1 - xx) + (y1 - yy) * (y1 - yy));//两点间距离公式
 if (r > r1*0.15f)
 return true;
 else return false;
 }
 public void onDraw(Canvas g, Paint p){ //画摇杆
 if(down) { //当摇杆被按下时 才显示
 //怎么用Canvas画图这里就不说了
 my.re.left = x1 - r1;
 my.re.top = y1 - r1;
 my.re.right = x1 + r1;
 my.re.bottom = y1 + r1;
 g.drawBitmap(img, null, my.re, p); //画大圆
 my.re.left = x2 - r2;
 my.re.top = y2 - r2;
 my.re.right = x2 + r2;
 my.re.bottom = y2 + r2;
 g.drawBitmap(img, null, my.re, p); //画小圆
 }
 }
}

新建类 OnTouchMove.java

package com.yaogan.liziguo.yaogan;

import android.content.Context;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Liziguo on 2018/6/16.
 */

public class OnTouchMove extends View { //这个view负责监听移动摇杆的手势

 private Move m;

 public OnTouchMove(Context context,Move move) {
 super(context);
 this.m=move;
 setBackgroundColor(Color.WHITE);//背景色设为白色
 getBackground().setAlpha(my.ontouchAlpha);//设置触控区透明度
 setOnTouchListener(new OnTouchListener() { //设置触控监听
 @Override
 public boolean onTouch(View v, MotionEvent ev) {
 //加上getX() getY()因为这个view不是分布在左上角的
 final float xx = ev.getX() + getX(), yy = ev.getY() + getY();

 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
 m.down(xx, yy);//按下时的操作
// m.move(xx, yy);
 }
 m.move(xx, yy);//移动时的操作
 if (ev.getAction() == MotionEvent.ACTION_UP) {
 m.up();//松开时的操作
 }
 return true;//不要返回false
 }
 });
 }
}

修改 Hua.java 的代码

package com.yaogan.liziguo.yaogan;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.widget.RelativeLayout;

/**
 * Created by Liziguo on 2018/6/15.
 */

public class Hua extends RelativeLayout implements Runnable{ //继承RelativeLayout 实现Runnable接口

 private Paint p;//画笔
 private Move m=new Move();//移动摇杆

 public Hua(Context context) {
 super(context);
 p=new Paint();
 setBackgroundColor(Color.BLACK);//背景颜色设为黑色
 //实例化一个OnTouchMove
 OnTouchMove onTouchMove=new OnTouchMove(context,m);
 //把onTouchMove添加进来 宽度为屏幕的1/3 高度为屏幕的1/2
 addView(onTouchMove,my.w/3,my.h/2);
 //设置onTouchMove的位置
 onTouchMove.setX(0);
 onTouchMove.setY(my.h/2);

 new Thread(this).start();//启动重绘线程
 }

 @Override
 protected void onDraw(Canvas g) {//重写onDraw方法
 super.onDraw(g);
 m.onDraw(g,p);//画移动摇杆
 }

 @Override
 public void run() { //每隔20毫秒刷新一次画布
 while(true){
 try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}
 postInvalidate();//重绘 在子线程重绘不能调用Invalidate()方法
 }
 }
}

好的 现在我们的摇杆可以说已经做好一大半了,因为剩下的原理都一样

先运行一遍看看效果吧

左下角的白色矩形是我们的OnTouchMove类,为了更好的测试我们先让他显示出来 等做好了再隐藏掉

下面我们来解释一下为什么斜率k=(x1-x2)/(y1-y2)而不是(y1-y2)/(x1-x2)吧

因为我们手机上的平面直角坐标系跟数学上的平面直角坐标系不一样

数学上的平面直角坐标系是这样的

而我们手机是这样的

有没有发现把手机的坐标系 逆时针旋转一下就是数学里的坐标系了,不过x跟y调了一下位置

所以我们在写代码的时候把x y换一下就行了

数学坐标系中k=1的直线

程序中k=1的直线

再解释下 Move 类的 move方法

public void move(float xx,float yy){ //按下摇杆后移动的操作
 angle=getAngle(xx,yy);
 in=in(xx, yy);
 move=isMove(xx,yy);
 if (!in) {
 //下面会做解释
 xx= (float) (x1+ Math.sin(angle)*r1*0.7f);
 yy= (float) (y1+ Math.cos(angle)*r1*0.7f);
 }
 x2=xx;
 y2=yy;
 }

好的下面我们开始做技能摇杆,这教程做的比较累啊

下面的技能类是我直接从我游戏里拷贝过来的并做了些小修改

解释可能没那么清楚毕竟原理都一样

只不过是多了几个功能而已

准备图片

添加到工程里

由于图片比较多 我们加载图的代码位置改一下

修改 MainActivity。java 和 my.java

public class MainActivity extends AppCompatActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 my.main=this;
 getSupportActionBar().hide();//隐藏标题栏
 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏 隐藏状态栏
 //判断当前是否横屏 如果不是就设为横屏,设为横屏之后会自动调用onCreate方法
 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
 //获取屏幕的宽高
 DisplayMetrics dis = getResources().getDisplayMetrics();
 my.w = dis.widthPixels;
 my.h = dis.heightPixels;
 //获取屏幕分辨率和1920*1080的比例 以便适应不同大小的屏幕
 my.bili = (float) (Math.sqrt(my.w * my.h) / Math.sqrt(1920 * 1080));
 //加载图片
 my.border= BitmapFactory.decodeResource(my.main.getResources(),R.mipmap.border);
 my.cancel= BitmapFactory.decodeResource(my.main.getResources(),R.mipmap.cancel);
 my.down= BitmapFactory.decodeResource(my.main.getResources(),R.mipmap.down);
 my.yaogan= BitmapFactory.decodeResource(my.main.getResources(),R.mipmap.yaogan);
 my.cd= BitmapFactory.decodeResource(my.main.getResources(),R.mipmap.cd);
 setContentView(new Hua(this));
 } else {
 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);// 横屏
 }
 }
}
public class my { //这个类当一个全局变量使用
 public static int w,h;//屏幕的宽高
 public static float bili;
 public static MainActivity main;
 public static RectF re=new RectF();
 public static int ontouchAlpha=100;//触控区透明度0-255 0为透明,为了测试我们先设为100

 public static Bitmap border,cancel,down,yaogan,cd;

 public static Skill skill;//当前正在使用的技能 现在会报错 因为我们还没新建技能Skill类
}

修改 Move 类的构造方法

 public Move(){
 r1 = 480 * 0.5f * my.bili;//乘上一个比例 适应不同大小的屏幕
 r2 = 300 * 0.5f * my.bili;
// img= BitmapFactory.decodeResource(my.main.getResources(),R.mipmap.yaogan);//初始化摇杆图片////////////////////////
 img=my.yaogan;////////////////////////////////////////////////////
 }

新建技能类 Skill.java

package com.yaogan.liziguo.yaogan;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;

/**
 * Created by Liziguo on 2018/6/16.
 */

public abstract class Skill {
 public int jineng;
 private final float x,y;//技能图标中心位置,不是按下时的位置
 private float x2, y2;//技能按下移动后手指的坐标
 private float xxx,yyy;//判断拖动点是否超出两倍r的范围
 private final float calcelx, cancely;
 public float angle;//技能按下后 x y指向xx yy的角度
 public Bitmap img, imgborder, imgdown, imgyaogan,imgcd,imgcancel;
 private final float r2;
 private final float r3=50*my.bili;
 public boolean down=false;
 public boolean down_main=false;//down_main 只触发一次;
 public boolean cancel=false;
 public int cdmax;
 public long last,cd=0;//last最后一次释放技能的时间
 /*
 0 普通攻击
 1 技能1
 2 技能2
 3 技能3
 */
 public Skill(int jineng, int cd, Bitmap image){
 this.jineng=jineng;
 switch (jineng){
 case 0:
 x= my.w*0.87f;
 y= my.h*0.8f;
 break;
 case 1:
 x= my.w*0.7f;
 y= my.h*0.88f;
 break;
 case 2:
 x= my.w*0.75f;
 y= my.h*0.62f;
 break;
 case 3:
 x= my.w*0.9f;
 y= my.h*0.5f;
 break;
 default:x=y=0;
 }
 cdmax=cd;
 if(jineng == 0) r2=125*my.bili;
 else r2=80*my.bili;
 calcelx =my.w-r2*2;
 cancely =my.h/4;
 img=image;
 imgborder=my.border;
 imgdown=my.down;
 imgyaogan=my.yaogan;
 imgcd=my.cd;
 imgcancel=my.cancel;
 }
 // public abstract void down();
// public abstract void move();
// public abstract void up();
 public void down(){ //DOWN 由ontouch触发
 if(cd>0)return;
 down=true;
 my.skill=this;
 }
 public abstract void down_main(); //DOWN 教程用不到该抽象方法

 public void move(float x,float y){//按下技能后 由ontouch触发
 x2 =x;
 y2 =y;
 angle=getAngle(x2, y2);
 cancel=incancel(x,y);
 if (jineng !=0 && !in2(x,y)) {
 xxx= (float) (this.x+ Math.sin(angle)*r2*2);
 yyy= (float) (this.y+ Math.cos(angle)*r2*2);
 }else{
 xxx=x;
 yyy=y;
 }
 }
 public abstract void move_main();//按下技能后 由MyActor触发 教程用不到该抽象方法
 public abstract void up(); //松开后 由MyActor触发 释放技能

 public boolean in(float xx,float yy){ //判断是否被点中
 double r= Math.sqrt((x - xx)*(x-xx)+(y-yy)*(y-yy));
 if(r<r2)
 return true;
 else return false;
 }
 public boolean in2(float xx, float yy) { //判断拖动点是否超出两倍r的范围
 double r = Math.sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy));
 if (r < r2 * 2)
 return true;
 else return false;
 }
 public boolean incancel(float xx,float yy){ //判断是否取消
 double r= Math.sqrt((calcelx - xx)*(calcelx -xx)+(cancely -yy)*(cancely -yy));
 if(r<r2)
 return true;
 else return false;
 }
 public float getAngle(float xx,float yy){ //x y指向xx yy的角度
 float angle,k;
 if (y==yy)
 if (x > xx)
 angle= (float) (-Math.PI/2);
 else
 angle= (float) (Math.PI/2);
 else{
 k=(x-xx)/(y-yy);
 if (y > yy) {
 angle= (float) (Math.atan(k) + Math.PI);
 } else {
 angle= (float) Math.atan(k);
 }
 if(angle>Math.PI)
 angle-=Math.PI*2;
 else if(angle<-Math.PI)
 angle+=Math.PI*2;

 }
 return angle;
 }
 private float drawpx=10*my.bili;

 public void next(){
 //计算技能冷却时间
 cd=cdmax-System.currentTimeMillis()+last;
 }
 //按下的时候技能图标下移 显示蓝色框框
 public void onDraw(Canvas g, Paint p){
 my.re.left=x-r2;
 my.re.top=y-r2;
 my.re.right=x+r2;
 my.re.bottom=y+r2;
 if(down){
// new RectF(x-r2,y-r2,x+r2,y+r2);
// new RectF(x-r2,y-r2+10*my.bili,x+r2,y+r2+10*my.bili);
// my.re.left=x-r2;
// my.re.top=y-r2;
// my.re.right=x+r2;
// my.re.bottom=y+r2;
 if(jineng!=0){
 final float bl=2;
 my.re.left=x-r2*bl;
 my.re.top=y-r2*bl;
 my.re.right=x+r2*bl;
 my.re.bottom=y+r2*bl;
 //蓝色框框未下移
 g.drawBitmap(imgdown,null,my.re,p);
 }
 my.re.left=x-r2;
 my.re.top=y-r2;
 my.re.right=x+r2;
 my.re.bottom=y+r2;
 ///////////////////////////////////////////////////////////
 //技能图片和技能边框下移
 my.re.top+=drawpx;
 my.re.bottom+=drawpx;
 g.drawBitmap(img,null,my.re,p);
 my.re.left-=drawpx;
 my.re.top-=drawpx;
 my.re.right+=drawpx;
 my.re.bottom+=drawpx;

 g.drawBitmap(imgborder,null,my.re,p);
 if(jineng!=0){
 my.re.left=xxx-r3;
 my.re.top=yyy-r3;
 my.re.right=xxx+r3;
 my.re.bottom=yyy+r3;
 g.drawBitmap(imgyaogan,null,my.re,p);
 //cancle
 my.re.left= calcelx -r2;
 my.re.top= cancely -r2;
 my.re.right= calcelx +r2;
 my.re.bottom= cancely +r2;
 g.drawBitmap(imgcancel,null,my.re,p);
 }
 }else{
 g.drawBitmap(img,null,my.re,p);
 if(jineng!=0 && cd>0) {
 p.setTextSize(40*my.bili);
                p.setColor(Color.WHITE);
 g.drawBitmap(imgcd,null,my.re,p);
 float f=cd/100f;
 f=(int)f;
 f=f/10;
 g.drawText(String.valueOf(f),x-p.getTextSize()*4/5,y+p.getTextSize()/3,p);

 }
 my.re.left-=drawpx;
 my.re.top-=drawpx;
 my.re.right+=drawpx;
 my.re.bottom+=drawpx;
 g.drawBitmap(imgborder,null,my.re,p);
 }
 }
}

新建一个类 OnTouchSkill.java 他也是一个监听view

这样多点触控会好写很多,刚开始我是用一个view做监听的 写到我心态爆炸。。。

package com.yaogan.liziguo.yaogan;

import android.content.Context;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Liziguo on 2018/6/16.
 */

public class OnTouchSkill extends View {
 /*
 A 普通攻击
 Q 技能1
 W 技能2
 E 技能3
 R 没有R
 */

 public Skill A,Q,W,E;

 public OnTouchSkill(Context context,Skill a,Skill q,Skill w,Skill e) {
 super(context);
 A=a;Q=q;W=w;E=e;
 setBackgroundColor(Color.WHITE);
 getBackground().setAlpha(my.ontouchAlpha);//0-255
 setOnTouchListener(new OnTouchListener() {
 @Override
 public boolean onTouch(View v, MotionEvent ev) {
 final float xx = ev.getX() + getX(), yy = ev.getY() + getY();
 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
 if ( A.in(xx, yy)) {
 A.down();
 } else if ( Q.in(xx, yy)) {
 Q.down();
 } else if ( W.in(xx, yy)) {
 W.down();
 } else if ( E.in(xx, yy)) {
 E.down();
 }

 }
 if (my.skill != null) my.skill.move(xx, yy);
 if(ev.getAction()==MotionEvent.ACTION_UP){
 A.down = false;
 Q.down = false;
 W.down = false;
 E.down = false;
 }
 return true;
 }
 });
 }
}

把监听控件添加到Hua,修改 Hua.java

package com.yaogan.liziguo.yaogan;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.widget.RelativeLayout;

/**
 * Created by Liziguo on 2018/6/15.
 */

public class Hua extends RelativeLayout implements Runnable{ //继承RelativeLayout 实现Runnable接口

 private Paint p;//画笔
 private Move m=new Move();//移动摇杆

 /*
 A 普通攻击
 Q 技能1
 W 技能2
 E 技能3
 R 没有R
 */

 public Skill A=new Skill(0,100, BitmapFactory.decodeResource(getResources(),R.mipmap.putonggongji)) {
 @Override
 public void down_main() { }
 @Override
 public void move_main() { }
 @Override
 public void up() { }
 };
 public Skill Q=new Skill(1,1000, BitmapFactory.decodeResource(getResources(),R.mipmap.skill1)) {
 @Override
 public void down_main() { }
 @Override
 public void move_main() { }
 @Override
 public void up() {
 down_main=false;
 if(!cancel){ //技能冷却时间
 last= System.currentTimeMillis();
 }
 }
 };
 public Skill W=new Skill(2,1000, BitmapFactory.decodeResource(getResources(),R.mipmap.skill2)) {
 @Override
 public void down_main() { }
 @Override
 public void move_main() { }
 @Override
 public void up() {
 down_main=false;
 if(!cancel){
 last= System.currentTimeMillis();
 }
 }
 };
 public Skill E=new Skill(3,1000, BitmapFactory.decodeResource(getResources(),R.mipmap.skill3)) {
 @Override
 public void down_main() { }
 @Override
 public void move_main() { }
 @Override
 public void up() {
 down_main=false;
 if(!cancel){
 last= System.currentTimeMillis();
 }
 }
 };

 public Hua(Context context) {
 super(context);
 p=new Paint();
 setBackgroundColor(Color.BLACK);//背景颜色设为黑色
 //实例化一个OnTouchMove
 OnTouchMove onTouchMove=new OnTouchMove(context,m);
 //把onTouchMove添加进来 宽度为屏幕的1/3 高度为屏幕的1/2
 addView(onTouchMove,my.w/3,my.h/2);
 //设置onTouchMove的位置
 onTouchMove.setX(0);
 onTouchMove.setY(my.h/2);

 //添加技能摇杆监听
 OnTouchSkill onTouchSkill=new OnTouchSkill(context,A,Q,W,E);//后添加的优先级高
 addView(onTouchSkill);
 onTouchSkill.setX(my.w*0.7f-85*my.bili);
 onTouchSkill.setY(my.h/2-85*my.bili);
 new Thread(this).start();//启动重绘线程
 }

 @Override
 protected void onDraw(Canvas g) {//重写onDraw方法
 super.onDraw(g);
 m.onDraw(g,p);//画移动摇杆
 //画技能
 A.onDraw(g,p);
 Q.onDraw(g,p);
 W.onDraw(g,p);
 E.onDraw(g,p);
 }

 @Override
 public void run() { //每隔20毫秒刷新一次画布
 while(true){
 try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}
 //计算冷却时间
 A.next();
 Q.next();
 W.next();
 E.next();
 //释放技能
 if (my.skill != null) {
 my.skill.down_main();//教程用不到该方法
 my.skill.move_main();//教程用不到该方法
 if (my.skill.down == false) {
 my.skill.up();
 my.skill = null;
 }
 }

 postInvalidate();//重绘 在子线程重绘不能调用Invalidate()方法
 }
 }
}

运行下看看效果吧

修改 my.java

public class my { //这个类当一个全局变量使用
 public static int w,h;//屏幕的宽高
 public static float bili;
 public static MainActivity main;
 public static RectF re=new RectF();
 public static int ontouchAlpha=0;//把触控区透明度改成0

 public static Bitmap border,cancel,down,yaogan,cd;

 public static Skill skill;//当前正在使用的技能
}

再运行下

大功告成

下载地址:

android studio游戏摇杆开发教程 仿王者荣耀摇杆

以上所述是小编给大家介绍的android studio游戏摇杆开发教程详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android studio 3.0安装配置方法图文教程

    本文为大家分享了Android studio安装与配置,具体内容如下 1.首先下载Android studio安装包,可以从http://www.android-studio.org/,下载最新版本,这里采用3.0版本进行演示,对应安装包为android-studio-ide-171.4408382-windows.exe,安装包大小681 MB,安装包不带SDK 2.下载好该安装包之后,点击进行安装,依次出现以下界面 在这里自己选择程序安装路径 这里Android studio程序安装完毕,但

  • Android studio 3.0 查看手机文件系统的方法(超简单)

    众所周知,我们要查看安卓手机中文件系统前提条件是要root手机,然后去DDMS里面去看,但是现在很多手机都不好root,替代的方法是用电脑模拟器,不管怎么样,都挺麻烦的,最近更新Android studio 到3.0版本,无意间发现了一个方法,非常简单,还不用root手机. 1.手机USB线连接手机,打开调试模式 2.打开AS,找到窗口右下角的Device File Explorer,如下图: 3.点击这个按钮,就直接打开了手机的文件系统,如图: 4.接下来看下我们最关注的data/data和s

  • Android Studio升级到3.0后遇到的坑

    这几天谷歌推出了as3.0的正式版,相信大家都进行更新了,然后对3.0的新特性也有过一些了解,最后磨刀霍霍开始宰杀,然鹅却一不小心就开始了排坑之路. 第一坑.必须升级gradle到4.0以上 相信这个大坑,一般使用as的人都会解决了,所以就不多说 第二坑.buildToolsVersion升级到26.0.0 其实这个不算坑,一般buildToolsVersion都会升级到最新的版本,直接更新就是了 第三坑.Error:Resource shrinker cannot be used for li

  • Android Studio 3.0上分析内存泄漏的原因

    以前用eclipse的时候,我们采用的是DDMS和MAT,不仅使用步骤复杂繁琐,而且要手动排查内存泄漏的位置,操作起来比较麻烦.后来随着Android studio的潮流,我也抛弃了eclipse加入了AS. Android Studio也开始支持自动进行内存泄漏检查,并且操作起来也比较方便. 封面 戳我下载 Android Studio 3.0 这个不用梯子我会告诉你吗 1.写在前面 Google在上周发布了Android Studio 3.0的正式版本,周四早晨在上班的地铁上就看到群里在沸沸

  • 详解Android Studio 3.0的新特性与适配

    简介 Android Studio升级到3.0后,有不少的改动和新特性,先贴出官方的迁移说明. 本文会持续收集与总结本人在使用Android Studio 3.0进行开发的过程中所遇到的问题. 版本配置 Gradle版本 Android Studio 3.0需要的Gradle版本至少为4.1. 如果是使用gradle wrapper,则工程根目录/gradle/wrapper/gradle-wrapper.properties中的distributionUrl字段为https\://servic

  • AndroidStudio项目打包成jar的简单方法

    首先备注一下 JAR(Java Archive,Java 归档文件)是与平台无关的文件格式,它允许将许多文件组合成一个压缩文件.为 J2EE 应用程序创建的 JAR 文件是 EAR 文件(企业 JAR 文件). 什么是AAR,与JAR区别 *.jar:只包含了class文件与清单文件,不包含资源文件,如图片等所有res中的文件. *.aar:包含所有资源,class以及res资源文件全部包含 Android Studio 如何打JAR包 在eclipse中我们知道如何将一个项目导出为jar包,供

  • Android Studio3.0新特性及安装图文教程

    Android Studio是Android的官方IDE.它是专为Android而打造,可以加快您的开发速度,帮助您为每款Android设备构建最优应用. 它提供专为Android开发者量身定制的工具,其中包括丰富的代码编辑.调试.测试和性能分析工具. 一.Android Studio3.0新特性 (1).核心IDE更改 我们将基础IDE从IntelliJ 2016.2升级到2017.1.2,在2016.3和 2017.1中增加了许多新功能, 包括参数提示,语义突出显示,搜索中的即时结果等等.

  • Android Studio 升级到3.0后输入法中文状态下无法选词的终极解决方案

    AndroidStudio终于出3.0正式版了,内置了kotlin(虽然我安了插件一直能用).一直忍着没敢下rc版的好奇猫,总算装了正式版.当然,伴随每次大版本更新,总有一些恼人的后遗症,其中以gradle问题最多.AS3.0要求gradle版本在3.5以上,配置文件内将标准版本指定为gradle-4.1-milestone-1. 之前用的是AS2.3,在稳定版3.0发布之后由于好奇,就更新到了3.0.但是,除了Android Profiler分析器+自我感觉native编译速度加快以外,其他的

  • 浅谈Android Studio 3.0 工具新特性的使用 Android Profiler 、Device File Explorer

    前言: 其实 studio3.0的工具大家也已经使用过一段时间了,自己呢,就是从bate版开始使用的,我觉得比较好用的几个地方.就几个,可能还没用到其他的精髓. 但我觉的这个两个功能对我是比较实用的.好那么下面就给大家介绍一下吧. 正文: 话不多说咱们直接上图吧.(个人比较喜欢看图说话) 第一个(Android Profiler)我要介绍的就是这个了.(先看一下效果"震撼一下") (图-1) (图-2) (图-3) (厉害不厉害,牛逼不牛逼)那么我们怎么来操作这个工具呢,来咱们接着看图

  • 浅析Android Studio 3.0 升级各种坑(推荐)

    点击 Check for Updates 增量更新: 下载完成,会提示更新 您将 Gradle 更新至 4.1: 这里建议您对老项目先暂时点击 Don't remind me on this project,以防有坑.当然我不入地狱谁入地狱,我点 Update,于是问题来了,一直处于下载中,不过,莫担心,我下载好了,公众号聊天界面回复「 gradle-4.1-all 」,下载 gradle-4.1-all.zip 文件,放到: 重启 Android Studio. gradle 目录: Mac系

随机推荐