lover-fish
  • Introduction
  • 搭建环境
  • 绘制背景
  • 绘制海葵
  • 绘制果实
  • 果实动画
  • 控制果实的数量
  • 增加果实的类型
  • 绘制鱼
  • 让鱼动起来
  • 让鱼跟着鼠标动起来
  • 吃果实之碰撞检测
  • 创建鱼宝宝
  • 给鱼添加动画
  • 加入计分模块
  • 大鱼身体特效
  • 游戏结束逻辑
  • 增加吃果实特效
  • 海葵动画
  • 漂浮物
Powered by GitBook
On this page

让鱼动起来

鱼动起来的原理就是通过设置鱼的坐标来实现,而设置什么值呢?

很明显,我们是通过移动鼠标来控制鱼,那当然是我们鼠标的坐标。

在 init.ts 里面声明俩个变量来保存我们的鼠标坐标,并且通过监听我们的鼠标移动事件,来获得我们鼠标的坐标。

  • 声明变量

let mouse_x: number, // 鱼的x坐标,和鼠标x的坐标
    mouse_y: number; // 鱼的y坐标,和鼠标y的坐标,因为鼠标在哪鱼在哪,所以重合。
  • 创建监听函数

这里的 offset 会比 layer 大 1

// 鼠标移动监听函数
function mouseMove(e: MouseEvent) {

  // offset = layer + 1

  if(e.offsetX || e.layerX) {
    mouse_x = typeof e.offsetX == undefined ? e.layerX : e.offsetX
    mouse_y = typeof e.offsetY == undefined ? e.layerY : e.offsetY
  }

  console.log(mouse_x);
  console.log(mouse_y);
}
  • 修改 init 函数,为 canvas one 添加事件监听

function init() {
  [cvs_one, ctx_one] = getCanvasAndContextById('one');
  [cvs_two, ctx_two] = getCanvasAndContextById('two');

  bgPic.src = 'assets/img/background.jpg';

  cvs_width = cvs_one.width;
  cvs_height = cvs_one.height;

  anemones = new Anemones()
  fruits = new Fruits()
  fish_mother = new FishMother()

  mouse_x = cvs_width / 2; // 先把鱼初始化在画布的中间
  mouse_y = cvs_height / 2;

  // 因为鱼是在 canvas one 上面,所以把监听添加到 one 上面
  cvs_one.addEventListener('mousemove', mouseMove, false);

}
  • 添加导出

export {
  bgPic,
  cvs_width,
  cvs_height,
  cvs_one,
  cvs_two,
  ctx_one,
  ctx_two,
  anemones,
  fruits,
  fish_mother,
  mouse_x,
  mouse_y
};
  • 在 fish-mother.ts 使用坐标,首先先导入。

import { ctx_one, cvs_height, cvs_width, mouse_x, mouse_y } from "./init";
  • 更新 draw 函数

  draw(){

    this.x = mouse_x
    this.y = mouse_y

    ctx_one.save();
    ctx_one.translate(this.x, this.y); // 定义相对定位的坐标中心点
    ctx_one.scale(.7, .7);
    ctx_one.drawImage(this.bigEye, -this.bigEye.width / 2, -this.bigEye.height / 2); // 居中,所以向左移动宽度的一半,向上移动宽度的一半
    ctx_one.drawImage(this.bigBody, -this.bigBody.width / 2, -this.bigBody.height / 2);
    ctx_one.drawImage(this.BigTail, -this.BigTail.width / 2 + 30, -this.BigTail.height / 2); // 这里的尾巴,往右移动30像素,让它在身体的后面。

    ctx_one.restore();

  }
  • 创建一个带有缓冲功能的函数

此时移动你的鼠标,你会发现这个鱼动的太硬了,完全贴着鼠标。

每一次设置值只是设置一个趋近于鼠标位置的值,这样就会有一个渐变的过程,就不会那么突然。

而不是直接就等于,当鼠标与鱼的位置重合时,lerpDistance 就返回的 aim

新建 utils.ts 文件

/**
 * 按照一定的 ratio 比率趋近于目标值,当目标值与当前值距离越大,他们相差就越大。
 * @param  {number} aim   目标值
 * @param  {number} cur   当前值
 * @param  {number} ratio 百分比
 * @return {number} 趋近于目标值的值
 */
function lerpDistance(aim: number, cur: number, ratio: number) : number {
  var delta = cur - aim; // 当前值与目标值的距离
  return aim + delta * ratio;
}

export default {
  lerpDistance
}

我们来模拟一下这个函数的运行环境。

第一帧时

cur: 20
aim: 10
ratio: 0.9

delta 10

return 19 = 10 + 10 * 0.9 

this.x = 19

第二帧,此时的 cur = 19

cur: 19
aim: 10

delta 9

return 18.1 = 10 + 9 * 0.9

第三帧,此时 cur = 18.1

此时只是无线趋近,而不是真正的等于。这里的3帧动画只是花了几十毫秒而已。

  • 在 fish-mother.ts 中使用这个函数

  draw(){

    this.x = utils.lerpDistance(mouse_x, this.x , .9)
    this.y = utils.lerpDistance(mouse_y, this.y , .9)

    // this.x = mouse_x
    // this.y = mouse_y

    ctx_one.save();
    ctx_one.translate(this.x, this.y); // 定义相对定位的坐标中心点
    ctx_one.scale(.7, .7);
    ctx_one.drawImage(this.bigEye, -this.bigEye.width / 2, -this.bigEye.height / 2); // 居中,所以向左移动宽度的一半,向上移动宽度的一半
    ctx_one.drawImage(this.bigBody, -this.bigBody.width / 2, -this.bigBody.height / 2);
    ctx_one.drawImage(this.BigTail, -this.BigTail.width / 2 + 30, -this.BigTail.height / 2); // 这里的尾巴,往右移动30像素,让它在身体的后面。

    ctx_one.restore();

  }

再次试一试,看看鱼儿是如何动起来的。

Previous绘制鱼Next让鱼跟着鼠标动起来

Last updated 7 years ago