canvas实现弹性绳子手掌反重力交互效果代码
代码语言:html
所属分类:动画
代码描述:canvas实现弹性绳子手掌反重力交互效果代码,试试用鼠标抓住两个手掌。
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> html, body { width: 100%; height: 100%; overflow: hidden; touch-action: none; cursor: none; } </style> </head> <body> <!-- partial:index.partial.html --> <canvas id="canvas"></canvas> <!-- partial --> <script > function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;} function lerp(a, b, n) { return (1 - n) * a + n * b; } //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡/ // Canvas //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡*/ class Canvas { constructor({ canvas, entities = [], pointer }) {_defineProperty(this, "setCanvasSize", () => { const { innerWidth: w, innerHeight: h } = window; const w2 = w * this.dpr; const h2 = h * this.dpr; this.canvas.width = w2; this.canvas.height = h2; this.canvas.style.width = w + 'px'; this.canvas.style.height = h + 'px'; this.bounds = new Bounds(0, 0, w2, h2); });_defineProperty(this, "addEntity", newEntity => { this.entities = [...this.entities, newEntity]; return this.entities.length - 1; });_defineProperty(this, "render", () => { // Main loop // Draw and Update items here. this.entities.forEach(({ draw, update }) => { draw(this); update(this); }); ++this.tick; window.requestAnimationFrame(this.render); }); // setup a canvas this.canvas = canvas;this.dpr = window.devicePixelRatio || 1;this.ctx = canvas.getContext('2d');this.ctx.scale(this.dpr, this.dpr); // tick counter this.tick = 0; // entities to be drawn on the canvas this.entities = entities; // track mouse/touch movement this.pointer = pointer || null; // setup and run this.setCanvasSize();this.setupListeners();this.render();}setupListeners() {window.addEventListener('resize', this.setCanvasSize);}removeEntity(deleteIndex) {this.entities = this.entities.filter((el, i) => i !== deleteIndex);return this.entities;}} //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡/ // Entity //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡*/ class Entity {constructor() {_defineProperty(this, "dpr", window.devicePixelRatio || 1);_defineProperty(this, "toValue", value => value * this.dpr);_defineProperty(this, "draw", () => {});_defineProperty(this, "update", () => {});}} //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡/ // Background //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡*/ class Background extends Entity { constructor({ color }) { super();_defineProperty(this, "draw", context => { this.drawBg(context); });this.color = color;}drawBg({ ctx, canvas, bounds }) {ctx.fillStyle = this.color;ctx.fillRect(...bounds.params);}} //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡/ // Cursor //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡*/ class Cursor extends Entity { constructor({ color, radius }) { super();_defineProperty(this, "draw", ({ ctx, pointer }) => { ctx.strokeStyle = this.strokeStyle; ctx.lineWidth = this.lineWidth; ctx.beginPath(); ctx.arc( pointer.position.x, pointer.position.y, this.radius, 0, this.pi2, true); ctx.closePath(); ctx.stroke(); });this.radius = this.toValue(radius);this.pi2 = Math.PI * 2;this.lineWidth = this.toValue(2);this.strokeStyle = color;}} //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡/ // Pointer //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡*/ class Pointer { constructor() {_defineProperty(this, "update", ({ tick }) => { this.modifier && this.modifier(this, tick); });this.dpr = window.devicePixelRatio || 1;this.delta;this.lastPosition = null;this.position = new Point(null, null);this.addListeners();}delta() {return this.position.delta(this.lastPosition);}addListeners() {['mousemove', 'touchmove'].forEach((event, touch) => {window.addEventListener(event, e => {// move previous point const { x: px, y: py } = this.position; // disable the demo modifier if it's been added if (this.modifier) {this.modifier = null;}if (touch) {e.preventDefault();const x = e.targetTouches[0].clientX * this.dpr;const y = e.targetTouches[0].clientY * this.dpr;if (!this.lastPosition) {this.lastPosition = new Point(x, y);} else {this.lastPosition.moveTo(px, py);}this.position.moveTo(x, y);} else {const x = e.clientX * this.dpr;const y = e.clientY * this.dpr;if (!this.lastPosition) {this.lastPosition = new Point(x, y);} else {this.lastPosition.moveTo(px, py);}this.position.moveTo(x, y);}}, false);});}addPointerModifier(modifier) {this.modifier = modifier;}} //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡/ // Point //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡*/ class Point { constructor(x, y) { this.x = x; this.y = y; } get position() { return [this.x, this.y]; } clone() { return new Point(this.x, this.y); } delta(point) { return [this.x - point.x, this.y - point.y]; } distance(point) { const dx = point.x - this.x; const dy = point.y - this.y; return Math.sqrt(dx * dx + dy * dy); } moveTo(x, y) { this.x = x; this.y = y; return this; } move(x, y) { this.x += x; this.y += y; return this; } moveAtAngle(angle, distance) { this.x += Math.cos(angle) * distance; this.y += Math.sin(angle) * distance; return this; } applyVelocity(velocity) { this.x += velocity.vx; this.y += velocity.vy; return this; } angleRadians(point) { // radians = atan2(deltaY, deltaX) const y = point.y - this.y; const x = point.x - this.x; return Math.atan2(y, x); } angleDeg(point) { // degrees = atan2(deltaY, deltaX) * (180 / PI) const y = point.y - this.y; const x = point.x - this.x; return Math.atan2(y, x) * (180 / Math.PI); } rotate(origin, radians) { // rotate the point around a given origin point const cos = Math.cos(radians); const sin = Math.sin(radians); this.x = cos * (this.x - origin.x) + sin * (this.y - origin.y) + origin.x; this.y = cos * (this.y - origin.y) - sin * (this.x - origin.x) + origin.y; return this; }} //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡/ // PointPhysics //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡*/ const DPR = window.devicePixelRatio || 1; const MOUSE_STRENGTH = 0.25; // 0 - 1 const MOUSE_RADIUS = 100 * DPR; class PointPhysics extends Point { constructor({ x: _x, y: _y, mass, isFixed }) { super(_x, _y);_defineProperty(this, "update", ({ pointer, tick }) => { if (this.isFixed) return; this.applyForceFromMouse(pointer); this.solveVelocity(); });_defineProperty(this, "draw", ({ ctx }) => { const { x, y } = this; ctx.fillStyle = 'white'; ctx.lineWidth = 5; ctx.fillRect(x - 2, y - 2, 4, 4); ctx.beginPath(); ctx.arc(x, y, 4, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); });this.vx = 0; // velocity x this.vy = 0; // velocity y this.fx = 0; // force x this.fy = 0; // force y this.mass = mass;this.isFixed = isFixed;}applyForce(x, y) {this.fx += x;this.fy += y;}applyForceFromMouse(pointer) {const distance = this.distance(pointer.position);if (distance < MOUSE_RADIUS) {const [dx, dy] = pointer.delta();const power = (1 - distance / MOUSE_RADIUS) * MOUSE_STRENGTH;this.applyForce(dx * power, dy * power);}}solveVelocity() {if (this.fx === 0 && this.fy === 0) return; // acceleration = force / mass; const ax = this.fx / this.mass;const ay = this.fy / this.mass; // velocity + acceleration this.vx += ax;this.vy += ay;this.x += this.vx;this.y += this.vy; // reset any applied forces this.fx = 0;this.fy = 0;}} //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡/ // Body //*‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡*/ class Arm extends Entity {constructor({ width, height, position, resolution, color, force, holeColor }) { super();_defineProperty(this, "drawShade", ({ ctx }) => { const g1 = this.spine[0]; const g2 = this.spine[1]; const dist = Math.floor(g1.distance(g2) / 2); const rad = g1.angleRadians(g2); const [dx, dy] = g1.delta(g2); let i = dist; while (i >= 0) { const n = i / dist; const x = lerp(g2.x, g1.x, n); const y = lerp(g2.y, g1.y, n); // ctx.fillStyle = 'red'; // ctx.fillRect(x, y, 2, 2); ctx.fillStyle = this.color; ctx.globalAlpha = 1; ctx.beginPath(); ctx.arc(x, y, this.width / 2, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); ctx.fillStyle = this.holeColor; ctx.globalAlpha = n; ctx.beginPath(); ctx.arc(x, y, this.width / 2, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); ctx.globalAlpha = 1; i--; } });_defineProperty(this, "draw", ({ ctx }) => { this.drawShade({ ctx }); ctx.strokeStyle = this.color; ctx.lineWidth = this.width; ctx..........完整代码请登录后点击上方下载按钮下载查看
网友评论0