К чему этот пост и о чем он? Если честно, я сам не знаю для чего я пишу этот пост, возможно, мне просто скучно или что-то в этом духе. Данный пост будет повествовать о том, как мы будем создавать небольшую игру с использованием веб технологий. В данном посте не будет каких-то нормальных пояснений и теории, здесь будет только практика и код. Только хардкор в общем. Саму игру я сам еще не дописал, поэтому любая помощь с кодом или моральная поддержка приветствуется. Данный пост будет обновляться по мере написания сей игры.
Идея написать эту игру меня сподвигло вот это довольно простая и интересная игра (хотя это больше движок), затягивающая на мгновение пройти свой единственный уровень.
Суть Игра довольно тривиальная и простая. Основная суть игры заключается в прохождении сгенерированного лабиринта, при прохождении, генерируется новый лабиринт, но только БОЛЬШЕ и СЛОЖНЕЕ. Так же для усложнения игрок не видит всего лабиринта, он видит лишь место, где он находится (более наглядный пример: представьте себя в реальном лабиринте).
Структура
За основу взята ООП модель. А точнее, prototype (кликните, что бы почитать, что это)
Код
var Game = function () { this.tile_size = 16; // размер квадратика карты в пикселях
// для удобного получения нажатой кнопки this.key = { down: false, left: false, right: false, up: false };
// перевод кода кнопки в читаемый вид this.keyCode = { 37: "left", 38: "up", 39: "right", 40: "down" };
this.player = { loc: {x: 0, y: 0}, // координаты игрока step:1 // шаг игрока в пикселях };
// бинд функций на нажатие кнопок window.onkeydown = this.keydown.bind(this); window.onkeyup = this.keyup.bind(this);
this.current_map = this.map_gen(5); };
// тут пояснять не буду Game.prototype.keydown = function (e) { var _this = this; k = _this.keyCode[e.keyCode]; if (k) _this.key [k]= true; };
Game.prototype.keyup = function (e) { var _this = this; k = _this.keyCode[e.keyCode]; if (k) _this.key [k]= false; };
За основу алгоритма взят алгоритм Эллера, почитать о нем можно тут. У меня есть небольшая ошибка при генерации. Если точнее, в завершающей строке возникают могут возникать закрытые области, которых не должно быть. Милый человек, если знаешь где ошибка - помоги.
Код
Game.prototype.map_gen = function(size){ // данный объект нам нужен для удобной реализации алгоритма Эллера function obj(id, gleft, gdown){ this.id=0; this.gdown = false; this.gleft = false; if (id)this.id=id; if (gleft)this.gleft=true; if (gdown)this.gdown=true;
// собственно генерация лабиринта по алгоритму Эллера, пояснять код не буду // кстати, вместо добавлении справа границы, добавляем слева, мне почему-то показалось это проще var arr = []; logt = ''; for (var y = 0; y < s_y; y++) { arr [y]= [];
for(var x=0; x<s_x; x++){ arr [y][x]= new obj(x); var bar = Math.round(Math.random()); var left = (bar==1&&x!=0)?true:false, downprev = false, down = false;
if (y!=0) arr[y][x]= new obj(arr[y-1][x].id, arr[y-1][x].gleft, arr[y-1][x].gdown) else arr[y][x]= new obj(x);
if (y == s_y-1){ left = false; if (arr[y][x-1]) { if((arr[y][x].id == arr[y][x-1].id && !arr[y][x].gleft && !arr[y][x].gdown && !arr[y][x-1].gleft)) { arr[y][x-1].gleft = false; arr[y][x-1].gdown = false; left = true; } arr[y][x].id = arr[y][x-1].id; } } else { if(arr[y][x].gdown) arr [y][x]= new obj(x); if(arr[y][x-1] && x!=0){ if(!left) { if (Math.round(Math.random()) ==0) down = true; else downprev = true; } if (!left) arr[y][x-1].id = arr[y][x].id; } } if (downprev)arr[y][x-1].gdown = downprev; arr[y][x].gleft = left; arr[y][x].gdown = down; } };
//перевод в нормальный вид, для удобного вывода на экран var new_arr = []; var border = []; for (var y = 0; y < s_y*2; y++) {new_arr [y]= [];};
for (var y = 0; y < s_y; y++) { for (var x=0; x < s_x; x++){ new_arr[y*2+1][x*2+1] = 0; if (arr[y][x].gleft) { new_arr[y*2][x*2-1] = 1; if(arr[y-1]) new_arr[y*2-1][x*2-1] = 1; if(arr[y+1]) new_arr[y*2+1][x*2-1] = 1; }
// добавление границ лабиринта for (var e = 0; e<new_arr.length ; e++) { border [e]= [1]; new_arr[e].unshift(1); new_arr[e][new_arr.length] = 1 } border.push(1); new_arr.unshift(border); new_arr[new_arr.length-1] = border;
// вывод в консоль то что мы сгенерировали, для нормальной отладки log(arr); log(new_arr); return new_arr; };
// функция для вывода в консоль матрицы в удобном представлении log = function(arr) { text = ''; for (var i = 0; i < arr.length; i++) { if (arr[i].length<arr.length)arr[i].length=arr.length; for (var e=0; e<arr[i].length; e++){ if (!arr[i][e]) text += 0; else text += arr[i][e]; text+=' '; } text+='\n'; } console.log(text) }
3. Персонаж. Разрабатываем перемещение в лабиринте. 4. Видимость персонажа. Накладываем ограничения на видимость лабиринта.
Выводим на экран мы благодаря canvas. Она входит в HTML5 и на данный момент есть у всех новых браузеров, даже у IE. Нам необходимо циклично обновлять содержимое, если не будем обновлять, то будет казаться, что все просто замерло. Так же нам необходимо выводить сгенерированный лабиринт и блаблабла.
Код
// вывод одной "ячейки" в канвас Game.prototype.draw_tile = function (x, y, colour, context) { context.fillStyle = colour; context.fillRect( x, y, this.tile_size, this.tile_size ); };
// вывод сгенерированного лабиринта Game.prototype.draw_map = function(context){ var mapdata = this.current_map; for (var y = 0; y < mapdata.length; y++) {
for (var x = 0; x < mapdata[y].length; x++) { var t_x = (x * this.tile_size) var t_y = (y * this.tile_size) if(mapdata[y][x]!=0 && mapdata[y][x]) this.draw_tile(t_x,t_y,'#111',context); else this.draw_tile(t_x,t_y,'#fff',context); } } }
UPD: переписал весь код, теперь все что выше к тому что ниже никак не относится.
зеленый бонус - увеличивает радиус видимости (вероятность появления 1 к 7) синий бонус - увеличивает таймер (вероятность появления 1 к 7) оранжевый бонус - +5 к очкам (есть на всех уровнях) багровая клетка - переход на следующий уровень фиолетовая клетка - меняет цвет игрока при нажатии на энтер
Все уровни генерируется случайным образом, с каждым уровнем возможный максимальный размер увеличивается на 1. Генерация карты все еще через зад.
Для новой игры, необходимо перезагрузить страницу.
З.Ы. как обычно еще не полностью готово, еще слишком много работы. Возможно позже более менее распишу код.