БлогNot. Лопни пузыри! - игра на canvas

Лопни пузыри! - игра на canvas

Сегодня вдруг родилось :) Для начала игры щёлкните по надписи "Click to start" под игровым полем.

С нижней части игрового поля появляются разноцветные мыльные пузыри, Ваша задача - лопнуть их все (просто наведением мыши, ничего нажимать не нужно).

Если хоть один пузырь улетел за верхней край канвы, игра окончена и Вы проиграли, но можно снова щёлкнуть по надписи с Вашим количеством набранных очков и всё повторить.

Отличная игра на скорость реакции и проверку качества мыши :)

Навскидку у меня больше 400-500 очков набрать не получается, а у Вас?

Ниже под катом приложена сама игра, а затем полный исходник, который можно скопировать и выполнить как файл типа .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>

теги: javascript графика random игра

показать комментарии (1)

12.01.2019, 18:29; рейтинг: 271