Ранее я опубликовал урок о том, как создать игру пятнашки на Flash. Чуть позже мы портировали игру на Андроид сделав сборку с помощью Adobe Air и переписав управление под мультитач.
Теперь попробуем перевести игру рельсы HTML5. Использовать для будем исключительно элемент canvas (без CSS).
Самое главное отличие от flash-версии конечно будет способ отображения графической составляющей. Примитивная графика в нашей игре может быть программно сгенерирована прямо налету. Поэтому все элементы будем рисовать прямо на канвасе.
И так, приступим. Элементу <canvas> я задал id="map". Логика игры полностью повторяет логику flash-версии и просто переписана на Javascript.
Вот, что в итоге у нас получилось:
Теперь попробуем перевести игру рельсы HTML5. Использовать для будем исключительно элемент canvas (без CSS).
Самое главное отличие от flash-версии конечно будет способ отображения графической составляющей. Примитивная графика в нашей игре может быть программно сгенерирована прямо налету. Поэтому все элементы будем рисовать прямо на канвасе.
И так, приступим. Элементу <canvas> я задал id="map". Логика игры полностью повторяет логику flash-версии и просто переписана на Javascript.
window.onload = init;
var map;
var ctxMap;
var gameWidth=288;
var gameHeight=400;
var matrix = [[],[],[],[]] ;
var checkMatrix = [[1, 2, 3, 4 ],
[5, 6, 7, 8 ],
[9, 10, 11, 12],
[13, 14, 15, 0 ] ] ;
var randomMas=[];
var countMc;
var moveCount=0;
var flagVictory=false;
function init(){
map = document.getElementById("map");
map.width=gameWidth;
map.height=gameHeight;
ctxMap = map.getContext("2d");
game();
map.addEventListener("click", clickFunc, false);
}
var Tile = function(){
this.i=0;
this.j=0;
this.x=0;
this.y=0;
this.number=0;
this.addTile = function(){
ctxMap.fillStyle="#FFFFE8";
ctxMap.fillRoundedRect(this.x, this.y, 64, 64, 10);
}
this.setText=function(text){
with (ctxMap){
font = '20pt impact';
textBaseline = 'top';
textAlign = 'center';
fillStyle = '#000';
fillText(text, this.x+31, this.y+20);
}
}
this.clearTile = function(){
ctxMap.fillStyle="#CCFFFF";
ctxMap.fillRoundedRect(this.x, this.y, 64, 64, 10);
}
}
function clickFunc(e){
for (var j = 0; j < 4; j++ ) {
for (var i = 0; i < 4; i++ ) {
if (matrix[i][j].x+64 > e.offsetX && matrix[i][j].x < e.offsetX &&
matrix[i][j].y+64 > e.offsetY && matrix[i][j].y < e.offsetY )
move(matrix[i][j]);
}}
if (44.7+64 > e.offsetX && 44.7 < e.offsetX &&
326.5+64 > e.offsetY && 326.5 < e.offsetY )
newRandGame();
}
// обработка клика на плику, перемещение плит
function move(e) {
var currNumber = e.number; // сохраняем номер текущей плитки
if (currNumber != 0 && !flagVictory) { // если это не пустое поле и не победное положение, то продолжаем
var i = e.i; // сохраним координаты плитки в матрице
var j = e.j;
var flag = false; // флаг для определения завершения хода
for (var k = 0; k < 4; k++ ) { // нам нужно проверить наличие пустой плитки с четырёх сторон
switch(k) {
case 0 :{
if (i+1 < 4 && matrix[i + 1][j].number == 0) { // если плитка не крайняя и снизу есть пустое поле, то
matrix[i + 1][j].addTile(); // пустое поле превращаем в плитку
matrix[i + 1][j].setText(e.number); // задаем новой плитке строку с числом
matrix[i + 1][j].number = currNumber; // теперь новая плитка превратилась в ту, на которую мы нажали
flag = true; // говорим что ход заврешен
};
break;
}
case 1 :{
if (j+1 < 4 && matrix[i][j+1].number == 0) {
matrix[i][j + 1].addTile();
matrix[i][j + 1].setText(e.number);
matrix[i][j + 1].number = currNumber;
flag = true;
};
break;
}
case 2 :{
if (i-1 > -1 && matrix[i - 1][j].number == 0) {
matrix[i - 1][j].addTile();
matrix[i - 1][j].setText(e.number);
matrix[i - 1][j].number = currNumber;
flag = true;
};
break;
}
case 3 :{
if (j-1 > -1 && matrix[i][j-1].number == 0) {
matrix[i][j - 1].addTile();
matrix[i][j - 1].setText(e.number);
matrix[i][j - 1].number = currNumber;
flag = true;
};
break;
}
}
if (flag) { // если ход завершен
matrix[i][j].number = 0; // текущую плитку делаем пустым полем
e.clearTile();
moveCount++; // счетчик ходов
setCountMc(moveCount); // увеличиваем счетчик
// if(check()) flagVictory=true; // проверка на победу
break;
}
}
}
}
function game(){
ctxMap.fillStyle="#CECECE";
ctxMap.fillRect(0,0,gameWidth,gameHeight);
setRestartBtn();
setCountMc(0);
setTiles();
}
function setRestartBtn() {
with (ctxMap){
fillStyle="#333333";
fillRoundedRect(44.7, 326.5, 50, 50, 10);
font = '10pt impact';
textBaseline = 'top';
textAlign = 'left';
fillStyle = '#ffffff';
fillText("Restart", 44.7+5, 326.5+17);
}
}
function setCountMc(string) {
with (ctxMap){
fillStyle="#333333";
fillRoundedRect(192.55, 326.5, 50, 50, 10);
font = '10pt impact';
textBaseline = 'top';
textAlign = 'left';
fillStyle = '#ffffff';
fillText("MOVES", 192.55+7, 326.5+5);
font = '18pt impact';
textAlign = 'center';
fillText(string, 192.55+25, 326.5+22);
}
}
function setTiles(){
for (var j=0; j<4; j++){
for (var i=0; i<4; i++){
matrix[i][j]=new Tile();
matrix[i][j].i=i;
matrix[i][j].j=j;
matrix[i][j].x=4+i*64+8*i;
matrix[i][j].y=4+j*64+8*j;
}
}
newRandGame();
}
// функция создания новой игры
function newRandGame() {
flagVictory = false; // сброс флага победы
moveCount=0; // сброс счетчика ходов
// countMc.Count_field.text = String(moveCount);
var tempcount = 0; // временная переменная для присвоения занчений в массиве
random(); // генерируем рандомную последовательность от 1 до 15 в массив
for (var j = 0; j < 4; j++ ) { // в двойном цикле пишем рандомную последовательность в нашу матрицу
for (var i = 0; i < 4; i++ ) {
matrix[i][j].addTile();
matrix[i][j].setText(randomMas[tempcount]); //= String(randomMas[tempcount]);
matrix[i][j].number = randomMas[tempcount];
tempcount++;
}
}
matrix[3][3].clearTile(); // плитку в правом нижнем углу делаем пустым полем
matrix[3][3].number = 0;
}
// создание масива с рандомной последовательностью от 1 до 15
function random() {
var flag = true;
var temp = 0;
var count = 0;
for (var k = 0; k < 16; k++ ) randomMas[k]=0 // обнуляем массив
for (var j = 0; j <15; j++ ) { // в цикле создаем и записываем в массив 15 чисел
while (flag) { // этот цикл работает до тех пор, пока не сгенерируется число, которого еще нет в массиве
if (count == 15) break;
temp = Math.round(15 * Math.random() + 1);
flag = false;
for (var i = 0; i < 16; i++ ) { // цикл проверяет сгенерированное число, на его наличие в массиве
if (randomMas[i] == temp || temp==16) { flag = true; break; }
}
}
// console.log(temp);
randomMas[j] = temp;
count++;
flag = true;
}
}
CanvasRenderingContext2D.prototype.fillRoundedRect = fillRoundedRect;
/* x: Координата верхнего левого угла по горизонтали
y: Координата верхнего левого угла по вертикали
w: Ширина прямоугольника
h: Высота прямоугольника
r: Радиус закруглений
*/
function fillRoundedRect(x, y, w, h, r){
this.beginPath();
this.moveTo(x+r, y);
this.lineTo(x+w-r, y);
this.quadraticCurveTo(x+w, y, x+w, y+r);
this.lineTo(x+w, y+h-r);
this.quadraticCurveTo(x+w, y+h, x+w-r, y+h);
this.lineTo(x+r, y+h);
this.quadraticCurveTo(x, y+h, x, y+h-r);
this.lineTo(x, y+r);
this.quadraticCurveTo(x, y, x+r, y);
this.fill();
}
Вот, что в итоге у нас получилось:
В этом примере я не заморачивался со шрифтами и использовал Impact, но если у вас нет в системе этого шрифта, то буквы и цифры могут немного поплыть.
Комментариев нет:
Отправить комментарий