canvas实现鼠标跟随模拟物理绳子甩动交互效果代码

代码语言:html

所属分类:其他

代码描述:canvas实现鼠标跟随模拟物理绳子甩动交互效果代码

代码标签: canvas 鼠标 跟随 模拟 物理 绳子 甩动 交互

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
 
  
  
<style>
body{
  background-color:#1A1B1F;
}

#container{
  max-width:800px;
  height:480px;
  background-color:black;
  margin: 0 auto;
  -webkit-box-sizing::border-box;
  border-style: solid;
  border-color: white;
}

#container p{
  color:white;
  margin-left:25px;
}
</style>


  
  
</head>


<body>
  <div id="container">
    <canvas id="canvas" width="800" height="480"></canvas>
   <p>Verlet Physics Rope (move the mouse!)</p>
  </div>

  
      <script >
//A small scaffold specifically to help me design code pen interactions

//Math extensions
Math.lerp = (first, second, percentage) => {
  return first + (second - first) * percentage;
};

Math.clamp = (value, min, max) => {
  return value < min ? min : value > max ? max : value;
};

class Vector2 {
  static zero() {
    return { x: 0, y: 0 };
  }

  static sub(a, b) {
    return { x: a.x - b.x, y: a.y - b.y };
  }

  static add(a, b) {
    return { x: a.x + b.x, y: a.y + b.y };
  }

  static mult(a, b) {
    return { x: a.x * b.x, y: a.y * b.y };
  }

  static scale(v, scaleFactor) {
    return { x: v.x * scaleFactor, y: v.y * scaleFactor };
  }

  static mag(v) {
    return Math.sqrt(v.x * v.x + v.y * v.y);
  }

  static normalized(v) {
    const mag = Vector2.mag(v);

    if (mag === 0) {
      return Vector2.zero();
    }
    return { x: v.x / mag, y: v.y / mag };
  }}


class App {
  constructor(
  window,
  canvas,
  context,
  updateHandler,
  drawHandler,
  frameRate = 60)
  {
    this._window = window;
    this._canvas = canvas;
    this._context = context;
    this._updateHandler = updateHandler;
    this._drawHandler = drawHandler;
    this._frameRate = frameRate;
    this._lastTime = 0;
    this._currentTime = 0;
    this._deltaTime = 0;
    this._interval = 0;
    this.onMouseMoveHandler = (x, y) => {};
    this.onMouseDownHandler = (x, y) => {};
    this.start = this.start.bind(this);
    this._onMouseEventHandlerWrapper = this._onMouseEventHandlerWrapper.bind(
    this);

    this._onRequestAnimationFrame = this._onRequestAnimationFrame.bind(this);
  }

  start() {
    this._lastTime = new Date().getTime();
    this._currentTime = 0;
    this._deltaTime = 0;
    this._interval = 1000 / this._frameRate;

    this._canvas.addEventListener(
    "mousemove",
    e => {
      this._onMouseEventHandlerWrapper(e, this.onMouseMoveHandler);
    },
    false);


    this._canvas.addEventListener(
    "mousedown",
    e => {
      this._onMouseEventHandlerWrapper(e, this.onMouseDownHandler);
    },
    false);


    this._onRequestAnimationFrame();
  }

  _onMouseEventHandlerWrapper(e, callback) {
    let element = this._canvas;
    let offsetX = 0;
    let offsetY = 0;

    if (element.offsetParent) {
      do {
        offsetX += element.offsetLeft;
        offsetY += element.offsetTop;
      } while (element = element.offsetParent);
    }

    const x = e.pageX - offsetX;
    const y = e.pageY - offsetY;

    callback(x, y);
  }

  _onRequestAnimationFrame() {
    this._window.requestAnimationFrame(this._onRequestAnimationFrame);

    this._currentTime = new Date().getTime();
    this._deltaTime = this._currentTime - this._lastTime;

    if (this._deltaTime > this._interval) {

      //delta time in seconds
      const dts = this._deltaTime * 0.001;

      this._updateHandler(dts);

      this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
      this._drawHandler(this._canvas, this._context, dts);

      this._lastTime = this._currentTime - this._deltaTime % this._interval;
    }
  }}


//each rope part is one of these
//uses a high precison varient of Störmer–Verlet integration
//to keep the simulation consistant otherwise it would "explode"!
class RopePoint {
  //integrates motion equations per node without taking into account relationship
  //with other nodes...
  static integrate(point, gravity, dt, previousFrameDt) {
    point.velocity = Vector2.sub(point.pos, point.oldPos);
    point.oldPos = { ...point.pos };

    //drastically improves stability
    let timeCorrection = previousFrameDt != 0.0 ? dt / previousFrameDt : 0.0;

    let accel = Vector2.add(gravity, { x: 0, y: point.mass });

    const velCoef = timeCorrection * point.damping;
    const accelCoef = Math.pow(dt, 2);

    point.pos.x += point.velocity.x * velCoef + accel.x * accelCoef;
    point.pos.y += point.velocity.y * velCoef + accel.y * accelCoef;
  }

  //apply constraints related to other nodes next to it
  //(keeps each node within distance)
  static constrain(point) {
    if (point.next) {
      const delta = Vector2.sub(point.next.pos, point.pos);
     .........完整代码请登录后点击上方下载按钮下载查看

网友评论0