top of page
Search
cedarcantab

verly objects



entity


import { v4 } from "uuid";
import Vector from "./Vector";

class Entity {
  /**
   * @param {number} iterations
   * @param {Verly} verlyInstance
   */
  constructor(iterations, verlyInstance, name) {
    this.points = [];
    this.sticks = [];
    this.domNodes = [];
    this.name = name;
    this.verlyInstance = verlyInstance;
    this.iterations = iterations || 16;
  }

  /**
   * @param {HTMLElement} node
   * @param {typeof import('./Vector')} p
   */
  updateDOMNodePosition(node, p) {
    if (!node) return;
    node.style.left = `${p.pos.x}px`;
    node.style.top = `${p.pos.y - 1}px`;
  }

  findActiveFocusedNode() {
    let nodeId = document.activeElement.getAttribute("data-nodeid");
    if (!nodeId) return null;

    const foundNode = this.points.find((p) => p.uid === nodeId);
    if (!foundNode) return null;

    return foundNode;
  }

  /**
   * @param {KeyboardEvent} event
   */
  handleKeyDown(event) {
    const foundNode = this.findActiveFocusedNode();
    if (!foundNode) return;

    const isFaster = !!event.shiftKey;
    const velocityMultiplier = isFaster ? 5 : 1;
    const keyMap = {
      ArrowLeft: () => {
        this.setVelocityToPoint(foundNode, -velocityMultiplier, 0);
      },
      ArrowRight: () => {
        this.setVelocityToPoint(foundNode, velocityMultiplier, 0);
      },
      ArrowUp: () => {
        this.setVelocityToPoint(foundNode, 0, -velocityMultiplier);
      },
      ArrowDown: () => {
        this.setVelocityToPoint(foundNode, 0, velocityMultiplier);
      },
    };

    if (keyMap[event.key]) {
      foundNode.pin();
      keyMap[event.key]();
    }
  }

  /**
   * @param {KeyboardEvent} event
   */
  handleKeyUp(event) {
    const foundNode = this.findActiveFocusedNode();
    if (!foundNode) return;

    foundNode.resetVelocity();
    if (event.key === ' ') {
      foundNode.unpin()
    }
  }

  setupAccessibility() {
    window.addEventListener("keydown", this.handleKeyDown.bind(this));
    window.addEventListener("keyup", this.handleKeyUp.bind(this));
    this.points.forEach((p, i) => {
      let node = document.createElement("div");
      node.tabIndex = 0;
      node.setAttribute("data-nodeid", p.uid);
      node.setAttribute("aria-label", `Point of ${this.name}, use arrow keys to move point, press space to unpin`);
      node.classList.add("point");
      this.updateDOMNodePosition(node, p);
      document.body.appendChild(node);
      this.domNodes.push(node);
    });
  }

  /**
   * sets the gravity of this entity
   * @param {Vector} g
   */
  setGravity(g) {
    for (let i = 0; i < this.points.length; i++) {
      this.points[i].setGravity(g);
    }
  }

  /**
   * sets the friction of this entity
   * @param {number} f
   */
  setFriction(f) {
    for (let i = 0; i < this.points.length; i++) {
      this.points[i].setFriction(f);
    }
  }

  /**
   * pin a specific Point
   * @param {number} index
   */
  pin(index) {
    this.points[index].pin();
  }

  /**
   * remove a specific Point
   * @param {Point} p
   */
  removeSticks(p) {
    this.sticks.splice(this.sticks.indexOf(p.sticks[0]), 1);
    p.sticks.splice(0, 1);
  }

  /**
   *
   * @param {typeof import('./Point').default} point
   * @param {Number} x
   * @param {Number} y
   */
  setVelocityToPoint(point, x, y) {
    point.applyForce(new Vector(x, y));
  }

  /**
   *
   * @param {Number} x
   * @param {Number} y
   */
  setVelocity(x, y) {
    this.points.map((e) => {
      e.oldpos.x += x;
      e.oldpos.y += y;
    });
  }

  /**
   * adds a Point in points array with {x,y,vx,vy,radius}
   * @param {Number|Point} x
   * @param {Number=} y
   * @param {Number=} vx
   * @param {Number=} vy
   * @param {Number=} radius
   * @returns {Point}
   */
  addPoint(x, y, vx, vy, radius) {
    let uid = v4();
    let p;
    if (x instanceof Point) {
      p = x;
    } else {
      p = new Point(x, y, vx, vy, radius);
    }
    p.uid = uid;
    this.points.push(p);
    return p;
  }

  /**
   * adds a stick inbetween two points
   * @param {number|Point} p1
   * @param {number|Point=} p2
   * @param {number=} length
   * @param {number=} stiffness
   * @param {boolean=} ishidden
   */
  addStick(p1, p2, length, stiffness, ishidden) {
    let stick;
    if (p1 instanceof Stick) {
      stick = p1;
    } else {
      stick = new Stick(
        this.points[p1],
        this.points[p2],
        length,
        stiffness,
        ishidden
      );
    }
    this.sticks.push(stick);
    return stick;
  }

  /**
   * adds a AngleStick in between 3 points
   * @param {Point} p1
   * @param {Point} p2
   * @param {Point} p3
   * @param {number} stiffness
   * @returns {AngleStick}
   */
  addAngleStick(p1, p2, p3, stiffness) {
    let stick;
    if (p1 instanceof AngleStick) {
      stick = p1;
    } else {
      stick = new AngleStick(
        this.points[p1],
        this.points[p2],
        this.points[p3],
        stiffness
      );
    }
    this.sticks.push(stick);
    return stick;
  }

  /**
   *
   */
  updatePoints() {
    for (let i = 0; i < this.points.length; i++) {
      this.points[i].update(this.verlyInstance);
      this.updateDOMNodePosition(this.domNodes[i], this.points[i]);
    }
  }

  /**
   * @methdo updateSticks
   * @param {Number=} stepCoef
   */
  updateSticks(stepCoef) {
    for (let i = 0; i < this.sticks.length; i++) {
      this.sticks[i].update(stepCoef);
    }
  }

  /**
   */
  updateConstraints() {
    for (let i = 0; i < this.points.length; i++) {
      this.points[i].constrain(this.verlyInstance);
    }
  }

  /**
   */
  update() {
    // var stepCoef = 1 / this.iterations;
    this.updatePoints();
    for (let j = 0; j < this.iterations; ++j) {
      this.updateSticks();
      this.updateConstraints();
    }
  }

  /**
   */
  renderPoints() {
    for (let i = 0; i < this.points.length; i++) {
      this.points[i].render(this.verlyInstance.ctx);
    }
  }

  /**
   */
  renderSticks() {
    for (let i = 0; i < this.sticks.length; i++) {
      this.sticks[i].render(this.verlyInstance.ctx);
    }
  }

  /**
   */
  renderPointIndex() {
    for (let i = 0; i < this.points.length; i++) {
      this.verlyInstance.ctx.beginPath();
      this.verlyInstance.ctx.fillStyle = "black";
      this.verlyInstance.ctx.fillText(
        i,
        this.points[i].pos.x + 5,
        this.points[i].pos.y - 6
      );
      this.verlyInstance.ctx.closePath();
    }
  }

  /**
   */
  render() {
    this.renderPoints();
    this.renderSticks();
  }
}

export default Entity;

// join(...args) {
//   let points = [];
//   let sticks = [];

//   // loop through the args and push points and sticks to the array
//   for (let i = 0; i < args.length; i++) {
//     points.push(args[i].points);
//     sticks.push(args[i].sticks);
//   }

//   // join multiple arrays
//   points = [].concat.apply([], points);
//   sticks = [].concat.apply([], sticks);

//   // add the arrays to the mix::Entity
//   this.points = points;
//   this.sticks = sticks;

//   return this; // return for chaining
// }

box


class Box extends Entity {
  constructor(x, y, width, height, interation, verlyInstance) {
    super(interation, verlyInstance);
    this.x = x;
    this.y = y;
    // this.x = x;
    // this.y = y;
    this.width = width;
    this.height = height;

    // this._box = new Entity(16);
    this.addPoint(this.x, this.y, 0, 0);
    this.addPoint(this.x + this.width, this.y, 0, 0);
    this.addPoint(this.x + this.width, this.y + this.height, 0, 0);
    this.addPoint(this.x, this.y + this.height, 0, 0);
    this.addStick(0, 1);
    this.addStick(1, 2);
    this.addStick(2, 3);
    this.addStick(3, 0);
    this.addStick(3, 1);
  
  }
}

0 views0 comments

Recent Posts

See All

p2 naive broadphase

var Broadphase = require('../collision/Broadphase'); module.exports = NaiveBroadphase; /** * Naive broadphase implementation. Does N^2...

sopiro motor constranit

import { Matrix2, Vector2 } from "./math.js"; import { RigidBody } from "./rigidbody.js"; import { Settings } from "./settings.js";...

Comments


記事: Blog2_Post
bottom of page