【JavaScript】JavaScript对象(为弹球示例增加新功能)

根据MDN网站学习记录笔记


本项目主要是测试对JavaScript对象和面向对象结构的理解。

一、项目简介

首先在GitHub上面下载起始代码:index.html、 style.css 和 main.js

  1. 为弹球demo添加一个由玩家控制的“恶魔圈”,如果恶魔圈抓到弹球会把它会吃掉。
  2. 首先创建一个通用 Shape() 对象,然后由它派生出弹球和恶魔圈。
  3. 最后,为 demo 添加一个计分器来记录剩下的球数。

二、项目流程

2.1 创建新对象Shape()并添加一个新的构造器Ball()

改变你现有的构造器 Ball() 使其成为构造器 Shape() 并添加一个新的构造器 Ball(),其中draw(), update(), collisionDetect() 方法定义应保持不变。

// 定义Shape() 构造器
function Shape(x, y, velX, velY, exists) {
  this.x = x;
  this.y = y;
  this.velX = velX;
  this.velY = velY;
  this.exists = exists;
}

// 定义 Ball 构造器

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

2.2 定义恶魔圈EvilCircle()

EvilCircle() 构造器应该从Shape() 继承 x, y, 和 exists ,velX 和 velY 要恒为 20。

// 定义EvilCircle() 构造器
function EvilCircle(x, y, exists){
  Shape.call(this, x, y, exists);
  this.velX = 20;
  this.velY = 20;
  this.color = 'white';
  this.size = 10;
}

2.3 定义 EvilCircle() 的方法

  1. draw()

使恶魔圈变成空心,并且边缘加粗。

// 定义恶魔圈绘制函数
EvilCircle.prototype.draw = function() {
  ctx.beginPath();
  ctx.lineWidth = 3;
  ctx.strokeStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
  ctx.stroke();
};
  1. checkBounds()

类似于弹球的更新函数,要修改 x/y 的值,使恶魔圈稍微地弹回屏幕,通过加减size实现。

// 定义恶魔圈边缘检测函数
EvilCircle.prototype.checkBounds = function() {
  if((this.x + this.size) >= width) {
    this.x -= this.size;
  }

  if((this.x - this.size) <= 0) {
    this.x += this.size;
  }

  if((this.y + this.size) >= height) {
    this.y -= this.size;
  }

  if((this.y - this.size) <= 0) {
    this.y += this.size;
  }
};
  1. setControls()

这里的 window.onkeydown 用一个箭头函数代替了英文页面中的匿名函数

// 给window对象设置onkeydown键盘监听器
EvilCircle.prototype.setControls = function(){
  window.onkeydown = e => {
    switch(e.key) {
      case 'a':
        this.x -= this.velX;
        break;
      case 'd':
        this.x += this.velX;
        break;
      case 'w':
        this.y -= this.velY;
        break;
      case 's':
        this.y += this.velY;
        break;
    }
  };
}
  1. collisionDetect()

类似于弹球的碰撞检测,不同的是:这里的彭咋黄检测首先要检查循环到的小球是否存在,不存在则无需比较了。除此之外,需要将发生碰撞的小球的exists属性设置为不存在。

// 定义碰撞检测函数
EvilCircle.prototype.collisionDetect = function() {
  for(let j = 0; j < balls.length; j++) {
    if(balls[j].exists === true) {
      const dx = this.x - balls[j].x;
      const dy = this.y - balls[j].y;
      const distance = Math.sqrt(dx * dx + dy * dy);
    // 因为distance是两个圆心之间的距离!所以得小于两个圆的半径之和!
      if (distance < this.size + balls[j].size) {
        balls[j].exists = false;
      }
    }
  }
};

2.4 把恶魔圈带到程序中

loop()函数之前,创建一个新的恶魔圈的对象实例 (指定必需的参数),然后调用它的 setControls() 方法。

// 创建恶魔圈的实例并且使其坐标为随机数
evil = new EvilCircle(random(0, width), random(0, width), true);
// 启动监听
evil.setControls();

修改loop()函数

  • draw(), update(),collisionDetect() 函数的调用进行修改, 使这些函数只会在小球存在时被调用。
  • 调用恶魔圈实例的方法 draw(), checkBounds(), 和collisionDetect()
// 定义一个循环来不停地播放
function loop() {
  ctx.fillStyle = 'rgba(0,0,0,0.25)';
  ctx.fillRect(0, 0, width, height);

  for(let i = 0; i < balls.length; i++) {
    if(balls[i].exists){
      balls[i].draw();
      balls[i].update();
      balls[i].collisionDetect();
    }
    evil.draw();
    evil.checkBounds();
    evil.collisionDetect();
  }
  requestAnimationFrame(loop);
}

2.5 计算得分

  • 在HTML中添加一个

    元素并在css添加相应样式

  • 在js中创建变量存储段落的引用
// 存储段落的引用
const para = document.querySelector('p');
// 设置全局变量count
let count = 0;
  • 恶魔圈碰撞检测中减少count,在屏幕上显示小球数量
      if (distance < this.size + balls[j].size) {
        balls[j].exists = false;
        count--;
        para.textContent = "剩余彩球数:" + count;
      }
  • 创建小球数组时增加count,在屏幕上显示小球数量
  balls.push(ball);
  count++;
  para.textContent = '剩余彩球数:' + count;

三、效果展示

在这里插入图片描述

四、章节小结

4.1 对象继承中的call()函数

JavaScript中对象的继承不是复制来的,而是通过原型链继承。

function.call(thisArg, arg1, arg2, ...)

thisArg可选的。在 function 函数运行时使用的 this 值。如果为nullundefined则会自动替换为指向全局对象。

call()函数使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

使用 call 来实现继承:写一个方法,然后让另外一个新的对象来继承它。

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

4.2 用Object.create实现类式继承

Object.create(proto,[propertiesObject])

其中proto是新创建对象的原型对象propertiesObject可选。

返回值是一个带着指定原型对象和属性的新对象

// Shape - 父类(superclass)
function Shape() {
  this.x = 0;
  this.y = 0;
}

// 父类的方法
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - 子类(subclass)
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?',
  rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
  rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'

4.3 Canvas 2D中fillStyle和strokestyle

  • fillStyle: 设置填充图形的颜色,渐变和模式。
  • strokeStyle: 设置用于笔触(描边)的颜色,渐变和模式。

两者语法类似:

ctx.fillStyle = color;
ctx.fillStyle = gradient;
ctx.fillStyle = pattern;
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值