检测 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. 的所有建议!!非常感谢您的帮助。
在我当前的原型中,我有一个固定的矩形网格,我在 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. 的所有建议!!非常感谢您的帮助。