检测 Canvas 个对象之间的交互

Detecting interactions between Canvas objects

在我当前的原型中,我有一个固定的矩形网格,我在 canvas 上循环绘制,还有一个红色正方形“gamePiece”,玩家可以用手指在屏幕上拖动它(下面的屏幕截图). 我的目标是让玩家方块可以与灰色方块互动,但我不确定如何检测 canvas 对象之间的互动。如何实现?

下面是我的相关代码块,但如果还有什么我可以提供帮助的,请告诉我。我不希望有人为我做这个,但如果有人能给我指出好的资源,我将不胜感激!!

代码

GamePiece(红场)

public class GamePiece implements GameObject {

    private Rect rectangle;
    private int color;

    public GamePiece(Rect rectangle, int color) {
        this.rectangle = rectangle;
        this.color = color;
    }

    @Override
    public void draw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(color);
        canvas.drawRect(rectangle, paint);
    }

    @Override
    public void update() {

    }

    public void update(Point point) {
        //ltrb
        rectangle.set(point.x - rectangle.width()/2, point.y - rectangle.height()/2, point.x + rectangle.width()/2, point.y + rectangle.height()/2);
    }
}

GameTile(单个灰色方块)

public class GameTile implements GameObject{

    private RectF rectangle;
    private int color;

    public static int tilesPerRow = 10;
    final public static int TILE_SIZE = (PolyGoneUtils.getScreenWidth() - (40 + 20 * tilesPerRow)) / tilesPerRow;

    public GameTile(RectF rectangle, int color) {
        this.rectangle = rectangle;
        this.color = color;
    }


    @Override
    public void draw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(color);
        canvas.drawRoundRect(rectangle, 10, 10, paint);
    }

    @Override
    public void update() {

    }

    @Override
    public void update(Point point) {
        rectangle.set(point.x - rectangle.width()/2, point.y - rectangle.height()/2, point.x + rectangle.width()/2, point.y + rectangle.height()/2);
    }
}

GameBoard(制作 GameTiles 的网格)

public class GameBoard extends View {


    private static final int originX = 30;
    private static final int originY = 400;
    private static final int tileSize = GameTile.TILE_SIZE;
    
    public GameBoard(Context context) {
        super(context);

    }

    
    public static void makeGameBoard(Canvas canvas) {
        
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                GameTile gameTile = new GameTile(new RectF(originX + i * tileSize + (20 * i),
                        originY + j * tileSize + (20 * j),
                        originX + (i + 1) * tileSize + (20 * i),
                        originY + (j + 1) * tileSize + (20 * j)), Color.DKGRAY);
                gameTile.draw(canvas);
            }

        //System.out.println("Squared Dimensions of the tiles are: " + tileSize);
        }
    }
}

最后这是我的 GameView

public class GameView extends SurfaceView implements SurfaceHolder.Callback {
    private MainThread thread;
    Context context;

    private GamePiece gamePiece;
    private Point piecePoint;

    public GameView(Context context) {
        super(context);
        this.context = context;

        getHolder().addCallback(this);
        thread = new MainThread(getHolder(), this);
        setFocusable(true);
        
        gamePiece = new GamePiece(new Rect(300, 300, 384, 384), Color.rgb(255, 0, 0));
        piecePoint = new Point(342, 342);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        thread = new MainThread(getHolder(), this);

        thread.setRunning(true);
        thread.start();
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        boolean retry;
        retry = true;
        while(retry) {
            try {
                thread.setRunning(false);
                thread.join();
            } catch (Exception e) {e.printStackTrace();}
            retry = false;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: //player pressing down
            case MotionEvent.ACTION_MOVE: //player moving their finger
                piecePoint.set((int)event.getX(), (int)event.getY() - 100);
        }

        return true;
        //return super.onTouchEvent(event);
    }

    public void update() {
        gamePiece.update(piecePoint);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        canvas.drawColor(Color.parseColor("#201E36"));

        GameBoard.makeGameBoard(canvas); // Drawing GameBoard Grid

        gamePiece.draw(canvas);
    }
}

根据@Mike M. 的建议,我实施了以下解决方案。我没有创建我的瓷砖并在每个循环中绘制它们,而是将其更改为我最初在 GameView 中定义我的 GameBoard 瓷砖并将它们存储到 ArrayList 的位置...

//Within GameBoard class
public static void makeGameBoard() {
    tiles = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            GameTile gameTile = new GameTile(new RectF(originX + i * tileSize + (20 * i),
                    originY + j * tileSize + (20 * j),
                    originX + (i + 1) * tileSize + (20 * i),
                    originY + (j + 1) * tileSize + (20 * j)), Color.DKGRAY);
            tiles.add(gameTile);

        }
    }
}

然后我使用一个单独的方法从这个 ArrayList 中绘制它们...

//Within GameBoard class
public static void drawGameBoard(Canvas canvas) {
    for (int i = 0; i < tiles.size(); i++) {
        tiles.get(i).draw(canvas);
    }
}

最后,为了处理棋盘的 gameTiles 和玩家的 gamePiece 之间的交互,我只需使用 RectF 的内置 .contains 方法检查 gamePiece 中心的 Point 是否在图块 ArrayList 中的任何 gameBoard 的 gameTiles 内。

//Within GameBoard class
public static void doesTileInteract(Point gamePiecePoint) {
    for (int i = 0; i < tiles.size(); i++) {
        if (tiles.get(i).getRectangle().contains(gamePiecePoint.x, gamePiecePoint.y)) {
            System.out.println("The tiles are interacting!");
        }
    }
}

在onTouchEvent方法中调用。

//Within GameView class
@Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: //player pressing down
            wasClicked = gamePiece.getRectangle().contains((int) event.getX(), (int) event.getY());

        case MotionEvent.ACTION_MOVE: //player moving their finger
            if (wasClicked) {
                gamePiecePoint.set((int) event.getX(), (int) event.getY() - 100);
            }
            GameBoard.doesTileInteract(gamePiecePoint);
    }
    return true;
    //return super.onTouchEvent(event);
}

非常感谢@Mike M. 的所有建议!!非常感谢您的帮助。