Сегодня я расскажу вам о том как написать кубик для игр, при этом понадобиться только браузер и текстовый редактор. О том что можно написать такой кубик, я увидел на одном из примеров и интернете, но мне совсем не понравилась реализация и я решил изменить код на свой вкус поэтому можно считать, что это моя разработка. Итак начнем:
Первое с чем необходимо познакомиться это с объектной моделью языка JavaScript (сами сами). Все это дело я поместил в отдельный файл, — отдельный объект, который в итоге можно очень удобно прицепить к canvas -у.
Сам объект разделил на несколько частей(методов):
- Отрисовка кубика.
- Отрисовка точки.
- Вывод точек на кубике.
- Эффектный бросок.
Творческий процесс начинается еще до момента программирования определяю для себя как будут располагаться точки на кубике их номер и координаты. Кубик статический 100х100px.
this.point={ // Координаты точек. 1:{'x':20, 'y':20}, // 1 2 2:{'x':80, 'y':20}, // 3 4 5 3:{'x':20, 'y':50}, // 6 7 4:{'x':50, 'y':50}, 5:{'x':80, 'y':50}, 6:{'x':20, 'y':80}, 7:{'x':80, 'y':80}, };
Теперь, надо сопоставить какие точки показывать при каком количестве выпавших очков:
this.dependence={ // Колличество очков, какие точки. 1:[4], 2:[1,7], 3:[1,4,7], 4:[1,2,6,7], 5:[1,2,4,6,7], 6:[1,2,3,5,6,7] };
Теперь можно приступить к прорисовке кубика, ну раз 2d то квадрата. И сразу надо оговориться, что когда я его нарисовал прямоугольным он мне не понравился, порывшись в интернете нашел готовую функцию нарисовать квадрат с закругленными углами.
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(); }
Чтоб, ей можно было воспользоваться «красиво» прикручиваю ее через прототип к 2d контенту:
CanvasRenderingContext2D.prototype.fillRoundedRect = fillRoundedRect;
После того как квадрат нарисован, я сохраняю его в переменную с помощью функции getImageData() для дальнейшего использования и сокращение времени выполнения (не надо заново перерисовывать — он уже есть готовый).
/* * Рисуем квадрат. */ this.DrawSquare=function(){ this.ctx.strokeStyle="black"; this.ctx.fillStyle="rgba(100,100,100,0.4)"; this.ctx.fillRoundedRect(0, 00, 100, 100, 15); this.ctx.stroke(); this.pic_square=this.ctx.getImageData(0, 0, 100, 100); };
Теперь по тому же принципу рисую точку на квадрате и сохраняю ее в переменную:
/* * Рисуем точку. */ this.DrawPoint=function(){ this.ctx.strokeStyle="black"; this.ctx.fillStyle="rgba(150,150,250,0.9)"; this.ctx.beginPath(); this.ctx.arc(this.point[this.dependence[1][0]].x, this.point[this.dependence[1][0]].y, 10, 0, 360); this.ctx.stroke(); this.ctx.fill(); this.pic_point=this.ctx.getImageData(this.point[this.dependence[1][0]].x-11, this.point[this.dependence[1][0]].y-11, 22,22); }
Тут стоит пояснить что происходит при сохранении картинки. Дело в том что координаты точек указанны для центра окружности, поэтому при сохранении надо учитывать сдвиг по осям плюс увеличении площади сохранения. Как показала практика в разы быстрее работает использование именно переменной, а не перерисовки каждой точки заново, при броске.
Теперь интересное… кинем кубик, для этого нужен рандом для случайного появления очков при броске. В интернете есть все:
function getRandomInt(min, max){ return Math.floor(Math.random() * (max - min + 1)) + min; }
С начало рисую чистый кубик, потом узнаю сколько очков должно выпасть и рисую на нем соответствующие точки:
/* * Кидаем кубик. */ this.ThrowDice=function(){ this.ctx.putImageData(this.pic_square, 0, 0); var namber=getRandomInt(1,6); for (var draw in this.dependence[namber]) this.ctx.putImageData(this.pic_point, this.point[this.dependence[namber][draw]].x-11, this.point[this.dependence[namber][draw]].y-11); };
Стоит отметить опять же про координаты точек, делаем поправку на центр окружности. Можно на этом остановиться и при клике запускать эту функцию.. но мне показалось это скучно… И я решил добавить еще самый волнующий момент — эффект хаотичного вращения кубика:
/* * Эффкет бросания. */ this.RandThrow=function(){ if(this.timer) clearInterval(this.timer); this.count=0; this.count_end=getRandomInt(5,20); var link=this; this.timer=setInterval(function(){ if(link.count>link.count_end) clearInterval(link.timer); link.ThrowDice(); link.count++; },160); }
Остановлюсь поподробней на этой функции. Первая строчка появилась благодаря моему соседу на котором я тестировал. Дело в том, что она вешается на клик по изображению, и когда происходит несколько кликов даже боюсь представить что твориться. Когда сосед сказал, что кубик не останавливается, у меня вызвало удивление, оказалось он тыркал на него не дождавшись остановки, т.е таймер терял свой идентификатор, и цикл шел бесконечно. Эта строчка избавляет от этого недоразумения.
3 строчка — Случайным образом выбираем «силу» броска.
4 строчка — Для правильного понимания объекта в таймере необходимо использовать постоянную ссылку на объект, т.к. «this» внутри таймера принимает другое значение.
И потом бросаем кубик…
Теперь осталась инициализация, передаем id элемента <canvas> и цепляемся к нему, проверяем поддержку браузером, рисуем квадратик, точку, бросаем кубик, и вешаю событие опять через линк.
var canvas=document.getElementById(canvas); if(canvas && canvas.getContext) { this.ctx=canvas.getContext("2d"); this.DrawSquare(); this.DrawPoint(); this.RandThrow(); var link=this; canvas.onclick=function(){link.RandThrow()}; } }
Для подключения необходимо добавить на страницу:
<script type="text/javascript" src="/wp-includes/js/dice.js"></script>
И после того как страница загрузиться прицепить к нему объект:
$(document).ready(function(){ var dice1 = new Dice('myCanvas'); });
Описанный выше костяк легко дополняется например достаточно передать дополнительный объект, чтоб бросать по два кубика.. Например:
var bla = new Dice("canvas1",new Dice("canvas2"));
а в инициализации добавить obj.RandThrow();
var canvas=document.getElementById(canvas); if(canvas && canvas.getContext) { this.ctx=canvas.getContext("2d"); this.DrawSquare(); this.DrawPoint(); var link=this; link.RandThrow(); canvas.onclick=function(){link.RandThrow()}; if(obj) obj.RandThrow(); } }
Полный код ищите в шапке страницы «Dice.js».
Ну и пример работы:
P.s:
Это моя первая статья… =)
Сам писал или готовое решение в инете нашел?
Я в начале написал, идею в интернете нашел, а реализацию сам сочинял.
Красавчик=)