9

我有一个 CustomView 和一个 Image 视图。CustomView 是一个在屏幕周围移动并从墙壁反弹的球。图像是四分之一圆,您可以在触摸时旋转一圈。我正在尝试制作我的游戏,以便当来自 CustomView 的填充像素与来自 ImageView 的填充像素交叉路径时检测到碰撞。我遇到的问题是我不知道如何检索每个视图上填充像素的位置。

这是我的 XML 代码

<com.leytontaylor.bouncyballz.AnimatedView
    android:id="@+id/anim_view"
    android:layout_height="fill_parent"
    android:layout_width="fill_parent"
    />

<ImageView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/quartCircle"
    android:layout_gravity="center_horizontal"
    android:src="@drawable/quartercircle"
    android:scaleType="matrix"/>

我的主要活动

public class MainActivity extends AppCompatActivity {

private static Bitmap imageOriginal, imageScaled;
private static Matrix matrix;

private ImageView dialer;
private int dialerHeight, dialerWidth;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // load the image only once
    if (imageOriginal == null) {
        imageOriginal = BitmapFactory.decodeResource(getResources(), R.drawable.quartercircle);
    }

    // initialize the matrix only once
    if (matrix == null) {
        matrix = new Matrix();
    } else {
        // not needed, you can also post the matrix immediately to restore the old state
        matrix.reset();
    }

    dialer = (ImageView) findViewById(R.id.quartCircle);
    dialer.setOnTouchListener(new MyOnTouchListener());
    dialer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            // method called more than once, but the values only need to be initialized one time
            if (dialerHeight == 0 || dialerWidth == 0) {
                dialerHeight = dialer.getHeight();
                dialerWidth = dialer.getWidth();

                // resize
                Matrix resize = new Matrix();
                resize.postScale((float) Math.min(dialerWidth, dialerHeight) / (float) imageOriginal.getWidth(), (float) Math.min(dialerWidth, dialerHeight) / (float) imageOriginal.getHeight());
                imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false);

                // translate to the image view's center
                float translateX = dialerWidth / 2 - imageScaled.getWidth() / 2;
                float translateY = dialerHeight / 2 - imageScaled.getHeight() / 2;
                matrix.postTranslate(translateX, translateY);

                dialer.setImageBitmap(imageScaled);
                dialer.setImageMatrix(matrix);

            }
        }
    });
 }

MyOnTouchListener 类:

private class MyOnTouchListener implements View.OnTouchListener {

    private double startAngle;

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                startAngle = getAngle(event.getX(), event.getY());
                break;

            case MotionEvent.ACTION_MOVE:
                double currentAngle = getAngle(event.getX(), event.getY());
                rotateDialer((float) (startAngle - currentAngle));
                startAngle = currentAngle;
                break;

            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }
}

private double getAngle(double xTouch, double yTouch) {
    double x = xTouch - (dialerWidth / 2d);
    double y = dialerHeight - yTouch - (dialerHeight / 2d);

    switch (getQuadrant(x, y)) {
        case 1:
            return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
        case 2:
            return 180 - Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
        case 3:
            return 180 + (-1 * Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);
        case 4:
            return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
        default:
            return 0;
    }
}

/**
 * @return The selected quadrant.
 */
private static int getQuadrant(double x, double y) {
    if (x >= 0) {
        return y >= 0 ? 1 : 4;
    } else {
        return y >= 0 ? 2 : 3;
    }
}

/**
 * Rotate the dialer.
 *
 * @param degrees The degrees, the dialer should get rotated.
 */
private void rotateDialer(float degrees) {
    matrix.postRotate(degrees, dialerWidth / 2, dialerHeight / 2);

    dialer.setImageMatrix(matrix);
}

还有我的 AnimatedView

public class AnimatedView extends ImageView {

private Context mContext;
int x = -1;
int y = -1;
private int xVelocity = 10;
private int yVelocity = 5;
private Handler h;
private final int FRAME_RATE = 60;

public AnimatedView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mContext = context;
    h = new Handler();
}

private Runnable r = new Runnable() {
    @Override
    public void run() {
        invalidate();
    }
};

protected void onDraw(Canvas c) {
    BitmapDrawable ball = (BitmapDrawable) mContext.getResources().getDrawable(R.drawable.smallerball);

    if (x<0 && y <0) {
        x = this.getWidth()/2;
        y = this.getHeight()/2;
    } else {
        x += xVelocity;
        y += yVelocity;
        if ((x > this.getWidth() - ball.getBitmap().getWidth()) || (x < 0)) {
            xVelocity = xVelocity*-1;
        }
        if ((y > this.getHeight() - ball.getBitmap().getHeight()) || (y < 0)) {
            yVelocity = yVelocity*-1;
        }
    }

    c.drawBitmap(ball.getBitmap(), x, y, null);
    h.postDelayed(r, FRAME_RATE);
}

public float getX() {
    return x;
}

public float getY() {
    return y;
}

}

我的问题是:如何从这两个视图中检索填充的像素,并将它们传递给检测碰撞的函数。

在此先感谢您的帮助!:)

4

2 回答 2

1

您可以使用标记边界坐标的点数组封装您的图像(并在移动时更新它们/根据原点计算它们),然后您将能够决定对面对象是否处于接触状态(如果任何对面数组共享同一点)

于 2017-06-29T15:54:43.300 回答
0

您确实需要定义“填充像素”。我假设你的意思是不透明的像素。找到它们的最简单方法是将整个视图转换为位图并遍历其像素。您可以将 aView转换为Bitmap这样的:

private Bitmap getBitmapFromView(View view) {
    view.buildDrawingCache();
    Bitmap returnedBitmap = Bitmap.createBitmap(view.measuredWidth,
            view.measuredHeight,
            Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(returnedBitmap);
    canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC_IN);
    Drawable drawable = view.background;
    drawable.draw(canvas);
    view.draw(canvas);
    return returnedBitmap;
}

您还需要获取视图的绝对位置:

Point getViewLocationOnScreen(View v) {
    int[] coor = new int[]{0, 0};
    v.getLocationOnScreen(coor);
    return new Point(coor[0], coor[1]);
}

然后你只需要遍历 each 的像素Bitmap,检查它们的颜色以了解它们是否被“填充”,并根据它们在位图​​中的协调和屏幕上视图的绝对位置检查它们是否重叠。

遍历位图的方法如下:

for (int x = 0; x < myBitmap.getWidth(); x++) {
    for (int y = 0; y < myBitmap.getHeight(); y++) {
        int color = myBitmap.getPixel(x, y);
    }
}

但我必须说,我认为在 UI 线程上执行这种繁重的计算并不是一个好主意。有几十种比像素完美检查更好的碰撞检测方法。这可能会非常滞后。

于 2017-07-02T10:12:50.917 回答