我正在开发一款类似于尖峰时刻/交通拥堵/封锁益智游戏的Android游戏。该板是一个包含矩形块的正方形。长件只能水平移动,而高件只能垂直移动。目的是释放红色片并将其移出板。这个游戏只是我用任何语言编写的第二个编程项目,因此任何提示或最佳实践都会与您的答案一起受到赞赏。
我有一个名为Pieces的游戏类,它描述了它们的大小和绘制方式,给它们拖放功能,并检测和处理碰撞。
然后我有一个名为GameView的活动类,它创建我的布局并创建Pieces对象以添加到名为Board的RelativeLayout。我考虑过让董事会成为自己的班级,但还不需要。
以下是我正在进行的工作:
我的问题:
除了我的碰撞处理之外,大部分工作都非常好。它似乎很好地检测到了碰撞,但是当发生碰撞时,它不是将碎片推到彼此之外,而是在碎片被拖动到的位置(应该是什么)之间来回疯狂地来回捕捉。它看起来像这样:
另一个奇怪之处:当被拖动的棋子与左边的棋子碰撞时,碰撞处理似乎完美无缺。只有上方,下方和右侧会出现问题
这是碰撞代码:
@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变量应该是int而不是像现在这样的浮点数? 此外,任何有关如何更好地实施事情的建议都将受到高度赞赏,即使与问题无关!提前感谢您的帮助和坐下这么长的问题!
更新
我已经使用以下代码几乎完美地工作了(这不包括垂直部分的代码):
@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));
}
此代码的唯一问题是它仅检测移动件与另一个之间的碰撞(优先于左侧的碰撞)。如果左侧和右侧碰撞有一块,它只会检测左侧的碰撞。我认为这是因为一旦发现可能的碰撞,它就会处理它而不会完成循环通过包含所有碎片的数组。如何让它同时检查多个可能的碰撞?
答案 0 :(得分:2)
我最好的猜测是将被拖动的棋子拖入另一块,然后向后移动,使其不再碰撞,然后再次拖入另一块。至少这是我在绘图后发生碰撞响应时的预期。
在旁注中,以下代码让我有点疑惑:
//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)使用int而不是浮点数。 b)使用远程比较(>=
等)。不要使用(a)但是,微小(时间)步骤等有许多缺点。
尝试使用与触摸检测相同的方法:
//check if touch is on piece
if (eventX > x && eventX < (x+width) && eventY > y && eventY < (y+height))
答案 1 :(得分:1)
你应该能够更简单地做到这一点:)
请注意,我对如何存储移动方向做了一些假设,您可能需要根据自己的喜好进行调整。
另请注意,我将piece1视为我们关注的移动部件,而piece2仅仅作为它碰撞的对象。所以piece1重新定位,piece2不重新定位。
// 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 )
我在这里做的如下:
你可以将这个简单的例程应用于两个部分的每个可能的组合,它们将不再渗透。
我希望这会帮助你!
答案 2 :(得分:0)
回复你的第二个问题:
此代码的唯一问题是它仅检测移动件与另一个之间的碰撞(优先于左侧的碰撞)。如果有一块要在左边碰撞而另一块在右边碰撞,它只会检测到与左边碰撞的碎片。
循环中有一个break语句 - 特别是在 left 碰撞检查中。 ;)
答案 3 :(得分:0)
我做了一些改动,到目前为止,它已经完美地工作了。这是我的新代码:
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
continue;
}else{
x = piece.right+1;
}
}else if(this.isLeftOf(piece)){ //check for and handle collisions while moving right
if(eventX<piece.x-(width/2)){
x = (int)(eventX-(width/2));
continue;
}else{
x = piece.x-width-1;
}
}else{
continue;
}
break;
}else{
x = (int)(eventX-(width/2));
}
}
}
if(height>width){
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 vertical collision
if(this.isAllignedVerticallyWith(piece)){
//check for and handle collisions while moving up
if(this.isBelow(piece)){
if(eventY>piece.bottom+(height/2)){
y = (int)(eventY-(height/2)); //move normally
continue;
}else{
y = piece.bottom+1;
}
}else if(this.isAbove(piece)){ //check for and handle collisions while moving down
if(eventY<piece.y-(height/2)){
y = (int)(eventY-(height/2));
continue;
}else{
y = piece.y-height-1;
}
}else{
continue;
}
break;
}else{
y = (int)(eventY-(height/2));
}
}
}
invalidate();
break;
这些是我使用的方法:
private boolean isLeftOf(Pieces piece) {
int r1 = this.right;
int x2 = piece.initialX;
boolean bool = false;
if (r1<=x2){
for(Pieces piece2: aPieces){
if (piece2==piece || piece2==this){
continue;
}
if (this.isAllignedHorizontallyWith(piece2) && r1<=piece2.initialX){
if (piece.x>piece2.x){
bool = false;
break;
}else{
bool = true;
continue;
}
}else{
bool = true;
}
}
}else{
bool = false;
}
return bool;
}
private boolean isRightOf(Pieces piece) {
//True means that "this" is right of "piece" and "piece" is farther right than other possible pieces
int x1 = this.initialX;
int r2 = piece.right;
boolean bool = false;
if (x1>=r2){
for(Pieces piece2: aPieces){
if (piece2==piece || piece2==this){
continue;
}
if (this.isAllignedHorizontallyWith(piece2) && x1>=piece2.right){
if (piece.x<piece2.x){
bool = false;
break;
}else{
bool = true;
continue;
}
}else{
bool = true;
}
}
}else{
bool = false;
}
return bool;
}
private boolean isBelow(Pieces piece){
int y1 = this.initialY;
int b2 = piece.bottom;
boolean bool = false;
if (y1>=b2){
for(Pieces piece2: aPieces){
if (piece2==piece || piece2==this){
continue;
}
if (this.isAllignedVerticallyWith(piece2) && y1>=piece2.bottom){
if (piece.y<piece2.y){
bool = false;
break;
}else{
bool = true;
continue;
}
}else{
bool = true;
}
}
}else{
bool = false;
}
return bool;
}
private boolean isAbove(Pieces piece){
int y2 = piece.initialY;
int b1 = this.bottom;
boolean bool = false;
if (b1<=y2){
for(Pieces piece2: aPieces){
if (piece2==piece || piece2==this){
continue;
}
if (this.isAllignedVerticallyWith(piece2) && b1<=piece2.y){
if (piece.y>piece2.y){
bool = false;
break;
}else{
bool = true;
continue;
}
}else{
bool = true;
}
}
}else{
bool = false;
}
return bool;
}
private boolean isAllignedHorizontallyWith(Pieces piece) {
int y1 = this.y;
int b1 = this.bottom;
int y2 = piece.y;
int b2 = piece.bottom;
if((y1>=y2&&y1<=b2)||(b1>=y2&&b1<=b2)){
return true;
}else{
return false;
}
}
private boolean isAllignedVerticallyWith(Pieces piece) {
int x1 = this.x;
int r1 = this.right;
int x2 = piece.x;
int r2 = piece.right;
if((x1>=x2&&x1<=r2)||(r1>=x2&&r1<=r2)){
return true;
}else{
return false;
}
}
这可以更好地评论,可能做得更简单,但我将它留在这里作为参考。
答案 4 :(得分:0)
没有什么可以获得你的imageview s Left,right,top,bottom, and intersect with current x and y and find this solution more about this go to this link it
s也帮助我跳到你在这个链接上得到正确的答案
/技术/游戏的编程/碰撞检测算法-r754" &GT; HTTP://www.gamedev.net/page/resources//technical/game-programming/collision-detection-algorithm-r754