首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >拖拽式拼图游戏中的碰撞问题

拖拽式拼图游戏中的碰撞问题
EN

Stack Overflow用户
提问于 2011-03-13 20:55:36
回答 5查看 1.8K关注 0票数 3

我正在开发一个类似于高峰时间/交通堵塞/阻塞益智游戏的Android游戏。板是一个正方形,包含长方形的部分。长的部分只能水平移动,高的部分只能垂直移动。目标是释放红色的部分,并将其从板上移出。这个游戏只是我在任何语言中的第二个编程项目,所以任何提示或最佳实践都将与您的回答一起感谢。

我有一个名为gives的游戏片段类,它描述了它们的大小和绘制到屏幕上的方式,提供了拖放功能,并检测和处理冲突。

然后,我有一个名为GameView的活动类,它创建我的布局,并创建要添加到名为RelativeLayout的RelativeLayout中的碎片对象。我已经考虑过让董事会成为它自己的班级,但还没有必要。

以下是我正在进行的工作:

我的问题:

除了我的碰撞处理之外,大部分的操作都很好。它似乎能很好地探测碰撞,但当发生碰撞时,它不会把碎片推到彼此的外面,而是疯狂地在物体被拖到的地方和它应该在的位置之间来回切换。看起来是这样的:

另一个奇怪之处是:当被拖动的物体与左边的一个物体发生碰撞时,碰撞处理似乎工作得很完美。只有上面、下面和右边的部分会引起问题。

以下是碰撞代码:

代码语言:javascript
运行
复制
    @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期间发生的:

代码语言:javascript
运行
复制
width = sizedBitmap.getWidth();
height = sizedBitmap.getHeight();
right = x+width;
bottom = y+height;

我的碰撞测试方法如下所示,每种方法都有不同的数学计算:

代码语言:javascript
运行
复制
    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,对,底部,宽度,高度变量应该是整数,而不是像现在这样的浮点数吗?此外,任何关于如何更好地执行事情的建议都会受到极大的赞赏,即使与问题无关!提前感谢你的帮助,感谢你坐着回答这么长的问题!

更新:

下面的代码(这不包括垂直部分的代码)使它几乎完美地工作了:

代码语言:javascript
运行
复制
@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));
                }

这段代码的唯一问题是,它只检测移动部件与另一个(优先于左侧)之间的冲突。如果有一块在左边与另一块在右边碰撞,它只会检测到与左边的那块碰撞。我认为这是因为一旦它发现可能的碰撞,它处理它,而不完成循环通过数组保存所有的部分。如何让它同时检查多个可能的碰撞?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-03-13 22:12:01

我最好的猜测是,被拖的碎片被拖到另一块,然后移回来,这样它就不再碰撞,然后再被拖入另一块。至少这是我所期望的,如果在绘制之后会发生碰撞响应。

顺便提一下,下面的代码让我有点好奇:

代码语言:javascript
运行
复制
            //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;
            }

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

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

代码语言:javascript
运行
复制
    //check if touch is on piece
    if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height))
票数 1
EN

Stack Overflow用户

发布于 2011-03-14 14:46:48

您应该能够更简单地做到这一点:)

注意,我对你如何存储运动方向做了一些假设,你可能需要根据你的喜好进行调整。

还请注意,我将piece1视为我们所关注的移动部件,而piece2则简单地将其视为与其碰撞的对象。所以piece1被重新定位,piece2没有。

代码语言:javascript
运行
复制
// Horizontal:
if( piece1.isMovingLeft )
    piece1.x += Math.max( 0, piece2.right - piece1.x );
else if( piece1.isMovingRight )
    piece1.x -= Math.max( 0, piece1.right - piece2.x );

// Vertical:
if( piece1.isMovingUp )
    piece1.y -= Math.max( 0, piece2.bottom - piece1.y );
else if( piece1.isMovingDown )
    piece1.y += Math.max( 0, piece1.bottom - piece2.y )

我在此所做的工作如下:

  • ,如果该部件向某个方向移动,我们将其向相反的方向移动(一点点),以补偿(可能的)碰撞。我们需要用重叠像素的数量将其移回,例如,
  • ,当向左移动时,重叠量是第二个对象的右侧减去第一个对象的左侧。(负的意思是没有重叠)
  • Math.max( 0,重叠)确保所述负值变为0,即没有碰撞导致不发生任何运动方向的补偿,从而有效地将piece1从piece2中剔除。(然后您可以选择反转其移动方向或以任何进一步的方式作出响应。)

你可以将这个简单的例程应用于每一个可能的两块组合,它们将不再穿透。

希望这能帮到你!

票数 1
EN

Stack Overflow用户

发布于 2011-03-16 11:51:22

在回答你的第二个问题时:

这段代码的唯一问题是它只检测到移动的部分和另一个之间的冲突(优先于左边的一个)。如果有一块在左边与另一块在右边碰撞,它只会检测到与左边的那块碰撞。

循环中有一个中断语句--特别是在左碰撞检查中。;)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5292323

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档