Andriod小程序——简单制作游戏中控制任务移动的轮盘

Andriod小程序——简单制作游戏中控制人物移动的轮盘

  • 说明
    • 自定义自己的view继承于View类
    • 重写onDraw()方法
      • 当我们看到这个控件的时候那个样子,如图
      • 完善onDraw()方法
        • 重写OnTouch()方法
        • 更新onDraw()方法
    • 解决遗留问题
      • 解决切割问题
      • 解决主程序的调用问题
    • 最后放上程序的完整代码
      • 重写的控件
      • 主程序中调用

说明

近期有在做一个项目,项目的其中一个要求就是,做一个控制设备上下左右的轮盘。网上找了好多都是猜奖转盘,本菜鸟表示心情十分复杂。于是在花费了19个小时之后,本菜鸡才简单制作了一个 成型,话不多说,先上图
Andriod小程序——简单制作游戏中控制任务移动的轮盘_第1张图片
上面出现的两个数,是移动的参数,一会儿我会说明。
这个效果实现起来相当简单 文末含有整个类只要有一点android基础,一看就懂,下面一步步解释。

自定义自己的view继承于View类

一般都是继承于View类,看自己的需求。
当然也可以继承于SurfaceView,但是这里,不会一直刷新,我认为没必要。

public class DiscView extends View {
	//有人可能不懂三个构造方法的意思,我解释一下

	//在主程序中new的时候调用这个
	//DiscView disc = new DiscView(this);
	public DiscView(Context context) {
        this(context,null);
    }

	//在xml文件中创建控件是调用这个
    public DiscView(Context context,AttributeSet attrs) {
        this(context, attrs, 0 );
    }

	//在xml文件中创建控件,指定style属性的时候会使用这个方法,否则默认第二种
    public DiscView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        manager = LocalBroadcastManager.getInstance(context);
    }
}

重写onDraw()方法

这里是 重点,整个控件的核心 要一步步来。

当我们看到这个控件的时候那个样子,如图

Andriod小程序——简单制作游戏中控制任务移动的轮盘_第2张图片

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.TRANSPARENT);

        //设置背景图的半径
        radiusBack = getWidth() / 2;
        //设置小圆点的半径
        radiusPre = getWidth() / 4;
        //圆心
        circleX = getWidth() / 2;
        circleY = getHeight() / 2;

        if (paint == null) {
            paint = new Paint();
        }
        //设置画笔的基本属性
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(0x7f111111);
        //画出内圆
        canvas.drawCircle(circleX,circleY,(float) radiusBack,paint);
        //画出外圆,内外圆颜色不一样,所以要用不同的颜色
        paint.setColor(0xFF744041);
        canvas.drawCircle(btnX,btnY,(float) radiusPre,paint);
        canvas.save();
    }

但是这个肯定不是我们需要的效果。
所以说肯定是要动态刷新的。我们整理一下思路。

手指点击或移动要刷新内部圆
手指离开屏幕
静态
刷新后的图形
内部圆回到初始位置,同时记录参数
结束

接下来实现这个过程

完善onDraw()方法

因为要捕获手指的位置,因此重写onTouch()方法是不可少的

重写OnTouch()方法

	@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_MOVE:
            	//手指在屏幕上移动会调用这个方法,(btnX,btnY)是内部圆的圆心
            	//我们要随时根据自己的手指位置来带动内部圆移动,因此在手指移动过程中要记录圆心。
                btnX = (int) event.getX();
                btnY = (int) event.getY();
                //记录圆心,进行判断,我们不希望我们的内部圆完全跑到外部之外,所以要进行判断,当内部圆的圆心在离开外圆,就控制他不离开外圆
                //这里用到了勾股定理
                if ((btnY - circleY)*(btnY - circleY) + (btnX - circleX)*(btnX - circleX) >= radiusBack * radiusBack){
                	//改变圆心位置
                    changeBtnLocation();
                }
                //每次都要提交并刷新屏幕,invalidate会调用OnDraw()方法
                this.invalidate();
                break;
            case MotionEvent.ACTION_UP:
            	//当手指离开的时候 把btnX和btnY都置为零,onMesure中进行判断,当两个都为零时
            	btnX = 0;
                btnY = 0;
                //同样刷新
                this.invalidate();
                break;
        }
        //返回true时屏幕才会对你的手势拦截并消费。
        return true;
    }

关于changeBtnLocation()方法,这里会用到数学知识。
这里我画了一个图,简单易懂
Andriod小程序——简单制作游戏中控制任务移动的轮盘_第3张图片

	/**
     * 这里会用到数学知识,相似三角形
     */
    private void changeBtnLocation() {
        //相似比
        double similarity = Math.sqrt((radiusBack * radiusBack) / ((btnY - circleY)*(btnY - circleY) + (btnX - circleX)*(btnX - circleX)));
        //改变(btnX,btnY)的位置
        btnX = (int) ((btnX - circleX)*similarity + circleX);
        btnY = (int) ((btnY - circleY)*similarity + circleY);
    }

之前的onDraw()方法只有之前的版本,这里,我们要改一下,让他根据生成的btnX btnY的值进行不同的刷新

更新onDraw()方法

	@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.TRANSPARENT);

        //设置背景图的半径
        radiusBack = getWidth() / 2;
        //设置小圆点的半径
        radiusPre = getWidth() / 4;
        //圆心
        circleX = getWidth() / 2;
        circleY = getHeight() / 2;

        if (paint == null) {
            paint = new Paint();
        }
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(0x7f111111);
        canvas.drawCircle(circleX,circleY,(float) radiusBack,paint);
        //如果手指离开屏幕
        if (btnX <= 0 && btnY <= 0){
            paint.setColor(0xFFF10159);
            canvas.drawCircle(circleX,circleY,(float) radiusPre,paint);
            canvas.save();
            return;
        }
        //手指点击屏幕,之所以颜色参数不一样,是为了让点击有反馈
        paint.setColor(0xFF744041);
        canvas.drawCircle(btnX,btnY,(float) radiusPre,paint);
        canvas.save();
    }

写到这里,会有一个问题差不多就可以跑起来了。但是还有几个问题

  • 控件的layout_width 和 layout_height要一样。
  • 内圆移动到边缘会被切割掉,很丑。
  • 控件写完了,但是我们的主程序怎么用啊。总不能为了好看而搞个控件出来。

关于第一个问题网上很多解决方法 ,我懒得写了 ,我是用的时候直接设置一样的,如有需要,重写 onMeasure() 方法

解决遗留问题

解决切割问题

很简单,让内圆和外圆的直径加起来小于控件的宽度,即getWidth()即可

	//设置背景图的半径
    radiusBack = getWidth() / 3;
	//设置小圆点的半径
    radiusPre = getWidth() / 8;
    // 2 / 3 + 2 / 8 = 11 / 12 < 1

解决主程序的调用问题

这个也很简单;在移动或者手指离开的时候 根据需求 发个广播就行了
在主程序中接收广播就行了

	private void sendAction(int x,int y) {
        Intent intent = new Intent(DISC_BROADCAST);
        intent.putExtra("move",(x - circleX) + " " + (y - circleY));
        manager.sendBroadcast(intent);
    }

最后放上程序的完整代码

重写的控件

package com.example.administrator.myapplication;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v4.content.LocalBroadcastManager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class DiscView extends View {

    private Paint paint;
    private int btnX;
    private int btnY;
    //内外圆半径
    private int radiusBack;
    private int radiusPre;
    //外圆圆心
    private float circleX;
    private float circleY;

    //广播action
    public static final String DISC_BROADCAST = "com.scsdesign.DISCVIEW";
    private LocalBroadcastManager manager;


    public DiscView(Context context) {
        this(context,null);
    }

    public DiscView(Context context,AttributeSet attrs) {
        this(context, attrs, 0 );
    }

    public DiscView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        manager = LocalBroadcastManager.getInstance(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.TRANSPARENT);

        //设置背景图的半径
        radiusBack = getWidth() / 3;
        //设置小圆点的半径
        radiusPre = getWidth() / 8;
        //圆心
        circleX = getWidth() / 2;
        circleY = getHeight() / 2;

        if (paint == null) {
            paint = new Paint();
        }
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(0x7f111111);
        canvas.drawCircle(circleX,circleY,(float) radiusBack,paint);
        if (btnX <= 0 && btnY <= 0){
            paint.setColor(0xFFF10159);
            canvas.drawCircle(circleX,circleY,(float) radiusPre,paint);
            canvas.save();
            return;
        }
        paint.setColor(0xFF744041);
        canvas.drawCircle(btnX,btnY,(float) radiusPre,paint);
        canvas.save();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_MOVE:
                System.out.println(event.getX() + " " + event.getY());
                btnX = (int) event.getX();
                btnY = (int) event.getY();
                if ((btnY - circleY)*(btnY - circleY) + (btnX - circleX)*(btnX - circleX) >= radiusBack * radiusBack){
                    changeBtnLocation();
                }
                this.invalidate();
                break;
            case MotionEvent.ACTION_UP:
                System.out.println(event.getX() + " " + event.getY() + "TAG");
                //发广播
                sendAction(btnX,btnY);
                btnX = 0;
                btnY = 0;
                this.invalidate();
                break;
        }

        return true;
    }



    private void sendAction(int x,int y) {
        Intent intent = new Intent(DISC_BROADCAST);
        intent.putExtra("move",(x - circleX) + " " + (y - circleY));
        manager.sendBroadcast(intent);
    }

    /**
     * 这里会用到数学知识
     */
    private void changeBtnLocation() {
        //相似比
        double similarity = Math.sqrt((radiusBack * radiusBack) / ((btnY - circleY)*(btnY - circleY) + (btnX - circleX)*(btnX - circleX)));
        btnX = (int) ((btnX - circleX)*similarity + circleX);
        btnY = (int) ((btnY - circleY)*similarity + circleY);
    }

}

主程序中调用

package com.example.administrator.myapplication;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private String message;
    private MyBroadCastReceiver receiver;
    private LocalBroadcastManager manager;
    private DiscView view;
    private boolean is = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        view = findViewById(R.id.view);
        textView = findViewById(R.id.textView2);

		/**
		 * 注册本地广播接收器就,接收广播
		 **/
        manager = LocalBroadcastManager.getInstance(this);
        IntentFilter filter = new IntentFilter();
        filter.addAction(view.DISC_BROADCAST);
        receiver = new MyBroadCastReceiver();
        manager.registerReceiver(receiver,filter);
    }

    class MyBroadCastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String string = intent.getStringExtra("move");
            textView.setText(string);
        }
    }

}

你可能感兴趣的:(安卓)