Я работаю над игрой для Android, похожей на Rush Hour / Traffic Jam / Blocked головоломки. Доска представляет собой квадрат, содержащий прямоугольные фигуры. Длинные части могут двигаться только горизонтально, а высокие могут двигаться только вертикально. Цель состоит в том, чтобы освободить красную фигуру и убрать ее с доски. Эта игра - мой второй проект по программированию на любом языке, поэтому любые советы и рекомендации будут оценены вместе с вашим ответом.
У меня есть класс для игровых фигур, который называется Pieces и который описывает их размеры и изображение на экране, дает им возможность перетаскивания, обнаруживает и обрабатывает столкновения.
Затем у меня есть класс активности GameView, который создает мой макет и создает объекты Pieces для добавления в RelativeLayout, называемый Board. Я подумал о том, чтобы сделать Совет своим собственным классом, но пока не нуждался.
Вот как выглядит моя работа:
Мой вопрос:
Большая часть этого работает отлично, за исключением моей обработки столкновений. Кажется, что он хорошо обнаруживает столкновения, но вместо того, чтобы выталкивать куски наружу друг от друга, когда происходит столкновение, он лихорадочно щелкает взад-вперед между (что, кажется, есть) местом, куда перетаскивают кусочек и где он должен быть. Это выглядит примерно так:
Еще одна странность: когда перетаскиваемая часть сталкивается с частью слева, обработка столкновения, кажется, работает отлично. Только часть сверху, снизу и справа вызывает проблемы.
Вот код столкновения:
@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));
}
Единственная проблема с этим кодом состоит в том, что он обнаруживает только столкновения между движущейся деталью и одной другой (предпочтительнее одной слева). Если есть деталь, с которой нужно столкнуться слева, а другая справа, она будет обнаруживать столкновения только с той, что слева. Я думаю, это потому, что как только он обнаруживает возможное столкновение, он обрабатывает его, не заканчивая циклически перебирая массив, содержащий все части. Как заставить его проверить наличие нескольких возможных коллизий одновременно?