要看懂这个教程,你需要:

1.一个智商基本在线的脑子。

2.基础的Html,Css,JavaScript知识和一个能运行Html的IDE

3.亲手实操,持之以恒,善始善终。

游戏源代码已上传到我的GitHub仓库,欢迎 Submit issue

YLX621/bouncing-ball​github.com
64b90b13e9093d662cd9ed8f41b8a051.png

首先我们来看一下游戏的效果

知乎视频​www.zhihu.com

你只要跟紧我的每一步,在文章结束后就会亲手打造一个上述游戏,源码在文章末尾公开。

我使用的编辑器是vscode,你们也可以使用自己喜欢编辑器。

首先创建三个文件夹分别为index.html,style.css,main.js

本教程只针对Javascript进行讲解,对Css修饰类的文本只提供文案。

复制粘贴以下Html代码

<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8">
 <title>Bouncing balls</title>
 <link rel="stylesheet" href="style.css">
 </head>
 <body>
 <h1>bouncing balls</h1>
 <canvas></canvas>
 <script src="main.js"></script>
 </body>
</html>

这一段Html代码很普通,引入了Css和JavaScript文件,加入h1标题,和引入画布canvas。对此不进行过多解释,

接下来在style.css文件中加入以下代码

html, body {
 margin: 0;
  }
 html {
 font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
 height: 100%;
  } 
 body {
 overflow: hidden;
 height: inherit;
  }
 h1 {
 font-size: 2rem;
 letter-spacing: -1px;
 position: absolute;
 margin: 0;
 top: -4px;
 right: 5px;
 color: transparent;
 text-shadow: 0 0 4px rgb(19, 224, 163);
  }

也是很普通的代码块,值得注意的是将h1标题设置为透明。

到此为止,简单的过程已经完毕,接下来是重头戏,JavaScript。

JavaScript是实现对html的动态过程,也是前端工程师必须精通的一点,接下来我会比之前更详细地讲解。

在你的main.js文件中加入以下代码

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;

其中前两行我用canvas变量代替canvas元素,用ctx变量使得画布为'2d'。

接下来就是设置width,height变量,让canvas的宽和高等于浏览器的宽和高。

function random(min,max) {
  return Math.floor(Math.random()*(max-min)) + min;
}
function randomColor() {
  return 'rgb(' +
         random(0, 255) + ', ' +
         random(0, 255) + ', ' +
         random(0, 255) + ')';
}

第一个函数为我们生成一个minmax之间的随机整数,第二个函数为我们生成一个随机的颜色值。

接下来开始我们的面向对象操作-小球,将以下代码加入到你的代码底部

function Ball(x, y, velX, velY, color, size) {
  this.x = x;
  this.y = y;
  this.velX = velX;
  this.velY = velY;
  this.color = color;
  this.size = size;
}

我们在这里定义了小球的属性。x,y指的是小球的坐标。velX,velY指的是小球的速度,color是小球的颜色,size指的是小球的大小。

小球的属性定义完了,那么我们需要怎样让小球动起来呢?

首先给小球加一个draw的方法

Ball.prototype.draw = function() {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
  ctx.fill();
}

beginPath()声明,我们要开始在画布上画一个图像了。

用fillStyle()来声明小球的颜色

使用arc()方法来在纸上画出一段圆弧。有这些参数:

x和y是圆弧的中心的坐标 —— 也就是小球的中心坐标。圆弧的半径 —— 小球的半径。最后两个参数是开始和结束,也就是圆弧对应的夹角,单位以弧度表示。这里我们用的是 0 和 2 * PI,也就是 360 度(如果你设置成 0 和 1 * PI,则只会出现一个半圆,也就是 180 度)最后,我们使用fill()方法,也就是声明我们结束了以 beginPath() 开始的绘画,并且使用我们之前设置的颜色进行填充。

加入以下代码

let testBall = new Ball(50, 100, 4, 4, 'blue', 10);
testBall.x
testBall.size
testBall.color
testBall.draw()

此时打开你的Html文件,已经可以看到一个小球了。但这个小球并不会动,所以,我们需要给小球原型加上一个update()方法。复制粘贴以下代码

Ball.prototype.update = function() {
  if ((this.x + this.size) >= width) {
    this.velX = -(this.velX);
  }
  if ((this.x - this.size) <= 0) {
    this.velX = -(this.velX);
  }
  if ((this.y + this.size) >= height) {
    this.velY = -(this.velY);
  }
  if ((this.y - this.size) <= 0) {
    this.velY = -(this.velY);
  }
  this.x += this.velX;
  this.y += this.velY;
}

事实上,上面这一行代码看起来复杂,其实只是if···else···的变形。

按照顺序除了最后两行代码,其他的都是查看是否撞到右侧左侧下侧上侧。

最后两行,将vel的值加到x的坐标上,将velY的值加到y坐标上 —— 每次调用这个方法的时候小球就移动这么多。

好了,我们再加上一些小球,让画面动起来

 let balls = [];

while (balls.length < 150) {
 let size = random(10,20);
 let ball = new Ball(
 random(0 + size,width - size),
 random(0 + size,height - size),
 random(-7,7),
 random(-7,7),
 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')',
 size
  );
  balls.push(ball);
}

第一行,使用数组来储存小球。

接下来小球个数<150个,我会在后面解释这个代码。下面代码的作用也就是让画面动起来,几乎所有的动画效果都会用到一个运动循环,也就是每一帧都自动更新视图。这是大多数游戏或者其他类似项目的基础。

最后定义一个loop()函数。

function loop() {
  ctx.fillStyle = 'rgba(0, 0, 0,0.1)';
  ctx.fillRect(0, 0, width, height);

  for (let i = 0; i < balls.length; i++) {
    balls[i].draw();
    balls[i].update();
  }

  requestAnimationFrame(loop);
}

这个函数的作用是,将整个画布设置为半透明黑色。使用fillRect来定义整个画布的起始坐标和宽度。

之后用一个递归函数让小球数目保持在我们之前设置的150个。这里注意一下递归的用法,是算法的一种。

之后让保存在数组中的所有小球都调用draw()和update()函数。

使用requestAnimationFrame方法再运行一次函数 —— 当一个函数正在运行时传递相同的函数名,从而每隔一小段时间都会运行一次这个函数,这样我们可以得到一个平滑的动画效果。这主要是通过递归完成的 —— 也就是说函数每次运行的时候都会调用自己,从而可以一遍又一遍得运行。

最后别忘记了加入loop()函数

loop();

以上的教程就讲完了,如果你打开浏览器查看,你会发现你的小球实现了类似效果,但如果你仔细一点就会发现发现你的小球在撞击时候并不会变色,那是为什么呢?

因为没有在update()函数中定义此效果。

试着在你的Ball.prototype.后加入以下代码

Ball.prototype.collisionDetect = function() {
  for (let j = 0; j < balls.length; j++) {
    if (this !== balls[j]) {
      const dx = this.x - balls[j].x;
      const dy = this.y - balls[j].y;
      const distance = Math.sqrt(dx * dx + dy * dy);

      if (distance < this.size + balls[j].size) {
        balls[j].color = this.color = randomColor();
      }
    }
  }
}
balls[i].collisionDetect();

保存打开浏览器,你就会得到视频里面的游戏啦。

我希望你们玩得开心,编写出你自己的随机弹跳球。

源码链接: https://pan.baidu.com/s/19ezZOdDAOj4rnOh1zLFzEw 提取码: ninw

记得关注我哦!

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐