canvas实现弹性绳子手掌反重力交互效果代码

代码语言:html

所属分类:动画

代码描述:canvas实现弹性绳子手掌反重力交互效果代码,试试用鼠标抓住两个手掌。

代码标签: 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