Search code examples
javascriptgame-physicsfamous-engine

Famous Engine Bruteforce collisions


I have a famous engine setup and working with physics / drag etc.

But it appears there are other physics options, BruteForce, SweepAndPrune etc. I suspect these may be what i need to improve the collision detection between the elements.

I've tried to add the BruteForce collision detection like so: this.collision = new collision([rightWall, leftWall, topWall, bottomWall]);

But I get an error about an incorrect constraint. this.simulation.addConstraint(this.collision);

Does anyone have experience with solving this issue?

You can see a demo here:

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);

var centerPoint;

function Demo() {
  this.scene = FamousEngine.createScene('body');
  this.collision = new collision([rightWall, leftWall, topWall, bottomWall]);
  console.log(this.collision)
  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 < 10; 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 && i !== 9) {
      node.id = i;
      createSatellites.call(this, node, size, position);
    }
    if (i === 9) {
      node.id = i;
      createAlternateShape.call(this, node, size, position);

    }
  }

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

  var once = true;

  Demo.prototype.onUpdate = function(time) {
    this.simulation.update(time);
    this.collision.resolve(time, 360)

    //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++) {
        if (once) {
          console.log(this.items[i][1]._node.moving)
          once = false;
        }
        if (this.items[i][1]._node.moving) {
          console.log('moving!')
        } else {
          var itemPosition = this.simulation.getTransform(this.items[i][0]).position;
          this.items[i][1].set(itemPosition[0], itemPosition[1], 0);
        }


      }
    }

    FamousEngine.requestUpdateOnNextTick(this);
  };

  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) {
  node.moving = false;
  size.setAbsolute(100, 100);
  var mp = new MountPoint(node).set(0.5, 0.5);
  var el = new DOMElement(node, {
    tagName: 'img',
    attributes: {
      src: 'http://www.denisboudreau.org/presentations/2014/CSUN/Browser%20Zoom%20and%20Low%20Vision/Comps/ToM_EnsoCircle.png'
    }
  });
  centerPoint = new Sphere({
    radius: 50,
    mass: 10000,
    restrictions: ['xy'],
    position: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0)
  });

  var spring = new Spring(null, centerPoint, {
    stiffness: 95,
    period: 0.6,
    dampingRatio: 1.0,
    anchor: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0)
  });

  centerPoint.setVelocity(0, 0, 0);
  this.simulation.add(centerPoint, spring);
  this.items.push([centerPoint, position]);
  this.collision.addTarget(centerPoint);
}

function createAlternateShape(node, size, position) {
  node.moving = false;
  size.setAbsolute(100, 100);
  var el = new DOMElement(node, {
    properties: {
      'background-color': 'red',
    }
  });

  var box = new physics.Box({
    size: [100, 100, 100],
    mass: 10,
    position: new Vec3(100, 100, 0)
  });

  // Attach the box to the anchor with a `Spring` force
  var spring = new Spring(null, box, {
    stiffness: 95,
    period: 0.6,
    dampingRatio: 1.0,
    anchor: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0)
  });

  box.setVelocity(0.5, 0.5, 0);
  this.simulation.add(box, spring);
  this.items.push([box, position]);
  this.collision.addTarget(box);
}

function createSatellites(node, size, position, i) {
  node.moving = false;
  var rand = Math.round(Math.random() * 100 + 30);
  size.setAbsolute(rand, rand);
  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: rand / 2,
    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);
  //Drag
  var nodeGesture = new gestures(node);
  nodeGesture.on('drag', function(e, p) {
    if (e.status == "move") {
      node.moving = true;
    }
    var currentPos = node.getPosition()
    var newPosX = currentPos[0] + e.centerDelta.x
    var newPosY = currentPos[1] + e.centerDelta.y
    satellite.setPosition(newPosX, newPosY)
    node.setPosition(newPosX, newPosY)

    if (e.status == "end") {
      node.moving = false;
    }
  });
  //event
  node.addUIEvent('click');
  // node.addComponent({
  //   onReceive:function(event, payload){
  //           if(event==='click'){
  //               // el.setContent('I\'ve been clicked')
  //
  //           }
  //       }
  //   })
}

setTimeout(function() {
  // Boilerplate
  FamousEngine.init();
}, 500);


// 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>


Solution

  • This is the solution using BruteForceAABB.

    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);
    
    var centerPoint;
    
    function Demo() {
      this.scene = FamousEngine.createScene('body');
      // this.collision = new collision.({broadphase: 'BruteForce'});
      var broadPhase = new physics.Collision.BruteForceAABB([rightWall, leftWall, topWall, bottomWall]);
      this.collision = new collision([topWall], {
        'broadPhase': broadPhase
      });
    
      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 < 10; 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 && i !== 9) {
          node.id = i;
          createSatellites.call(this, node, size, position);
        }
        if (i === 9) {
          node.id = i;
          createAlternateShape.call(this, node, size, position);
    
        }
      }
    
      //Create Walls
      var node = this.scene.addChild();
      createWalls(node);
    
      var once = true;
    
      Demo.prototype.onUpdate = function(time) {
        this.simulation.update(time);
        // this.collision.resolve(time, 360)
    
        //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++) {
            if (once) {
              console.log(this.items[i][1]._node.moving)
              once = false;
            }
            if (this.items[i][1]._node.moving) {
              console.log('moving!')
            } else {
              var itemPosition = this.simulation.getTransform(this.items[i][0]).position;
              this.items[i][1].set(itemPosition[0], itemPosition[1], 0);
            }
    
    
          }
        }
    
        FamousEngine.requestUpdateOnNextTick(this);
      };
    
      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) {
      node.moving = false;
      size.setAbsolute(100, 100);
      var mp = new MountPoint(node).set(0.5, 0.5);
      var el = new DOMElement(node, {
        tagName: 'img',
        attributes: {
          src: './images/famous_logo.png'
        }
      });
      centerPoint = new Sphere({
        radius: 50,
        mass: 100000,
        restrictions: ['xy'],
        position: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0)
      });
    
      var spring = new Spring(null, centerPoint, {
        stiffness: 95,
        period: 0.6,
        dampingRatio: 1.0,
        anchor: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0)
      });
    
      centerPoint.setVelocity(0, 0, 0);
      this.simulation.add(centerPoint, spring);
      this.items.push([centerPoint, position]);
      this.collision.addTarget(centerPoint);
    }
    
    function createAlternateShape(node, size, position) {
      node.moving = false;
      size.setAbsolute(100, 100);
      var el = new DOMElement(node, {
        properties: {
          'background-color': 'red',
        }
      });
    
      var box = new physics.Box({
        size: [101, 101, 101],
        mass: 100,
        position: new Vec3(100, 100, 0)
      });
    
      // Attach the box to the anchor with a `Spring` force
      var spring = new Spring(null, box, {
        period: 1.5,
        dampingRatio: 0.8,
        anchor: new Vec3(window.innerWidth / 2, window.innerHeight / 2, 0)
      });
    
      box.setVelocity(0.1, 0.1, 0);
      this.simulation.add(box, spring);
      this.items.push([box, position]);
      this.collision.addTarget(box);
    }
    
    function createSatellites(node, size, position, i) {
      node.moving = false;
      var rand = Math.round(Math.random() * 100 + 30);
      size.setAbsolute(rand, rand);
      var radius = rand;
      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: rand / 2,
        mass: 100,
        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: 10,
        period: 1.5,
        dampingRatio: 0.8,
        anchor: anchor
      });
    
      //console.log(color);
      // satellite.setVelocity(-y / Math.PI, -x / Math.PI / 2, y / 2);
      satellite.setVelocity(0.1, 0.1, 0);
      // this.gravity.add(satellite);
      this.simulation.add(satellite, spring);
      this.items.push([satellite, position]);
      this.collision.addTarget(satellite);
      //Drag
      var nodeGesture = new gestures(node);
      nodeGesture.on('drag', function(e, p) {
        if (e.status == "move") {
          node.moving = true;
        }
        var currentPos = node.getPosition()
        var newPosX = currentPos[0] + e.centerDelta.x
        var newPosY = currentPos[1] + e.centerDelta.y
        satellite.setPosition(newPosX, newPosY)
        node.setPosition(newPosX, newPosY)
    
        if (e.status == "end") {
          node.moving = false;
        }
      });
      //event
      node.addUIEvent('click');
      // node.addComponent({
      //   onReceive:function(event, payload){
      //           if(event==='click'){
      //               // el.setContent('I\'ve been clicked')
      //
      //           }
      //       }
      //   })
    }
    
    setTimeout(function() {
      // Boilerplate
      FamousEngine.init();
    }, 500);
    
    
    // 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>