Лопни пузыри! - игра на canvas
Сегодня вдруг родилось :) Для начала игры щёлкните по надписи "Click to start" под игровым полем.
С нижней части игрового поля появляются разноцветные мыльные пузыри, Ваша задача - лопнуть их все (просто наведением мыши, ничего нажимать не нужно).
Если хоть один пузырь улетел за верхней край канвы, игра окончена и Вы проиграли, но можно снова щёлкнуть по надписи с Вашим количеством набранных очков и всё повторить.
Отличная игра на скорость реакции и проверку качества мыши :)
Навскидку у меня больше 400-500 очков набрать не получается, а у Вас?
Ниже под катом приложена сама игра, а затем полный исходник (без обрамляющих тегов HTML), который можно скопировать и выполнить как файл типа .html
в браузере. Наверняка, подобрав настройки, указанные в начале листинга, можно сделать игру более сбалансированной.
Click to start
<style> .buubleCanvas { margin:0; padding:0; border: 0; background: #000000; display: block; position: relative; z-index: 10; } .bubbleButton { font-family: sans-serif; font-weight: 500; font-size: 20px; color: #111111; border: 3px solid #773322; border-radius: 4px; padding: 8px; } </style> <div align="center"> <canvas id="buubleCanvas" class="buubleCanvas" width="600" height="600"></canvas> <p><span class="bubbleButton" id="countBox" onClick="startGame();">Click to start</span></p> </div> <script> var canvas = document.getElementById('buubleCanvas'); var ctx = canvas.getContext('2d'); var bubbleCount = 100; //количество пузырей var bubbles = []; var bubbleSpeed = 1; var popLines = 12; //сколько линий при взрыве var popDistance = 40; var popCoeff = 0.61; //степень разлёта при лопании, от 0 до 1 var minRadius = 18; //минимальный радиус var scaleRadius = 12; //максимальная добавка для радиуса var mouseOffset = { x: 0, y: 0 } var counter = 0; //счёт игры var inGame = false; var globalId; function startGame () { if (inGame) return; for (var i = 0; i < bubbleCount; i++) { var tempBubble = new createBubble(); bubbles.push(tempBubble); } inGame = true; document.getElementById('countBox').innerHTML = 'Your count is 0'; globalId = window.requestAnimationFrame (animate); } function animate () { //цикл анимации if (!inGame) return; ctx.clearRect(0, 0, canvas.width, canvas.height); //очистка канвы ctx.beginPath(); for (var i = 0; i < bubbles.length; i++) { //цикл отрисовки bubbles[i].position.x = Math.sin(bubbles[i].count/bubbles[i].distanceBetweenWaves) * 50 + bubbles[i].xOffset; bubbles[i].position.y = bubbles[i].count; bubbles[i].render(); if (bubbles[i].count < - bubbles[i].radius) { //конец игры //bubbles[i].count = canvas.height + bubbles[i].yOffset; document.getElementById('countBox').innerHTML = 'Your count is ' + counter + '; repeat?'; counter = 0; window.cancelAnimationFrame (globalId); bubbles = []; inGame = false; return; } else { bubbles[i].count -= bubbleSpeed; } } for (var i = 0; i < bubbles.length; i++) { //при наведении мыши на пузырь if (mouseOffset.x > bubbles[i].position.x - bubbles[i].radius && mouseOffset.x < bubbles[i].position.x + bubbles[i].radius) { if (mouseOffset.y > bubbles[i].position.y - bubbles[i].radius && mouseOffset.y < bubbles[i].position.y + bubbles[i].radius) { document.getElementById('countBox').innerHTML = 'Your count is ' + (++counter); for (var a = 0; a < bubbles[i].lines.length; a++) { popDistance = bubbles[i].radius * popCoeff; bubbles[i].lines[a].popping = true; bubbles[i].popping = true; } } } } globalId = window.requestAnimationFrame (animate); } var createBubble = function() { //Новый пузырь var colors = ['#ff0000','#0000ff','#00ff00','#ffff00','#ff00ff']; //цвета this.position = { x: 0, y: 0 }; this.radius = minRadius + Math.random() * scaleRadius; this.xOffset = Math.random() * canvas.width - this.radius; this.yOffset = Math.random() * canvas.height; this.distanceBetweenWaves = 50 + Math.random() * 40; this.count = canvas.height + this.yOffset; this.color = colors[ Math.floor(Math.random()*colors.length) ]; this.lines = []; this.popping = false; this.maxRotation = 85; this.rotation = Math.floor (Math.random() * (this.maxRotation - (this.maxRotation * -1))) - this.maxRotation; this.rotationDirection = 'forward'; for (var i = 0; i < popLines; i++) { var tempLine = new createLine (this.color); tempLine.bubble = this; tempLine.index = i; this.lines.push(tempLine); } this.resetPosition = function() { this.position = {x: 0, y: 0}; this.radius = 8 + Math.random() * 6; this.xOffset = Math.random() * canvas.width - this.radius; this.yOffset = Math.random() * canvas.height; this.distanceBetweenWaves = 50 + Math.random() * 40; this.count = canvas.height + this.yOffset; this.popping = false; } this.render = function() { if (this.rotationDirection === 'forward') { if (this.rotation < this.maxRotation) this.rotation++; else this.rotationDirection = 'backward'; } else { if (this.rotation > this.maxRotation * -1) this.rotation--; else this.rotationDirection = 'forward'; } ctx.save(); ctx.translate (this.position.x, this.position.y); ctx.rotate (this.rotation*Math.PI/180); if (!this.popping) { ctx.beginPath(); ctx.strokeStyle = this.color; ctx.lineWidth = 1; ctx.arc(0, 0, this.radius - 3, 0, Math.PI*1.5, true); ctx.stroke(); ctx.beginPath(); ctx.arc(0, 0, this.radius, 0, Math.PI*2, false); ctx.stroke(); } ctx.restore(); for (var a = 0; a < this.lines.length; a++) { //Отрисовка линий if (this.lines[a].popping) { if (this.lines[a].lineLength < popDistance && !this.lines[a].inversePop) this.lines[a].popDistance += 0.05; else { if (this.lines[a].popDistance >= 0) { this.lines[a].inversePop = true; this.lines[a].popDistanceReturn += 1; this.lines[a].popDistance -= 0.025; } else { this.lines[a].resetValues(); this.resetPosition(); } } this.lines[a].updateValues(); this.lines[a].render(); } } } } function createLine (color) { //новая линия this.lineLength = 0; this.popDistance = 0; this.popDistanceReturn = 0; this.inversePop = false; this.popping = false; this.color = color; this.resetValues = function() { this.lineLength = 0; this.popDistance = 0; this.popDistanceReturn = 0; this.inversePop = false; this.popping = false; this.updateValues(); } this.updateValues = function() { this.x = this.bubble.position.x + (this.bubble.radius + this.popDistanceReturn) * Math.cos(2 * Math.PI * this.index / this.bubble.lines.length); this.y = this.bubble.position.y + (this.bubble.radius + this.popDistanceReturn) * Math.sin(2 * Math.PI * this.index / this.bubble.lines.length); this.lineLength = this.bubble.radius * this.popDistance; this.endX = this.lineLength; this.endY = this.lineLength; } this.render = function() { this.updateValues(); ctx.beginPath(); ctx.strokeStyle = this.color; ctx.lineWidth = 2; ctx.moveTo(this.x, this.y); if (this.x < this.bubble.position.x) this.endX = - this.lineLength; if (this.y < this.bubble.position.y) this.endY = - this.lineLength; if (this.y === this.bubble.position.y) this.endY = 0; if (this.x === this.bubble.position.x) this.endX = 0; ctx.lineTo(this.x + this.endX, this.y + this.endY); ctx.stroke(); }; } canvas.addEventListener('mousemove', mouseMove); //назначаем слушатель события mousemove function mouseMove(e) { mouseOffset.x = e.offsetX; mouseOffset.y = e.offsetY; } </script> <noscript><div align="center">You need Javascript to run it</div></noscript>
12.01.2019, 18:29 [2302 просмотра]