Skip to content
Advertisement

Detecting interactions between Canvas objects

In my current prototype I have a fixed grid of rectangles I draw on the canvas in a loop, and a red square “gamePiece” which can be dragged around the screen by a player’s finger (screenshot below). My goal is to make it so that the player square can interact with the grey squares, but I’m not sure how to detect interactions between canvas objects. How can this be accomplished?

The relevant chunks of my code are below, but please let me know if there is anything else I can provide to help. I don’t expect anyone to make this for me, but if someone could point me towards good resources I would appreciate it a lot!!

enter image description here

Code

GamePiece (Red Square)

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 (Individual Gray Squares)

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 (makes the grid of 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);
        }
    }
}

And Finally here is my 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);
    }
}

Advertisement

Answer

Following @Mike M.’s suggestions I have implemented the following solution. Instead of creating my tiles and drawing them every loop, I have changed it to where I define my GameBoard tiles initially in GameView and store them to an 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);

        }
    }
}

I then use a separate method to draw them from this ArrayList in draw…

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

Finally, to handle the interactions between the board’s gameTiles and the player’s gamePiece I simply check if the Point at the center of the gamePiece is within any of the gameBoard’s gameTiles in the tiles ArrayList with RectF’s built in .contains method.

//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!");
        }
    }
}

Which is called in the onTouchEvent method.

//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);
}

Thanks so much to @Mike M. for all his suggestions!! I really appreciate the help.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement