java - 拖放益智游戏的碰撞问题

标签 java android drag-and-drop collision-detection

我正在开发一款类似于尖峰时刻/交通拥堵/阻塞益智游戏的 Android 游戏。棋盘是一个包含长方形棋子的正方形。长棋子只能水平移动,高棋子只能垂直移动。目标是释放红色棋子并将其移出棋盘。这个游戏只是我用任何语言进行的第二个编程项目,所以任何提示或最佳实践将不胜感激。

我有一个名为 Pieces 的游戏部件类,它描述了如何调整它们的大小并绘制到屏幕上,为它们提供拖放功能,并检测和处理碰撞。

然后我有一个名为 GameView 的 Activity 类,它创建我的布局并创建 Pieces 对象以添加到名为 Board 的 RelativeLayout。我考虑过让 Board 成为自己的类(class),但还没有必要。

这是我正在进行的工作的样子:
screen_cap1

我的问题:
除了我的碰撞处理之外,大部分工作都很好。它似乎能很好地检测到碰撞,但是当发生碰撞时,它并没有将 fragment 相互推开,而是疯狂地在 fragment 被拖动到的位置和它应该在的位置之间来回移动(看起来是什么)。它看起来像这样:
screencapgif1
另一个奇怪之处:当被拖动的棋子与其左边的棋子发生碰撞时,碰撞处理似乎完美无缺。只有上面、下面和右边的部分会导致问题。
这是碰撞代码:

    @Override
public boolean onTouchEvent(MotionEvent event){

    float eventX = event.getX();
    float eventY = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        //check if touch is on piece
        if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height)){
            initialX=x;
            initialY=y;
            break;
        }else{
            return false;
        }
    case MotionEvent.ACTION_MOVE:
        //determine if piece should move horizontally or vertically
        if(width>height){
            for (Pieces piece : aPieces) {
                //if object equals itself in array, skip to next object
                if(piece==this){
                    continue;
                }
                //if next to another piece, 
                //do not allow to move any further towards said piece
                if(eventX<x&&(x==piece.right+1)){
                    return false;
                }else if(eventX>x&&(x==piece.x-width-1)){
                    return false;
                }
                //move normally if no collision
                //if collision, do not allow to move through other piece
                if(collides(this,piece)==false){
                    x = (eventX-(width/2));
                }else if(collidesLeft(this,piece)){
                    x = piece.right+1;
                    break;
                }else if(collidesRight(this,piece)){
                    x = piece.x-width-1;
                    break;
                }
            }
            break;
        }else if(height>width){
            for (Pieces piece : aPieces) {
                if(piece==this){
                    continue;
                }else if(collides(this,piece)==false){
                    y = (eventY-(height/2));
                }else if(collidesUp(this,piece)){
                    y = piece.bottom+1;
                    break;
                }else if(collidesDown(this,piece)){
                    y = piece.y-height-1;
                    break;
                }
            }
        }
        invalidate();
        break;

    case MotionEvent.ACTION_UP:
        // end move
        if(this.moves()){
        GameView.counter++;
        }
        initialX=x;
        initialY=y;
        break;
        }
    // parse puzzle
    invalidate();
    return true;
    }

这发生在 onDraw 期间:

width = sizedBitmap.getWidth();
height = sizedBitmap.getHeight();
right = x+width;
bottom = y+height;

我的碰撞测试方法看起来像这样,每个方法都有不同的数学:

    private boolean collidesDown(Pieces piece1, Pieces piece2){
    float x1 = piece1.x;
    float y1 = piece1.y;
    float r1 = piece1.right;
    float b1 = piece1.bottom;
    float x2 = piece2.x;
    float y2 = piece2.y;
    float r2 = piece2.right;
    float b2 = piece2.bottom;

    if((y1<y2)&&(y1<b2)&&(b1>=y2)&&(b1<b2)&&((x1>=x2&&x1<=r2)||(r1>=x2&&x1<=r2))){
        return true;
    }else{
        return false;
    }
}

private boolean collides(Pieces piece1, Pieces piece2){
    if(collidesLeft(piece1,piece2)){
        return true;
    }else if(collidesRight(piece1,piece2)){
        return true;
    }else if(collidesUp(piece1,piece2)){
        return true;
    }else if(collidesDown(piece1,piece2)){
        return true;
    }else{
        return false;
    }
}

作为第二个问题,我的 x,y,right,bottom,width,height 变量应该是整数而不是像现在这样的 float 吗? 此外,即使与问题无关,也将不胜感激任何关于如何更好地实现事情的建议!在此先感谢您的帮助并解决这么长的问题!

更新:
我已经让它几乎完美地与以下代码一起工作(这不包括垂直部分的代码):

@Override
public boolean onTouchEvent(MotionEvent event){

    float eventX = event.getX();
    float eventY = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        //check if touch is on piece
        if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height)){
            initialX=x;
            initialY=y;
            break;
        }else{
            return false;
        }
    case MotionEvent.ACTION_MOVE:
        //determine if piece should move horizontally or vertically
        if(width>height){
            for (Pieces piece : aPieces) {
                //if object equals itself in array, skip to next object
                if(piece==this){
                    continue;
                }
                //check if there the possibility for a horizontal collision
                if(this.isAllignedHorizontallyWith(piece)){
                    //check for and handle collisions while moving left
                    if(this.isRightOf(piece)){
                        if(eventX>piece.right+(width/2)){
                            x = (int)(eventX-(width/2)); //move normally
                        }else{
                            x = piece.right+1;
                        }
                    }
                    //check for and handle collisions while moving right
                    if(this.isLeftOf(piece)){
                        if(eventX<piece.x-(width/2)){
                            x = (int)(eventX-(width/2));
                        }else{
                            x = piece.x-width-1;
                        }
                    }
                    break;
                }else{
                    x = (int)(eventX-(width/2));
                }

此代码的唯一问题是它仅检测移动件与另一件之间的碰撞(优先考虑左侧的一件)。如果左边有一 block 要碰撞,右边有另一 block 要碰撞,它只会检测到与左边的碰撞。我认为这是因为一旦发现可能的碰撞,它就会处理它而无需完成对包含所有 fragment 的数组的循环。我如何让它同时检查多个可能的碰撞?

最佳答案

我最好的猜测是,被拖动的部分被拖入另一部分,然后移回原处,因此不再发生碰撞,然后再次被拖入另一部分。如果在绘图后发生碰撞响应,至少这是我所期望的。

顺便说一句,下面的代码让我有些疑惑:

            //if next to another piece, 
            //do not allow to move any further towards said piece
            if(eventX<x&&(x==piece.right+1)){
                return false;
            }else if(eventX>x&&(x==piece.x-width-1)){
                return false;
            }

在 float 上检查相等性 (==) 通常是一个非常糟糕的主意,请参阅无数的“浮点精度”主题。备选方案 a) 使用整数而不是 float 。 b) 使用范围比较(>= 等)。但是不要使用 (a),微小的(时间)步骤等有很多缺点。

尝试使用与触摸检测相同的方法:

    //check if touch is on piece
    if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height))

关于java - 拖放益智游戏的碰撞问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5292323/

相关文章:

java - Android Webview 输入文件选择器代码错误

java - 我正在尝试启动应用程序,但它崩溃了

Java ExecutorService - 任务/可调用不取消/中断

android - 更改日期时间选择器对话框的标题

android - 这个脚本实际上做了什么?

Javascript拖放同一对象的多个实例

java - 批处理文件显示无法找到或加载主类

java - 我怎样才能在Hibernate中调用这种函数呢?

java - 如何告诉 Hibernate 在 CRUD 操作中有条件地忽略列

javascript - 在 Firefox 和 IE 中如何在拖动不同目标时更改光标?