zoukankan      html  css  js  c++  java
  • Android快乐贪吃蛇游戏实战项目开发教程-05虚拟方向键(四)四个三角形按钮

    该系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html

    一、如何判断点击的是哪个方向键按钮

    在上篇教程中我们实现了左边的三角形按钮效果,本篇教程我们将左、上、右、下四个三角形按钮都一起实现了。
    能做出一个来,另外三个应该不难了吧?但实际并非怎么简单哦。
    首先我们来解决一下上节课遗留的一个问题,如何判断当前手指点击的是哪个三角形按钮?


    这个需要用解析几何大法来解决。
    假设我们的控件是边长为1的正方形,建立平面直角坐标系(注意:计算机中坐标系原点在左上角哦),如下图:

    正方形的对角线将控件分成了4个三角形区域,也就是我们的4个方向键按钮。

    据上图可知:
    左上角到右下角对角线的方程为y=x;
        y>x的区域包含左和下三角形
        y<x的区域包含右和上三角形

    右上角到左下角的对角线方程为y=-x+1;
        y>1-x的区域包含右和下三角形
        y<1-x的区域包含左和上三角形

    综上可得:
        y>x 且 y<1-x 表示左三角
        y<x 且 y<1-x 表示上三角
        y<x 且 y>1-x 表示右三角
        y>x 且 y>1-x 表示下三角

    以上是按照边长为1的正方形得到的结论,但实际中,我们的控件不一定是正方形,边长也不是1,而是一个不确定的矩形,这该怎么办呢?
    这就需要经过一定的转换,将普通的矩形转换为边长为1的正方形。
    这个转变也简单,如下:
    设画布上被触摸到的点的坐标为(x,y),则:

        float relativeX = x / width;//0<=relativeX<=1
        float relativeY = y / height;//0<=relativeY<=1

    我们将画布上被触摸的点的横纵坐标分别除以画布的宽和高,这样就得到了一个相对坐标,而这个相对坐标的取值一定在0到1之间。这样就相当于把一个不确定的矩形简化成了一个边长为1的正方形处理。

    二、程序代码

    有了上面的了解,下面就可以写代码了。由于有4个三角形按钮,而每个按钮又有两种状态,代码会稍微长点。但每个按钮的逻辑都是一样的,都是按哪个那个高亮,不按时都恢复正常状态。代码中的注释比较详细,相信大家如果看了前面的教程内容,看这个应该问题不大。唯一需要注意的是每次调用invalidate方法重绘界面时,是需要对整个画布都重绘的,而不能只重绘一个三角形。

    这里我们需要先引入一个表示方向的枚举:Direction

    package net.chengyujia.happysnake;
    
    /**
     * 用来表示方向的枚举
     * Created by ChengYuJia on 2016/8/21.
     */
    public enum Direction {
        //none表示没有方向键按下
        none,
        //
        left,
        //
        up,
        //
        right,
        //
        down;
    }

     
    下面是当前DirectionKeys的完整代码:

    package net.chengyujia.happysnake;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    /**
     * 屏幕上的虚拟方向键
     * Created by ChengYuJia on 2016/8/19.
     */
    public class DirectionKeys extends View {
        //左三角形按压时的颜色(较亮)
        private int leftPressedColor = 0xFFFF0000;
        //左三角形正常显示的颜色(较暗)
        private int leftNormalColor = 0xFFAA0000;
        //上三角形按压时的颜色(较亮)
        private int upPressedColor = 0xFF00FF00;
        //上三角形正常显示的颜色(较暗)
        private int upNormalColor = 0xFF00AA00;
        //右三角形按压时的颜色(较亮)
        private int rightPressedColor = 0xFF0000FF;
        //右三角形正常显示的颜色(较暗)
        private int rightNormalColor = 0xFF0000AA;
        //下三角形按压时的颜色(较亮)
        private int downPressedColor = 0xFFFFFF00;
        //下三角形正常显示的颜色(较暗)
        private int downNormalColor = 0xFFAAAA00;
    
        //画笔
        private Paint paint = new Paint();
        //画左三角形的路径
        private Path pathLeft = new Path();
        //画上三角形的路径
        private Path pathUp = new Path();
        //画右三角形的路径
        private Path pathRight = new Path();
        //画下三角形的路径
        private Path pathDown = new Path();
    
        //画布的宽
        private int width;
        //画布的高
        private int height;
        //初始化方法是否执行过,确保初始化方法只执行一次。
        private boolean initDone = false;
        //记录当前哪个方向键被按下
        private Direction currentDirection = Direction.none;
    
        //只有一个参数的构造方法是我们在程序中通过“new”关键字创建实例时调用。
        public DirectionKeys(Context context) {
            super(context);
        }
    
        //有两个参数的构造方法是系统在XML布局文件中创建实例时调用。
        public DirectionKeys(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        //初始化方法
        private void init(Canvas canvas) {
            /*获取画布的长和宽*/
            width = canvas.getWidth();
            height = canvas.getHeight();
            /*
            (小提示:在计算机中一般都是将左上角作为坐标原点的)
            画布上四个顶点和中心点的坐标如下:
            左上点 0,0
            左下点 0,height
            右上点 width,0
            右下点 width,height
            中心点 width/2,height/2
            */
    
            /*设置左三角形的路径数据*/
            //从画布左上点开始
            pathLeft.moveTo(0, 0);
            //画直线到画布中心点
            pathLeft.lineTo(width / 2, height / 2);
            //再画直线到画布左下点
            pathLeft.lineTo(0, height);
            //自动闭合图形。从最后一个点(左下点)画直线到第一个点(左上点)。
            pathLeft.close();
    
            /*同理设置上三角形的路径数据*/
            pathUp.moveTo(0, 0);
            pathUp.lineTo(width / 2, height / 2);
            pathUp.lineTo(width, 0);
            pathUp.close();
    
            /*同理设置右三角形的路径数据*/
            pathRight.moveTo(width, 0);
            pathRight.lineTo(width / 2, height / 2);
            pathRight.lineTo(width, height);
            pathRight.close();
    
            /*同理设置下三角形的路径数据*/
            pathDown.moveTo(width, height);
            pathDown.lineTo(width / 2, height / 2);
            pathDown.lineTo(0, height);
            pathDown.close();
        }
    
        //画路径的共用方法
        private void drawPath(Path path, int color, Canvas canvas) {
            //设置画笔颜色
            paint.setColor(color);
            //用画笔在画布上按照路径数据画出图形
            canvas.drawPath(path, paint);
        }
    
        //画左三角正常颜色
        private void drawLeftNormal(Canvas canvas) {
            drawPath(pathLeft, leftNormalColor, canvas);
        }
    
        //画左三角按压颜色(高亮)
        private void drawLeftPressed(Canvas canvas) {
            drawPath(pathLeft, leftPressedColor, canvas);
        }
    
        //画上三角正常颜色
        private void drawUpNormal(Canvas canvas) {
            drawPath(pathUp, upNormalColor, canvas);
        }
    
        //画上三角按压颜色(高亮)
        private void drawUpPressed(Canvas canvas) {
            drawPath(pathUp, upPressedColor, canvas);
        }
    
        //画右三角正常颜色
        private void drawRightNormal(Canvas canvas) {
            drawPath(pathRight, rightNormalColor, canvas);
        }
    
        //画右三角按压颜色(高亮)
        private void drawRightPressed(Canvas canvas) {
            drawPath(pathRight, rightPressedColor, canvas);
        }
    
        //画下三角正常颜色
        private void drawDownNormal(Canvas canvas) {
            drawPath(pathDown, downNormalColor, canvas);
        }
    
        //画下三角按压颜色(高亮)
        private void drawDownPressed(Canvas canvas) {
            drawPath(pathDown, downPressedColor, canvas);
        }
    
        //所有按钮恢复正常颜色
        private void reset(Canvas canvas) {
            drawLeftNormal(canvas);
            drawUpNormal(canvas);
            drawRightNormal(canvas);
            drawDownNormal(canvas);
        }
    
        //当按左三角时,左三角高亮,其它正常。
        private void drawWhenLeftPressed(Canvas canvas) {
            drawLeftPressed(canvas);
            drawUpNormal(canvas);
            drawRightNormal(canvas);
            drawDownNormal(canvas);
        }
    
        //当按上三角时,上三角高亮,其它正常。
        private void drawWhenUpPressed(Canvas canvas) {
            drawLeftNormal(canvas);
            drawUpPressed(canvas);
            drawRightNormal(canvas);
            drawDownNormal(canvas);
        }
    
        //当按右三角时,右三角高亮,其它正常。
        private void drawWhenRightPressed(Canvas canvas) {
            drawLeftNormal(canvas);
            drawUpNormal(canvas);
            drawRightPressed(canvas);
            drawDownNormal(canvas);
        }
    
        //当按下三角时,下三角高亮,其它正常。
        private void drawWhenDownPressed(Canvas canvas) {
            drawLeftNormal(canvas);
            drawUpNormal(canvas);
            drawRightNormal(canvas);
            drawDownPressed(canvas);
        }
    
        /**
         * 通过重写父类的onDraw方法来绘制我们需要的图形
         * 该方法会在控件第一次显示时被系统调用,并在之后每次调用invalidate方法后被系统调用。
         *
         * @param canvas 这里的canvas是系统提供的一块矩形画布,我们要做的就是在这块画布上画我们想要的东西。
         */
        @Override
        protected void onDraw(Canvas canvas) {
            if (!initDone) {
                init(canvas);
                //确保初始化方法只执行一次
                initDone = true;
            }
    
            //按下不同的方向键,绘制不同的界面效果。
            switch (currentDirection) {
                case left://按下左键时
                    drawWhenLeftPressed(canvas);
                    break;
                case up://按下上键时
                    drawWhenUpPressed(canvas);
                    break;
                case right://按下右键时
                    drawWhenRightPressed(canvas);
                    break;
                case down://按下下键时
                    drawWhenDownPressed(canvas);
                    break;
                default://其它情况
                    reset(canvas);
            }
        }
    
        /**
         * 当用户触摸到该控件时,系统通过该方法告诉控件“你被摸了,要不要有反应啊?有反应返回true,没反应返回false。”
         * 控件说“那要看是怎么摸的了。如果是按下,我就将对应的三角形按键高亮显示;如果是抬起,我就将所有的三角形按键恢复成正常的颜色。其它情况我就不反应了,摸就摸吧。”
         *
         * @param event 系统给我们传递的触摸事件参数
         * @return 如果该触摸事件被我们处理了返回true,反之返回false。
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            //获取当前的触摸动作
            int action = event.getAction();
            if (action == MotionEvent.ACTION_DOWN) {//按下
                //获取触摸点的坐标
                float x = event.getX();
                float y = event.getY();
                currentDirection = getDirection(x, y);
                invalidate();//重绘
                return true;
            } else if (action == MotionEvent.ACTION_UP) {//抬起
                currentDirection = Direction.none;
                invalidate();//重绘
                return true;
            } else {//其它不处理
                return false;
            }
        }
    
        //根据坐标判断哪个三角形方向键被按下
        private Direction getDirection(float x, float y) {
            //经过坐标转换,统一成边长为1的正方形处理。对角线分割形成的4个区域,分别代表4个方向。
            float relativeX = x / width;//0<=relativeX<=1
            float relativeY = y / height;//0<=relativeY<=1
            /*
            注意:原点是左上角。
            左上角到右下角对角线方程为y=x;
                则:
                y>x的区域包含左和下三角形
                y<x的区域包含右和上三角形
    
            左下角到右上角对角线方程为y=-x+1;
                则:
                y>1-x的区域包含右和下三角形
                y<1-x的区域包含左和上三角形
    
            综上可得:
                y>x 且 y<1-x 表示左三角
                y<x 且 y<1-x 表示上三角
                y<x 且 y>1-x 表示右三角
                y>x 且 y>1-x 表示下三角
             */
    
            if (relativeY > relativeX) {//左和下
                if (relativeY < 1 - relativeX) {//
                    return Direction.left;
                } else {//
                    return Direction.down;
                }
            } else {//上和右
                if (relativeY < 1 - relativeX) {//
                    return Direction.up;
                } else {//
                    return Direction.right;
                }
            }
        }
    }

     

    三、运行效果

    没有点击时的效果:

    点击左键时的效果:

    点击上建时的效果:

    点击右键时的效果:

    点击下键时的效果:

    到这里,我们的自定义方向键的4个背景三角形已经做好了,而且实现了点击变色的按钮效果。

    后面我们会在这4个三角形上都画上相应的箭头,同样也有点击变色的效果哦。敬请期待o(^▽^)o

  • 相关阅读:
    LeetCode 189. Rotate Array
    LeetCode 965. Univalued Binary Tree
    LeetCode 111. Minimum Depth of Binary Tree
    LeetCode 104. Maximum Depth of Binary Tree
    Windows下MySQL的安装与配置
    LeetCode 58. Length of Last Word
    LeetCode 41. First Missing Positive
    LeetCode 283. Move Zeroes
    《蚂蚁金服11.11:支付宝和蚂蚁花呗的技术架构及实践》读后感
    删除docker下的镜像
  • 原文地址:https://www.cnblogs.com/chengyujia/p/5795771.html
Copyright © 2011-2022 走看看