Famous Engine Physics Collisions

244 views Asked by At

I am building a site which requires a physics engine. Having worked with a number of SPA apps i feel pretty confident with.

Unfortunately I am having trouble applying collision detection & walls to a physics simulation that famous has created.

You can see the editable example here.

https://staging.famous.org/examples/index.html?block=gravity3d&detail=false&header=false

What I would like to know is it possible to add collisions to the particles? I have tried this but it appears the collisions are not setup correctly. I was hoping someone has managed to do it successfully.

Thanks!

var FamousEngine = famous.core.FamousEngine;

var Camera = famous.components.Camera;

var DOMElement = famous.domRenderables.DOMElement;
var Gravity3D = famous.physics.Gravity3D;
var Gravity1D = famous.physics.Gravity1D;
var MountPoint = famous.components.MountPoint;
var PhysicsEngine = famous.physics.PhysicsEngine;
var Physics = famous.physics;
var Wall = famous.physics.Wall;
var Position = famous.components.Position;
var Size = famous.components.Size;
var Sphere = famous.physics.Sphere;
var Vec3 = famous.math.Vec3;
var Collision = famous.physics.Collision;

function Demo() {
  this.scene = FamousEngine.createScene('#socialInteractive');

  this.camera = new Camera(this.scene);
  this.camera.setDepth(1000);

  this.simulation = new PhysicsEngine();
  this.items = [];

  this.collision = new Collision();

  var Wall = famous.physics.Wall;
  var rightWall = new Wall({
    direction: Wall.LEFT
  }); // bodies coming from the left will collide with the wall
  rightWall.setPosition(1000, 0, 0);

  var ceiling = new Wall({
    normal: [0, 1, 0],
    distance: 300,
    restitution: 0
  });
  var floor = new Wall({
    normal: [0, -1, 0],
    distance: 300,
    restitution: 0
  });
  var left = new Wall({
    normal: [1, 0, 0],
    distance: 350,
    restitution: 0
  });
  var right = new Wall({
    normal: [-1, 0, 0],
    distance: 350,
    restitution: 0
  });
  var node = this.scene.addChild();
  var position = new Position(node);
  // this.simulation.attach([right, left, floor, ceiling])
  // this.items.push([ceiling,position]);


  for (var i = 0; i < 10; i++) {
    var node = this.scene.addChild();
    var size = new Size(node).setMode(1, 1);
    var position = new Position(node);
    if (i === 0) {
      createLogo.call(this, node, size, position);
    }
    if (i !== 0) {
      node.id = i;
      createSatellites.call(this, node, size, position);
    }
  }
  FamousEngine.requestUpdateOnNextTick(this);
  console.log(this.collision)
  for (var i = 0; i < this.collision.length; i++) {
    this.simulation.attach(collision, balls, balls[i]);
  }
  this.simulation.addConstraint(this.collision);
}

Demo.prototype.onUpdate = function(time) {
  this.simulation.update(time);
  this.collision.update(time, 60);
  if (this.items.length > 0) {
    for (var i = 0; i < this.items.length; i++) {
      var itemPosition = this.simulation.getTransform(this.items[i][0]).position;
      this.items[i][1].set(itemPosition[0], itemPosition[1], 0);
    }
  }
  FamousEngine.requestUpdateOnNextTick(this);
};

function createLogo(node, size, position) {
  size.setAbsolute(50, 50);
  var mp = new MountPoint(node).set(0.5, 0.5);
  var el = new DOMElement(node, {
    tagName: 'img',
    attributes: {
      src: './images/famous-logo.svg'
    }
  });
  var sphere = new Sphere({
    radius: 100,
    mass: 10000,
    restrictions: ['xy'],
    position: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 5)
  });

  this.gravity = new Gravity3D(sphere);
  this.simulation.add(sphere, this.gravity);
  this.items.push([sphere, position]);

}

function createSatellites(node, size, position, i) {
  size.setAbsolute(20, 20);
  var radius = 200;
  var x = Math.floor(Math.random() * radius * 2) - radius;
  var y = (Math.round(Math.random()) * 2 - 1) * Math.sqrt(radius * radius - x * x);
  var color = 'rgb(' + Math.abs(x) + ',' + Math.abs(Math.round(y)) + ',' + (255 - node.id) + ')';
  var el = new DOMElement(node, {
    properties: {
      'background-color': color,
      'border-radius': '50%'
    }
  });
  var satellite = new Sphere({
    radius: 20,
    mass: 5,
    position: new Vec3(x + window.innerWidth / 2, y + window.innerHeight / 2, 0)
  });
  satellite.setVelocity(-y / Math.PI, -x / Math.PI / 2, y / 2);
  this.gravity.addTarget(satellite);
  this.simulation.add(satellite);
  this.items.push([satellite, position]);
  this.collision.addTarget(satellite);

}

// Boilerplate
FamousEngine.init();

// App Code
var demo = new Demo();

1

There are 1 answers

0
MichaelBell On BEST ANSWER

Thanks for your help Talves, I think i found a solution that works with physics Spring instead of gravity3d. This also has the 4 walls included which seems to work well.

var famous = famous;
var FamousEngine = famous.core.FamousEngine;

var Camera = famous.components.Camera;


var DOMElement = famous.domRenderables.DOMElement;
var Gravity3D = famous.physics.Gravity3D;
var MountPoint = famous.components.MountPoint;
var PhysicsEngine = famous.physics.PhysicsEngine;
var Position = famous.components.Position;
var Size = famous.components.Size;
var Wall = famous.physics.Wall;
var Sphere = famous.physics.Sphere;
var Vec3 = famous.math.Vec3;
var math = famous.math;
var physics = famous.physics;
var collision = famous.physics.Collision;
var gestures = famous.components.GestureHandler;
var Spring = famous.physics.Spring;
console.log(famous)
var anchor = new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0);

//Create Walls
var rightWall = new Wall({
  direction: Wall.LEFT
}).setPosition(window.innerWidth - 20, 0, 0);
var leftWall = new Wall({
  direction: Wall.RIGHT
}).setPosition(window.innerWidth + 20, 0, 0);
var topWall = new Wall({
  direction: Wall.DOWN
}).setPosition(0, 20, 0);
var bottomWall = new Wall({
  direction: Wall.UP
}).setPosition(0, window.innerHeight - 20, 0);

function Demo() {
  this.scene = FamousEngine.createScene('body');

  this.camera = new Camera(this.scene);
  this.camera.setDepth(1000);

  this.collision = new collision([rightWall, leftWall, topWall, bottomWall]);

  this.simulation = new PhysicsEngine();
  this.simulation.setOrigin(0.5, 0.5);
  this.simulation.addConstraint(this.collision);

  this.items = [];
  this.walls = [];


  //Create Items
  for (var i = 0; i < 30; i++) {
    var node = this.scene.addChild();
    node.setMountPoint(0.5, 0.5);
    var size = new Size(node).setMode(1, 1);
    var position = new Position(node);
    if (i === 0) {
      createLogo.call(this, node, size, position);
    }
    if (i !== 0) {
      node.id = i;
      createSatellites.call(this, node, size, position);
    }
  }

  //Create Walls
  var node = this.scene.addChild();
  createWalls(node);

  FamousEngine.requestUpdateOnNextTick(this);

  Demo.prototype.onUpdate = function(time) {
    this.simulation.update(time);

    //Postition walls
    var wallPosition = topWall.getPosition();
    node.setPosition(wallPosition.x, wallPosition.y);

    //Position elements
    if (this.items.length > 0) {
      for (var i = 0; i < this.items.length; i++) {
        var itemPosition = this.simulation.getTransform(this.items[i][0]).position;
        this.items[i][1].set(itemPosition[0], itemPosition[1], 0);
      }
    }

    FamousEngine.requestUpdateOnNextTick(this);
  };
}

function createWalls(wallNode) {
  wallNode.setSizeMode('absolute', 'absolute', 'absolute').setAbsoluteSize(window.innerWidth, 10, 0);
  var wallDOMElement = new DOMElement(wallNode, {
    tagName: 'div'
  }).setProperty('background-color', 'lightblue');
}

function createLogo(node, size, position) {
  size.setAbsolute(50, 50);
  var mp = new MountPoint(node).set(0.5, 0.5);
  var el = new DOMElement(node, {
    tagName: 'img',
    attributes: {
      src: './images/famous_logo.png'
    }
  });
  var sphere = new Sphere({
    radius: 100,
    mass: 10000,
    restrictions: ['xy'],
    position: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 5)
  });

  // this.gravity = new Gravity3D(sphere);
  // this.simulation.add(sphere, this.gravity);
  this.simulation.add(sphere);
  this.items.push([sphere, position]);
}

function createSatellites(node, size, position, i) {
  size.setAbsolute(50, 50);
  var radius = 100;
  var x = Math.floor(Math.random() * radius * 2) - radius;
  var y = (Math.round(Math.random()) * 2 - 1) * Math.sqrt(radius * radius - x * x);
  var color = 'rgb(' + Math.abs(x) + ',' + Math.abs(Math.round(y)) + ',' + (255 - node.id) + ')';
  var el = new DOMElement(node, {
    properties: {
      'background-color': color,
      'border-radius': '50%'
    }
  });
  var satellite = new Sphere({
    radius: 25,
    mass: 10,
    position: new Vec3(x + window.innerWidth / 2, y + window.innerHeight / 2, 0)
  });

  // Attach the box to the anchor with a `Spring` force
  var spring = new Spring(null, satellite, {
    stiffness: 95,
    period: 0.6,
    dampingRatio: 1.0,
    anchor: anchor
  });

  //console.log(color);
  // satellite.setVelocity(-y / Math.PI, -x / Math.PI / 2, y / 2);
  satellite.setVelocity(0.5, 0.5, 0);
  // this.gravity.addTarget(satellite);
  this.simulation.add(satellite, spring);
  this.items.push([satellite, position]);
  this.collision.addTarget(satellite);

}

// Boilerplate
FamousEngine.init();

// App Code
var demo = new Demo();
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Famous :: Seed Project</title>
        <link rel="icon" href="favicon.ico?v=1" type="image/x-icon">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
            html, body {
                width: 100%;
                height: 100%;
                margin: 0px;
                padding: 0px;
            }
            body {
                position: absolute;
                -webkit-transform-style: preserve-3d;
                transform-style: preserve-3d;
                -webkit-font-smoothing: antialiased;
                -webkit-tap-highlight-color: transparent;
                -webkit-perspective: 0;
                perspective: none;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
        <script src="http://code.famo.us/famous/0.6.2/famous.min.js"></script>
    </body>
</html>