Из-за этого после вращения часть фигуры может оказаться за пределами игрового поля или «залезть» на другую фигуру, уже стоящую на поле.
Кроме того, сам алгоритм вращения неординарный, и я не смог найти какой-то закономерности в изменениях координат при вращении. Можно было бы еще посидеть и подумать, но фигур не так много и вариантов позиций у каждой максимум 4.
Поэтому я решил сделать не очень красиво. Просто вручную описать все возможные положения фигур и порядок их изменения.
Внимание! Этот код может повлиять на вашу психику.
// ...
setRotatedCoords: function() {
var newCoords = [];
switch(this.type) {
// Проверяем тип фигуры
case 'I':
switch(this.rotatePosition) {
// и, в зависимости от текущего положения фигуры, изменяем координаты
case 0:
newCoords.push([
[this.coords[2][0][0], this.coords[2][0][1]-1],
[this.coords[2][0][0], this.coords[2][0][1]],
[this.coords[2][0][0], this.coords[2][0][1]+1],
[this.coords[2][0][0], this.coords[2][0][1]+2]
]);
this.coords = newCoords;
this.rotatePosition = 1;
break;
case 1:
newCoords.push([
[this.coords[0][1][0]-2, this.coords[0][1][1]]
],[
[this.coords[0][1][0]-1, this.coords[0][1][1]]
],[
[this.coords[0][1][0], this.coords[0][1][1]]
],[
[this.coords[0][1][0]+1, this.coords[0][1][1]]
]);
this.coords = newCoords;
this.rotatePosition = 0;
break;
}
break;
case 'S':
switch(this.rotatePosition) {
case 0:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]-1]
],[
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][1][0], this.coords[1][1][1]]
],[
[this.coords[1][1][0]+1, this.coords[1][1][1]]
]);
this.coords = newCoords;
this.rotatePosition = 1;
break;
case 1:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]+1],
[this.coords[0][0][0], this.coords[0][0][1]+2]
],[
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][1][0], this.coords[1][1][1]]
]);
this.coords = newCoords;
this.rotatePosition = 0;
break;
}
break;
case 'Z':
switch(this.rotatePosition) {
case 0:
newCoords.push([
[this.coords[0][1][0], this.coords[0][1][1]+1]
],[
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][1][0], this.coords[1][1][1]]
],[
[this.coords[1][0][0]+1, this.coords[1][0][1]]
]);
this.coords = newCoords;
this.rotatePosition = 1;
break;
case 1:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]-2],
[this.coords[0][0][0], this.coords[0][0][1]-1]
],[
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][1][0], this.coords[1][1][1]]
]);
this.coords = newCoords;
this.rotatePosition = 0;
break;
}
break;
case 'T':
switch(this.rotatePosition) {
case 0:
newCoords.push([
[this.coords[0][1][0]-1, this.coords[0][1][1]]
],[
[this.coords[0][0][0], this.coords[0][0][1]],
[this.coords[0][1][0], this.coords[0][1][1]]
],[
[this.coords[1][0][0], this.coords[1][0][1]]
]);
this.coords = newCoords;
this.rotatePosition = 1;
break;
case 1:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]]
],[
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][1][0], this.coords[1][1][1]],
[this.coords[1][1][0], this.coords[1][1][1]+1]
]);
this.coords = newCoords;
this.rotatePosition = 2;
break;
case 2:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]]
],[
[this.coords[1][1][0], this.coords[1][1][1]],
[this.coords[1][2][0], this.coords[1][2][1]]
],[
[this.coords[1][1][0]+1, this.coords[1][1][1]]
]);
this.coords = newCoords;
this.rotatePosition = 3;
break;
case 3:
newCoords.push([
[this.coords[1][0][0], this.coords[0][0][1]-1],
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][1][0], this.coords[1][1][1]]
],[
[this.coords[2][0][0], this.coords[2][0][1]]
]);
this.coords = newCoords;
this.rotatePosition = 0;
break;
}
break;
case 'J':
switch(this.rotatePosition) {
case 0:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]-1]
],[
[this.coords[1][0][0], this.coords[1][0][1]-1],
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][0][0], this.coords[1][0][1]+1]
]);
this.coords = newCoords;
this.rotatePosition = 1;
break;
case 1:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]],
[this.coords[0][0][0], this.coords[0][0][1]+1]
],[
[this.coords[1][0][0], this.coords[1][0][1]]
],[
[this.coords[1][0][0]+1, this.coords[1][0][1]]
]);
this.coords = newCoords;
this.rotatePosition = 2;
break;
case 2:
newCoords.push([
[this.coords[1][0][0], this.coords[1][0][1]-1],
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][0][0], this.coords[1][0][1]+1]
],[
[this.coords[1][0][0]+1, this.coords[1][0][1]+1]
]);
this.coords = newCoords;
this.rotatePosition = 3;
break;
case 3:
newCoords.push([
[this.coords[0][1][0]-1, this.coords[0][1][1]+1]
],[
[this.coords[0][1][0], this.coords[0][1][1]+1]
],[
[this.coords[1][0][0], this.coords[1][0][1]-1],
[this.coords[1][0][0], this.coords[1][0][1]]
]);
this.coords = newCoords;
this.rotatePosition = 0;
break;
}
break;
case 'L':
switch(this.rotatePosition) {
case 0:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]+1]
],[
[this.coords[1][0][0], this.coords[1][0][1]-1],
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][0][0], this.coords[1][0][1]+1]
]);
this.coords = newCoords;
this.rotatePosition = 1;
break;
case 1:
newCoords.push([
[this.coords[0][0][0], this.coords[0][0][1]-1],
[this.coords[0][0][0], this.coords[0][0][1]]
],[
[this.coords[1][0][0], this.coords[1][0][1]+2]
],[
[this.coords[1][0][0]+1, this.coords[1][0][1]+2]
]);
this.coords = newCoords;
this.rotatePosition = 2;
break;
case 2:
newCoords.push([
[this.coords[1][0][0], this.coords[1][0][1]+1],
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][0][0], this.coords[1][0][1]-1]
],[
[this.coords[1][0][0]+1, this.coords[1][0][1]-1]
]);
this.coords = newCoords;
this.rotatePosition = 3;
break;
case 3:
newCoords.push([
[this.coords[0][1][0]-1, this.coords[0][1][1]-1]
],[
[this.coords[0][1][0], this.coords[0][1][1]-1]
],[
[this.coords[1][0][0], this.coords[1][0][1]],
[this.coords[1][0][0], this.coords[1][0][1]+1]
]);
this.coords = newCoords;
this.rotatePosition = 0;
break;
}
break;
}
},
//...При создании фигуры будем не только выбирать тип фигуры, но и задавать случайным образом поворот:// ...
getRandomFigure: function() {
var keys = Object.keys(Tetris.config.figureTypes);
var randKey = Math.floor(Math.random() * keys.length);
// Запомним тип фигуры, чтобы потом знать, по какому алгоритму поворачивать фигуру
Tetris.figure.type = keys[randKey];
this.coords = Tetris.config.figureTypes[keys[randKey]]();
// Выберем случайное количество поворотов
var rotatePosition = Math.floor(Math.random() * 4);
// и вращаем, вращаем, вращаем
if (rotatePosition) {
for (var i = 0; i < rotatePosition; i++) {
this.setRotatedCoords();
}
}
console.log(rotatePosition);
},
// ...Не забудем обнулять позицию поворота при уничтожении фигуры// ...
destroy: function() {
this.coords = [];
this.rotatePosition = 0;
},
// ...Добавим вызов метода при нажатии кнопки «Вверх»// ...
window.onkeydown = function (event) {
var direction = '';
if (event.keyCode == 39) {
direction = 'right';
} else if(event.keyCode == 37) {
direction = 'left';
}
if (direction) {
Tetris.figure.sideStepStart(direction);
} else if(event.keyCode == 40) {
Tetris.setSpeed(30);
}
if (event.keyCode == 38) {
Tetris.figure.rotate();
}
}
// ...Теперь в методе rotate пропишем вызов вращения и различные проверки// ...
figure: {
// ...
create: function() {
// В методе getRandomFigure уже прописана установка координат, поэтому просто вызываем
this.getRandomFigure();
},
rotatePosition: 0,
rotate: function() {
// Если кнопку нажали до создания фигуры, ничего не делаем
if (this.coords.length == 0) {
return false;
}
// Заставляем фигуру совершить поворот
this.setRotatedCoords();
// Проверяем - не вылезла ли фигура за пределы поля
Tetris.each(this.coords, function(i,j){
var figureRow = Tetris.figure.coords[i][j][0];
var figureCol = Tetris.figure.coords[i][j][1];
// Если вылезла слева, будем двигать фигуру вправо
if (figureCol < 0) {
Tetris.figure.needStepSide = 'right';
}
// Если справа - влево
if (figureCol >= Tetris.pitch.width) {
Tetris.figure.needStepSide = 'left';
}
});
// Если мы определили, что надо бы подвинуть фигуру, делаем это
if (this.needStepSide) {
this.sideStep(this.needStepSide);
// обнуляем флаг
this.needStepSide = false;
}
// Проверяем, не налезла ли фигура на другие фигуры и не провалилась ли она под пол
if (this.touched()) {
// Если да, то откатываем поворот
this.rotateRollback();
return false;
}
// Если всё ОК, рисуем новое положение фигуры
Tetris.draw();
},
needStepSide: false,
// Возможных позиций у фигуры 4, поэтому, чтобы вернуться к предыдущему
// состоянию, нужно повернуться еще 3 раза
rotateRollback: function() {
this.setRotatedCoords();
this.setRotatedCoords();
this.setRotatedCoords();
},
// ...
},
// ...Теперь в тетрис можно уже и поиграть: http://jsfiddle.net/ilyautkin/aavju3jd/42/
Объектная
Я теперь понимаю, почему гигабайты требуются там, где раньше хватало килобайт.
Ну, как нет закономерности во вращении?
Возьмем для простоты квадрат три на три (четыре нужно только для палок и добавляется элементарно)
_____Y
X___44__45__46 ________ O
____54__55__56 _____ O O О
____64__65__66
Назначаем приказным порядком один квадратик в фигурке центральным (вокруг него и будем вращать)
пусть это будет точка с координатами 55
теперь вычтем ее коорд. из коорд. остальных точек. Это не обычное вычитание, а вычитание поразрядно, что в общем тоже элементарно реализуется (причем это все только для наглядности)
Получим такую матрицу
-1 -1 ___ -1 0 ___ {-1 1}
0 -1 ___ 0 0 ___ (0 1)
1 -1 ___ 1 0 ___ 1 1
Для перемещения точки ( 0: 1) (Y: X ) при повороте на 90 градусов в точку ( -1: 0) (Ynext: Xnext)против часовой стрелки выводится простейшая формула
if (Y == 0) {Xnext = 0; Ynext = -X} else {Xnext = Y; Ynext = 0}
для точки {-1 1} будет такая же формула, но чуть с другими параметрами.
ВСЁ! Мы умеем врашать фигуры 3 *3.
Для палок используется третья формула, аналогичная предыдущим.
Итого три строчки кода. И одна строчка ДО, что бы отделить нужные точки для нужных формул (ну там все просто — переход по условию)
Зачем ты столько нагородил???
PS ecли мы для интереса построим графики изменения X и Y от поворота, то получим пилу для точки ( 0 1) и меандр для точки{-1 1}. По сути это разложение в ряд синусоиды вращения. А графики — гармоники:)
Ну как неординарный алгоритм?!
Очень даже ординарный.
Как раз вчера дописал функционирующую программку тетриса, рабочий блок кода на джаве для вращения. Сильно за
стиль не ругайте, я не погромист.
int Y_temp = Y_current-Y_central;
int X_temp = X_current-X_central;
int sWitch = Math.abs(Y_temp)+Math.abs(X_temp);
if ((Math.abs(Y_temp)|Math.abs(X_temp))==2){sWitch=3;}
switch (sWitch)
{
case 1:
if (Y_temp == 0) {Xnext = 0; Ynext = -X_temp;} else {Xnext = Y_temp; Ynext = 0;}
break;
case 2:
if (Y_temp == -1 & X_temp == 1) {Ynext = -1; Xnext = -1;}
if (Y_temp == -1 & X_temp == -1) {Ynext = 1; Xnext = -1;}
if (Y_temp == 1 & X_temp == -1) {Ynext = 1; Xnext = 1;}
if (Y_temp == 1 & X_temp == 1) {Ynext = -1; Xnext = 1;}
break;
case 3:
if (Y_temp == 0) {Xnext = 0; Ynext = -X_temp;} else {Xnext = Y_temp; Ynext = 0;}
break;
}
Вращает все фигуры в том числе и палки. Ну и это все завернуто в цикл FOR для трех обсчитываемых точек (четвертая центральная — неподвижна). Для точки {-1;1} (case 2:) не нашел более короткого алгоритма, зато для крайней точки палки ОООО (case 3:) он тоже в одну строчку.Если у кого получится короче, выкладывайте.
int Y_temp = Y_current-Y_central;
int X_temp = X_current-X_central;
int sWitch = Math.abs(Y_temp)+Math.abs(X_temp);
if ((Math.abs(Y_temp)|Math.abs(X_temp))==2){sWitch=1;}
switch (sWitch)
{
case 1:
if (Y_temp == 0) {Xnext = 0; Ynext = -X_temp;} else {Xnext = Y_temp; Ynext = 0;}
break;
case 2:
if (Y_temp == -1 & X_temp == 1) {Ynext = -1; Xnext = -1;}
if (Y_temp == -1 & X_temp == -1) {Ynext = 1; Xnext = -1;}
if (Y_temp == 1 & X_temp == -1) {Ynext = 1; Xnext = 1;}
if (Y_temp == 1 & X_temp == 1) {Ynext = -1; Xnext = 1;}
}
Ynext= Ynext + Y_central;
Xnext= Xnext + X_central;
Илья, подскажите откуда newCoords.push, появляется 2, и как образуются,
эти данные в массиве.Может есть литература на эту тему?