0
votes

In my game, I make a sphere (created using a-sphere), a dynamic body, collide with another dynamic body (a-box).

Upon collision, the sphere breaks into multiple smaller spheres. I need to stop this disintegration

Here is the codepen - sphere breaks on collision with dynamic body

Here is the accompanying code -

HTML

<a-scene physics="debug: true; gravity: -5.0">
  <a-entity camera="userHeight: 1.6"
                look-controls
                kinematic-body>
        <a-entity cursor
                  position="0 0 -1"
                  geometry="primitive: circle; radius: 0.01; segments: 4;"
                  material="color: #FF4444; shader: flat"></a-entity>
    <a-entity position="0 0 1" id="attachment"></a-entity>
  </a-entity>

  <a-entity geometry="primitive: box; height:2" material="color: black; shader: flat" position="0 2 -5" dynamic-body></a-entity>

  <a-plane static-body color="#ccc" height="100" width="100" position="0 -0.1 0" rotation="-90 0 0"></a-plane>
</a-scene>

and JS

const scene = document.querySelector('a-scene');
const camera = document.querySelector('[camera]');
const attachment = document.querySelector('#attachment');

function spawnBullet() {
    let entity = document.createElement('a-sphere');
    let impulseAmount = 8;

    entity.setAttribute('radius', 1);
    // Set initial position of projectile to that of the camera.
    entity.setAttribute('position', camera.getAttribute('position'));
    entity.setAttribute('color', '#00FFCC');
    entity.setAttribute('shader', 'flat');
    entity.setAttribute('mass', 10);

    // Append projectile to the scene, not to the camera, to
    // avoid all sorts of complications. Most notably, CANNON.js
    // has no scene graph or nesting.
    scene.appendChild(entity);

    entity.setAttribute('dynamic-body', true);  

    entity.addEventListener('body-loaded', function(){
      // Can't apply forces during the same tick that attaches the body, because
      // it hasn't been fully synced to the physics sim. (bug)
      setTimeout(function () {
        let pStart = new CANNON.Vec3();
        // Use an origin point behind the head, not at the head, so
        // there's a useful vector between the origin and the projectile.
        pStart.copy(attachment.object3D.getWorldPosition());
        let force = entity.body.position.vsub(pStart);
        force.normalize(); 
        force.scale(impulseAmount, force);
        entity.body.applyImpulse(force, entity.body.position);
      }, 0);

      entity.addEventListener('collide', function(e){
        console.log("hit");
      })
    });
}

if (scene.hasLoaded) init(); // change 2
else scene.addEventListener('loaded', init);

function init () {
  // any code that appends things to the scene
  scene.addEventListener('click', spawnBullet);
}

Is there a way that this can be stopped and the sphere remains intact after collision?

2

2 Answers

2
votes

The sphere is not breaking, what's happening is that your click event handler is being called multiple times for each click, and creating many spheres at once. I'm not entirely sure why that's happening. One way around that, use AFRAME.utils.throttle to prevent creating spheres too quickly:

spawnBullet = AFRAME.utils.throttle(spawnBullet, 100);
scene.addEventListener('click', spawnBullet);

Updating to a newer version of A-Frame may also fix the issue.

2
votes

Listening for the click event on the scene is backfiring, because you get three events
- the cursor emits one when clicked on something
- the target emits one when clicked
- the canvas emits one (mouse clicking, not the a-frame cursor - on the DOM canvas element).

You can see it in this example, click on any object on the scene, and check out the console.


mousedownhere
viveshootBullet

Check it out working properly here.