Kros的博客 Kros的博客
首页
  • CSS
  • 工具
  • Vue
  • js
  • Vue3
  • 算法
  • 折腾笔记
一言
  • 分类
  • 标签
  • 归档
码云

Kros

凡心所向,素履以往,生如逆旅,一苇以航
首页
  • CSS
  • 工具
  • Vue
  • js
  • Vue3
  • 算法
  • 折腾笔记
一言
  • 分类
  • 标签
  • 归档
码云
  • CSS

  • JavaScript

    • 兼容ie7的水平无限滚动
    • 节流防抖
    • 数组乱序
    • 开启全屏
    • 数据类型
    • 变量提升
    • this调用指向
    • 原型及原型扩展
    • js获取元素属性精度问题
    • setTimeout和setInterval
    • 数组判断
    • dom节点添加或插入元素
    • var、let和const的区别
    • 判断ellipsis是否省略生效
    • 使用ResizeObserver监听元素size变化
    • js自定义事件
    • use strict详解
    • 私有属性
    • js实现类的方式
    • call和apply的理解和使用
    • js失焦和点击事件顺序冲突
    • js中不常见但非常实用的运算符
    • for of和for in的区别
    • defer和async的区别
    • promise值穿透
    • js为什么会出现数字精确度丢失
    • js禁用F12开发者模式
    • 使用scrollTop和scrollTo滚动到目标位置
    • js实现打字机效果
    • 多种方式实现数组去重
    • 替换使用setTimeout
    • encodeURI和encodeURIComponent的区别
    • canvas实现弹跳小球
    • js实现跨标签页通信
    • 事件循环与微任务、宏任务
    • 浏览器存储数据方式
    • 常见的meta元数据使用
    • 使用InterSectionObserver判断元素区域(chatGPT)
  • 工具

  • Vue

  • antdv踩坑记录

  • Vue3

  • 前端
  • JavaScript
kros
2025-08-14

canvas实现弹跳小球

ball

实现步骤:

  1. 获取canvas对象,初始相应对象数据
  2. 清空画布
  3. x、y方向移动单位距离dx、dy
  4. 边界检测,超出边界则当前方向dx或dy方向
  5. 根据当前x、y绘制圆形图形和阴影
  6. 重复2-5步骤

实现代码如下:

<canvas id="canvas"></canvas>

<style>
canvas {
  width: 500px;
  height: 300px;
  border: 1px solid red;
}
</style>
1
2
3
4
5
6
7
8
9
// 初始化canvas
const canvas = document.getElementById('canvas');
const ctx     = canvas.getContext('2d');

canvas.width  = 500;
canvas.height = 300;

/* ========= 小球类 ========= */
class Ball {
  constructor(w, h) {
		// 半径
    this.radius = Math.max(10, Math.floor(Math.random() * 20)); 
		// 初始化随机x位置
    this.x      = Math.max(this.radius, Math.random() * (w - this.radius));
		// 初始化随机x位置
    this.y      = Math.random() * (h - this.radius);
		// x方向单位移动距离
    this.dx     = (Math.round(Math.random() * 10) - 5) || 1;
		// y方向单位移动距离
    this.dy     = -this.dx;
		// 随机颜色
    this.color  = [Math.floor(Math.random() * 255), Math.floor(Math.random() * 255), Math.floor(Math.random() * 255)];
  }

  draw() {
		// 阴影
		ctx.shadowColor = `rgba(${this.color}, 0.5)`;
		ctx.shadowOffsetX = this.radius / 3 * -this.dx / Math.abs(this.dx); 
		ctx.shadowOffsetY = this.radius / 3 * -this.dy / Math.abs(this.dy);
		ctx.shadowBlur = this.radius / 2;
		
		// 绘制图形
		ctx.beginPath();
		ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
		ctx.fillStyle = `rgb(${this.color})`;
		ctx.fill();
		ctx.closePath();
  }

  /* 根据速度移动并检测边界反弹 */
  update() {
    this.x += this.dx;
    this.y += this.dy;

    // 水平边界
    if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {
      this.dx = -this.dx;
    }
    // 垂直边界
    if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {
      this.dy = -this.dy;
    }
  }
}

/* ========= 动画管理类 ========= */
class Stage {
  constructor(canvas) {
    this.canvas = canvas;
    this.width  = this.canvas.width;
    this.height = this.canvas.height;
    this.ctx    = canvas.getContext('2d');
    this.children = [];        // 存放所有可绘制/可更新的对象
  }

  /* 把对象加入舞台 */
  add(child) {
    this.children.push(child);
  }

  /* 清空画布 */
  clear() {
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  }

  /* 渲染并进入下一帧 */
  render() {
    this.clear();
    this.children.forEach(child => {
      child.update();
      child.draw();
    });
    requestAnimationFrame(() => this.render());
  }

  /* 启动动画 */
  start() {
    this.render();
  }
}

/* ========= 初始化 ========= */
const stage = new Stage(canvas);

// 添加随机小球
stage.add(new Ball(stage.width, stage.height));
stage.add(new Ball(stage.width, stage.height));

// 开始动画
stage.start();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
上次更新: 2025/09/05, 8:09:00
encodeURI和encodeURIComponent的区别
js实现跨标签页通信

← encodeURI和encodeURIComponent的区别 js实现跨标签页通信→

最近更新
01
Find the next perfect square
09-05
02
Regex validate PIN code
09-05
03
Find the odd int
09-05
更多文章>
Theme by Vdoing | Copyright © 2020-2025 kros king
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
icon-heart-o icon-heart icon-infinity icon-pause icon-play link next prev