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

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

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

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

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

最终效果


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

新建一个项目


建好项目之后,我们先新建一个类叫做“画”。也是我们的主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游戏摇杆开发教程详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对Devmax网站的支持!

详解android studio游戏摇杆开发教程,仿王者荣耀摇杆的更多相关文章

  1. html5 canvas合成海报所遇问题及解决方案总结

    这篇文章主要介绍了html5 canvas合成海报所遇问题及解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  4. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  5. Ionic – Splash Screen适用于iOS,但不适用于Android

    我有一个离子应用程序,其中使用CLI命令离子资源生成的启动画面和图标iOS版本与正在渲染的启动画面完美配合,但在Android版本中,只有在加载应用程序时才会显示白屏.我检查了config.xml文件,所有路径看起来都是正确的,生成的图像出现在相应的文件夹中.(我使用了splash.psd模板来生成它们.我错过了什么?这是config.xml文件供参考,我觉得我在这里做错了–解决方法在config.xml中添加以下键:它对我有用!

  6. ios – 无法启动iPhone模拟器

    /Library/Developer/CoreSimulator/Devices/530A44CB-5978-4926-9E91-E9DBD5BFB105/data/Containers/Bundle/Application/07612A5C-659D-4C04-ACD3-D211D2830E17/ProductName.app/ProductName然后,如果您在Xcode构建设置中选择标准体系结构并再次构建和运行,则会产生以下结果:dyld:lazysymbolbindingFailed:Symbol

  7. Xamarin iOS图像在Grid内部重叠

    heyo,所以在Xamarin我有一个使用并在其中包含一对,所有这些都包含在内.这在Xamarin.Android中看起来完全没问题,但是在Xamarin.iOS中,图像与标签重叠.我不确定它的区别是什么–为什么它在Xamarin.Android中看起来不错但在iOS中它的全部都不稳定?

  8. 在iOS上向后播放HTML5视频

    我试图在iPad上反向播放HTML5视频.HTML5元素包括一个名为playbackRate的属性,它允许以更快或更慢的速率或相反的方式播放视频.根据Apple’sdocumentation,iOS不支持此属性.通过每秒多次设置currentTime属性,可以反复播放,而无需使用playbackRate.这种方法适用于桌面Safari,但似乎在iOS设备上的搜索限制为每秒1次更新–在我的情况下太慢了.有没有办法在iOS设备上向后播放HTML5视频?解决方法iOS6Safari现在支持playbackRat

  9. 使用 Swift 语言编写 Android 应用入门

    Swift标准库可以编译安卓armv7的内核,这使得可以在安卓移动设备上执行Swift语句代码。做梦,虽然Swift编译器可以胜任在安卓设备上编译Swift代码并运行。这需要的不仅仅是用Swift标准库编写一个APP,更多的是你需要一些框架来搭建你的应用用户界面,以上这些Swift标准库不能提供。简单来说,构建在安卓设备上使用的Swiftstdlib需要libiconv和libicu。通过命令行执行以下命令:gitclonegit@github.com:SwiftAndroid/libiconv-libi

  10. Android – 调用GONE然后VISIBLE使视图显示在错误的位置

    我有两个视图,A和B,视图A在视图B上方.当我以编程方式将视图A设置为GONE时,它将消失,并且它正下方的视图将转到视图A的位置.但是,当我再次将相同的视图设置为VISIBLE时,它会在视图B上显示.我不希望这样.我希望视图B回到原来的位置,这是我认为会发生的事情.我怎样才能做到这一点?编辑–代码}这里是XML:解决方法您可以尝试将两个视图放在RelativeLayout中并相对于彼此设置它们的位置.

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部