Canvas弹球小游戏

Canvas弹球小游戏
C
玩法介绍:通过键盘上下左右键控制小黑球移动,'吃掉’彩色弹球,彩色弹球相互碰撞交换颜色,按住Ctrl键可加速小黑球移动速度。
使用技术: Canvas(绘制画布、小球)、javaScript(创建/操控小球、碰撞检测等)
设计思路

彩色弹球

  1. 创建一个弹球原型对象Ball(),在父类中定义每一个弹球的属性及事件,每一个弹球ball是’子’,创建后就有父类的属性和方法let ball = new Ball()
  2. init:定义弹球一些初始属性,随机的初始位置/初速度/随机颜色
  3. draw:通过canvas来绘制彩色弹球
  4. move:弹球间的碰撞检测处理,包括与小黑球的碰撞(碰撞后被清除)/彩色弹球之间的碰撞(改变颜色)/与画布边界的碰撞

操控小黑球
controlBall:控制小球的移动,并做边界处理,按下ctrl键增大小黑球的速度speed
完整代代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>弹球</title>
    <link rel="stylesheet" href="style.css">
  </head>

  <body>
    <h1>弹球</h1>
    <h2></h2>
    <h2 style="top: 60px;">方向键移动黑球,Ctrl键加速移动</h2>
    <canvas id="canvas"></canvas>
    <div id="conBall" style="top: 300px;left: 800px;width: 15px;"></div>
    <script src="main.js">
    </script>
  </body>
</html>
var can = document.getElementById("canvas");
var ctx = can.getContext("2d");
var conBall = document.getElementById("conBall");
var h2 = document.querySelector("h2");
var dir = 0; //小黑球移动方向
var speed = 15; //小黑球速度
var num = 25;
var aBall = [];
var aColor = [
  "rgb(136, 24, 241)",
  "rgb(247, 11, 133)",
  "rgb(1, 81, 255)",
  "rgb(253, 248, 0)",
  "rgb(246, 0, 0)",
  "rgb(53, 232, 53)",
];
var w, h;

// 获取小黑球的圆心坐标和半径
var offCl = conBall.offsetLeft;
var offCt = conBall.offsetTop;
var cr = parseInt(conBall.style.width) / 2;
var cx = offCl + cr;
var cy = offCt + cr;
~~(function setSize() {
  window.onresize = arguments.callee;
  w = can.width = window.innerWidth;
  h = can.height = window.innerHeight;
})();

// 生成随机数的函数
function random(min, max) {
  const num = Math.floor(Math.random() * (max - min)) + min;
  return num;
}

/*
创建小球对象
*/
function Ball() {}
// 在原型对象中设置小球的初始属性
Ball.prototype = {
  // 小球的初始位置属性
  init: function () {
    this.x = random(30, w);
    this.y = random(30, h);
    this.r = random(8, 20);
    this.vx = random(-5, 5);
    this.vy = random(-5, 5);
    this.crash = false;
    if (this.vx == 0 && this.vy == 0) {
      this.vx = 1;
      this.vy = 1;
    }
    this.color = aColor[Math.floor(random(0, 6))];
  },
  // 绘制初始小球
  draw: function () {
    ctx.beginPath();
    ctx.fillStyle = this.color;
    ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
    ctx.fill();
  },
  // 小球移动
  move: function () {
    var mItem = this;
    // 弹球与操控小球的碰撞
    if (
      Math.sqrt(Math.pow(this.x - cx, 2) + Math.pow(this.y - cy, 2)) <
      this.r + cr
    ) {
      this.clearBall();
    } else {
      //弹球之间的碰撞
      for (var item of aBall) {
        if (mItem != item) {
          if (
            Math.sqrt(
              Math.pow(item.x - mItem.x, 2) + Math.pow(item.y - mItem.y, 2)
            ) <
              item.r + mItem.r &&
            mItem.crash == false &&
            item.crash == false
          ) {
            mItem.crash = true;
            item.crash = true;
            var nColor = aColor[Math.floor(random(0, 6))];
            item.color = mItem.color = nColor;
            item.vx = -item.vx;
            item.vy = -item.vy;
            mItem.vx = -mItem.vx;
            mItem.vy = -mItem.vy;
          }
        }
        mItem.crash = false;
        item.crash = false;
      }
      this.x += this.vx;
      this.y += this.vy;
      // 水平碰撞
      if (this.x - this.r < 0 || this.x + this.r > w) {
        this.vx = -this.vx;
      }
      // 垂直碰撞
      if (this.y - this.r < 0 || this.y + this.r > h) {
        this.vy = -this.vy;
      }
      this.draw();
    }
  },
  // 清除小球
  clearBall: function () {
    aBall.splice(aBall.indexOf(this), 1);
  },
};

// 创建弹球函数
function creatBall(num) {
  for (var i = 0; i < num; i++) {
    var ball = new Ball();
    ball.init();
    ball.draw();
    aBall.push(ball);
  }
}

var timer = requestAnimationFrame(function fn() {
  h2.innerHTML = "还剩余" + aBall.length + "个弹球";
  // 绘制蒙版
  ctx.fillStyle = "rgba(0,0,0,0.1)";
  ctx.fillRect(0, 0, w, h);
  for (var item of aBall) {
    item.move();
  }
  controlBall();
  timer = requestAnimationFrame(fn);
});
creatBall(num);

/*
操纵小黑球
*/
function controlBall() {
  switch (dir) {
    case "ArrowLeft":
      if (conBall.offsetLeft < 5) {
        break;
      } else {
        conBall.style.left = conBall.offsetLeft - speed + "px";
        offCl = conBall.offsetLeft;
        cx = offCl + cr;
        break;
      }
    case "ArrowDown":
      if (conBall.offsetTop > h - 30) {
        break;
      } else {
        conBall.style.top = conBall.offsetTop + speed + "px";
        offCt = conBall.offsetTop;
        cy = offCt + cr;
        break;
      }
    case "ArrowRight":
      if (conBall.offsetLeft > w - 30) {
        break;
      } else {
        conBall.style.left = conBall.offsetLeft + speed + "px";
        offCl = conBall.offsetLeft;
        cx = offCl + cr;
        break;
      }
    case "ArrowUp":
      if (conBall.offsetTop < 5) {
        break;
      } else {
        conBall.style.top = conBall.offsetTop - speed + "px";
        offCt = conBall.offsetTop;
        cy = offCt + cr;
        break;
      }
  }
}

document.onkeydown = function (event) {
  // 按下ctrl键加速
  if (event.ctrlKey) {
    speed = 18;
  } else {
    speed = 10;
  }
  dir = event.key;
};
document.onkeyup = function () {
  dir = 0;
};

html, body {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  font-family: sans-serif;
  height: 100%;
}

body {
  overflow: hidden;
  height: inherit;
}

h1 {
  font-size: 32px;
  letter-spacing: -1px;
  position: absolute;
  margin: 0;
  top: -4px;
  right: 5px;
  color: transparent;
  text-shadow: 0 0 3px white;
}
h2 {
  font-size: 20px;
  letter-spacing: -1px;
  position: absolute;
  margin: 0;
  top: 35px;
  right: 5px;
  color: transparent;
  text-shadow: 0 0 2.5px white;
}
#canvas{
 background-color: #000;
 display: block;
}
#conBall{
  
  height: 15px;
  background-color: #000;
  border: 4px solid #fff;
  border-radius: 15px;
  position: absolute;
  

  box-shadow: 0px 2px 2px 0px #fff,
  0px -2px 2px 0px #fff,
  2px 0px 2px 0px #fff,
  -2px 0px 2px 0px #fff;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值