前言

众所周知,Region是android graphics一族中比较低调的东西类,首要原因仍是在磕碰检测方面存在一些不足,乃至能够说成事不足败事有余,以至于难以用于2D游戏开发。

用法

既然这么失利的东西为什么要介绍呢,首要咱们介绍一下它能成事的部份,以及正确的用法。

  • Region类能成事的部份首要仍是Op布尔操作和矩阵操作,可是这个似乎又和Path的作用重合,别的一部分contain包含关系判别,contain能准确的判别点和矩形是不是被包含了,可是其他形状那就没办法了。
  • 成事不足败事有余的部份,是quickXXX 快速检测办法,返回值true-能保证物体没有磕碰,但false无法保证是不是现已磕碰了,换句话说true是100%没磕碰,可是false还需求你自己进一步承认,不过这点能够作为削减判别的优化办法,但不是判定办法。

学习的意义
关于一些粒子,咱们不太关注巨细,这个时分是能够利用中心点去检测的,别的quickXXX其实用途不大,不过能够削减一部分代码,可是咱们仍然还需求了解它的用法。

非Path用法

关于非Path用法,Region仍是适当简略的,直接运用set办法即可

mainRegion.set((int) -radius, (int) -radius, (int) radius, (int) radius);

Path办法

这个用法比较奇怪,需求2个参数,最终一个是Region类,弄不好便是鸡生蛋蛋生鸡一样令人利诱,第二个能够看作被裁剪的区域,如下操作,求并集区域。不过话说回来,这个意义在哪里?

circlePath.reset();
circlePath.addCircle(x- width/2f,y - height/2f,10, Path.Direction.CCW);
circleRegion.setPath(circlePath,mainRegion);

小试一下

完成开头的图片效果

定义一些变量

 private float x; //x事件坐标
 private float y; //y事件坐标
 //所以形状
 Path[] objectPaths = new Path[5];
 //形状区域检测
 Region objectRegion = new Region();
 //小圆球区域
 Region circleRegion = new Region();
//小圆
 Path circlePath = new Path();
 //制作区域
 Region mainRegion = new Region();

构建物体

三角形、圆等物体

for (int i = 0; i < objectPaths.length; i++) {
    Path path = objectPaths[i];
    if (path == null) {
        path = new Path();
        objectPaths[i] = path;
    } else {
        path.reset();
    }
}
Path path = objectPaths[0];
path.moveTo(radius / 2, -radius / 2);
path.lineTo(0, -radius);
path.lineTo(radius / 2, -radius);
path.close();
path = objectPaths[1];
path.moveTo(-radius / 2, radius / 2);
path.lineTo(-radius / 2 - 100, radius / 2);
path.arcTo(-radius / 2 - 100, radius / 2, -radius / 2, radius / 2 + 100, 0, 180, false);
path.lineTo(-radius / 2, radius / 2);
path.close();
path = objectPaths[2];
path.addCircle(-radius + 200f, -radius + 100f, 50f, Path.Direction.CCW);
path = objectPaths[3];
path.addRoundRect(-radius / 2, -radius / 2, -radius / 2 + 20, 0, 10, 10, Path.Direction.CCW);
path = objectPaths[4];
path.addRect(120, 120, 200, 200, Path.Direction.CCW);

区域检测

检测是否发生了磕碰,准确度不高,但还能凑合

circlePath.reset();
circlePath.addCircle(x- width/2f,y - height/2f,10, Path.Direction.CCW);
circleRegion.setPath(circlePath,mainRegion);
mCommonPaint.setColor(Color.CYAN);
for (int i = 0; i < objectPaths.length; i++) {
    objectRegion.setPath(objectPaths[i],mainRegion);
    if(!objectRegion.quickReject(circleRegion)){
        Log.d("RegionView"," 可能发生了磕碰");
        mCommonPaint.setColor(Color.YELLOW);
    }else{
        mCommonPaint.setColor(Color.CYAN);
    }
    canvas.drawPath(objectPaths[i], mCommonPaint);
}

总结

到这儿结束了,关于Region类,咱们其实最有用的仍是contain类办法,contain(x,y)准确度很高,便于咱们检测粒子是不是在几何内部,本篇没有涉及到,可是有些制作地图类的运用会运用到这个,首要原因是地图犬牙交错,不是矩形也不是圆形,乃至还有飞地,因此运用containXXX是最好的方案之一。

悉数代码

public class RegionView extends View {
    private final DisplayMetrics mDM;
    private TextPaint mCommonPaint;
    public RegionView(Context context) {
        this(context, null);
    }
    public RegionView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDM = getResources().getDisplayMetrics();
        initPaint();
        setClickable(true); //触发hotspot
    }
    private void initPaint() {
        //否则提供给外部纹理制作
        mCommonPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        mCommonPaint.setAntiAlias(true);
        mCommonPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mCommonPaint.setStrokeCap(Paint.Cap.ROUND);
        mCommonPaint.setFilterBitmap(true);
        mCommonPaint.setDither(true);
        mCommonPaint.setStrokeWidth(dp2px(20));
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        if (widthMode != MeasureSpec.EXACTLY) {
            widthSize = mDM.widthPixels / 2;
        }
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            heightSize = widthSize / 2;
        }
        setMeasuredDimension(widthSize, heightSize);
    }
    private float x;
    private float y;
    //所以形状
    Path[] objectPaths = new Path[5];
    //形状区域检测
    Region objectRegion = new Region();
    //小圆球区域
    Region circleRegion = new Region();
   //小圆
    Path circlePath = new Path();
    //制作区域
    Region mainRegion = new Region();
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        if (width < 1 || height < 1) {
            return;
        }
        int save = canvas.save();
        canvas.translate(width / 2f, height / 2f);
        float radius = Math.min(width / 2f, height / 2f);
        mainRegion.set((int) -radius, (int) -radius, (int) radius, (int) radius);
        for (int i = 0; i < objectPaths.length; i++) {
            Path path = objectPaths[i];
            if (path == null) {
                path = new Path();
                objectPaths[i] = path;
            } else {
                path.reset();
            }
        }
        Path path = objectPaths[0];
        path.moveTo(radius / 2, -radius / 2);
        path.lineTo(0, -radius);
        path.lineTo(radius / 2, -radius);
        path.close();
        path = objectPaths[1];
        path.moveTo(-radius / 2, radius / 2);
        path.lineTo(-radius / 2 - 100, radius / 2);
        path.arcTo(-radius / 2 - 100, radius / 2, -radius / 2, radius / 2 + 100, 0, 180, false);
        path.lineTo(-radius / 2, radius / 2);
        path.close();
        path = objectPaths[2];
        path.addCircle(-radius + 200f, -radius + 100f, 50f, Path.Direction.CCW);
        path = objectPaths[3];
        path.addRoundRect(-radius / 2, -radius / 2, -radius / 2 + 20, 0, 10, 10, Path.Direction.CCW);
        path = objectPaths[4];
        path.addRect(120, 120, 200, 200, Path.Direction.CCW);
        circlePath.reset();
        circlePath.addCircle(x- width/2f,y - height/2f,10, Path.Direction.CCW);
        circleRegion.setPath(circlePath,mainRegion);
        mCommonPaint.setColor(Color.CYAN);
        for (int i = 0; i < objectPaths.length; i++) {
            objectRegion.setPath(objectPaths[i],mainRegion);
            if(!objectRegion.quickReject(circleRegion)){
                Log.d("RegionView"," 可能发生了磕碰");
                mCommonPaint.setColor(Color.YELLOW);
            }else{
                mCommonPaint.setColor(Color.CYAN);
            }
            canvas.drawPath(objectPaths[i], mCommonPaint);
        }
        mCommonPaint.setColor(Color.WHITE);
        canvas.drawPath(circlePath,mCommonPaint);
        canvas.restoreToCount(save);
    }
    @Override
    public void dispatchDrawableHotspotChanged(float x, float y) {
        super.dispatchDrawableHotspotChanged(x, y);
        this.x = x;
        this.y = y;
        postInvalidate();
    }
    @Override
    protected void dispatchSetPressed(boolean pressed) {
        super.dispatchSetPressed(pressed);
        postInvalidate();
    }
    public float dp2px(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mDM);
    }
    public static int argb(float red, float green, float blue) {
        return ((int) (1 * 255.0f + 0.5f) << 24) |
                ((int) (red * 255.0f + 0.5f) << 16) |
                ((int) (green * 255.0f + 0.5f) << 8) |
                (int) (blue * 255.0f + 0.5f);
    }
}