0

I have to create falling objects with reverse path on collision. So there are x number of balls that falling randomly, when it meet on his path another ball it have to change direction. They can't impose itself. I already created that code:

var flakePositions = [[]];
  var temp = 0;
  var move = 1;
  // snowflake proto
  function Snowflake() {
   this.pos = new Physics();
   // snowflake guid
   this.id = '';
   this.collisionCount = 0;
   // inits
   this.MAX_X_START_POS = 250;
   this.X_START_OFFSET = 200;
   this.MAX_Y_START_POS = 50;
   this.Y_START_OFFSET = 50;
   this.MAX_X_SPEED = 4;
   this.MAX_Y_SPEED = 1.2;

   // use to get sin && cos
   this.animationStepsCounter = 0
   this.fallFactor = 10;
   // snowflake html
   this.getId = function () {
    if (this.id == '') {
     this.id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,
      function (c) {
       var r = crypto.getRandomValues(new Uint8Array(1))[0] % 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
       return v.toString(16);
      });
    }
    return this.id;
   }
   this.initalize = function () {
    temp++;
    //var size = 5 + Math.random() * 20;
    var size = 20;
    this.flakeDOM.innerHTML = temp;
    this.flakeDOM.style.width = size + "px";
    this.flakeDOM.style.height = size + "px";
    this.flakeDOM.style.opacity = Math.random();
    this.pos.x = (Math.random() * this.MAX_X_START_POS);
    this.pos.y = this.Y_START_OFFSET + (Math.random() * this.MAX_Y_START_POS);
    this.pos.xSpeed = Math.random() * this.MAX_X_SPEED * Math.sign(-0.5 + Math.random());
    this.pos.ySpeed = Math.random() * this.MAX_Y_SPEED;

    //create array
    this.serial = temp;
    flakePositions[temp] = [];
    flakePositions[temp]['id'] = this.id;
    flakePositions[temp]['x'] = this.flakeDOM.style.top;
    flakePositions[temp]['y'] = this.flakeDOM.style.left;
    flakePositions[temp]['radius'] = this.flakeDOM.style.width;
    flakePositions[temp]['xspeed'] = this.pos.xSpeed;
    flakePositions[temp]['yspeed'] = this.pos.ySpeed
   }
   this.move = function () {
    this.flakeDOM.style.top = (this.pos.y += this.pos.ySpeed) + "px";
    this.flakeDOM.style.left = (this.pos.x += Math.sin(this.animationStepsCounter / this.fallFactor) * this.pos.xSpeed) + "px";
    this.animationStepsCounter += this.pos.ySpeed;

    //update array
    flakePositions[this.serial]['x'] = this.flakeDOM.style.top;
    flakePositions[this.serial]['y'] = this.flakeDOM.style.left;


    //check position with rest
                var rect1 = flakePositions[this.serial];
                var rect1d = rect1['id'];

                var firstBall_radius = parseInt(rect1['radius']) / 2;
                var firstBall_x = parseInt(rect1['x']) + firstBall_radius;
                var firstBall_y = parseInt(rect1['y']) + firstBall_radius;
                
                var firstBall_Ax = firstBall_x + firstBall_radius;
                var firstBall_Ay = firstBall_y + firstBall_radius;

                for (var j = 1, len = flakePositions.length; j < len; j++) {
                    if (rect1 !== flakePositions[j]) {
                        var rect2 = flakePositions[j];
                        var rect2d = rect2['id'];
                        var sflake = document.getElementById(rect2d);

                        var secondBall_radius = parseInt(rect2['radius']) / 2;
                        var secondBall_x = parseInt(rect2['x']) + secondBall_radius;
                        var secondBall_y = parseInt(rect2['y']) + secondBall_radius;
                        
                        var secondBall_Ax = secondBall_x + secondBall_radius;
                        var secondBall_Ay = secondBall_y + secondBall_radius;

                        if (firstBall_x + firstBall_radius + secondBall_radius > secondBall_x
                        && firstBall_x < secondBall_x + firstBall_radius + secondBall_radius
                        && firstBall_y + firstBall_radius + secondBall_radius > secondBall_y
                        && firstBall_y < secondBall_y + firstBall_radius + secondBall_radius) {
                            distance = Math.sqrt(
                                ((firstBall_x - secondBall_x) * (firstBall_x - secondBall_x))
                                + ((firstBall_y - secondBall_y) * (firstBall_y - secondBall_y))
                            );
                
                            if (distance < firstBall_radius + secondBall_radius) {
                                console.log('%c balls have collided', 'color: #0000FF');
                                sflake.style.left *= -1;
                            }
                        } 
                    }
                }
   }
  }




  function Physics() {
   // pos
   this.x = 0;
   this.y = 0;
   this.z = 0;
   // speed
   this.xSpeed = 0;
   this.ySpeed = 0;
   this.zSpeed = 0;
   // acceleration
   this.xAccel = 1;
   this.yAccel = 1;
   this.zAccel = 1;
  }

  snowflakes = new Array();
  var interval = 0;

  function makeThisBoom() {
   // snowflakes container
   snowfield = document.getElementById('snow');
   // snowflakes count
   snoflakesCount = 4;
   for (var i = 0; i < snoflakesCount; i++) {
    snowflakes[i] = new Snowflake();
    var flake = document.createElement('div');
    snowflakes[i].flakeDOM = flake;
    flake.id = snowflakes[i].getId();
    flake.classList.add('sf');
    snow.appendChild(flake);
    snowflakes[i].initalize();
    snowflakes[i].move();
   }
   interval = setInterval(anime, 50);
  }

  function anime() {
   for (var flake of snowflakes) {
    flake.move();
   }
  }

  function setInterface() {
   document.getElementById('startstop').onclick = function () {
    if (interval != 0) {
     clearInterval(interval);
     interval = 0;
    } else interval = setInterval(anime, 50);
   }
  }
  document.addEventListener("DOMContentLoaded", makeThisBoom);
  document.addEventListener("DOMContentLoaded", setInterface);
.sf{
  position:absolute;
  z-index:9999999;
  display:block;
  width:20px; height:20px;
  /* FOR DEV ONLY */
  background:#FFF;
  opacity:1!important;
  border-radius: 50%;
}
body{
  background:#222;
  overflow:hidden;
}
#snow {
    position: absolute;
    width: 100%;
    height: 100%;
    overflow: hidden;
}
#startstop{
  width:100px;
  height:30px;
  border:0;
  background:rgb(61, 95, 123);
  color:#FFF;
  outline:none;
}
<button id="startstop">Start/stop</button>
 <div id="snow"> </div>

It detect collision, but I ready don't know how to bounce it on collision. I tried to just reverse it (*-1) but nothing. Someone have any ideas? Thanks for all answers

Wojciech Parys
  • 339
  • 2
  • 18
  • Have you tried reversing flake.pos.xSpeed ? You have to change the speed and not the actual position of the flake. You will need some calculation in order to make a clean bounce so it bounces away from the colliding flake. – Pierre C. Mar 10 '16 at 14:08

2 Answers2

0

The solution you suggested works to just change the direction on collision, just multiply the speed with -1 when they collide.

See https://jsfiddle.net/f1z9ak6c/

this.pos.xSpeed *= -1;

However, you run into problems if balls are on top of eachother, they will just move together forever, this does however work as long as they don't start on top of eachother. You will need to write additional code to stop this behaviour, the simplest being simply making sure they don't spawn on top of eachother.

Robin
  • 1,251
  • 11
  • 18
  • I think the general solution is that the speeds need to be reflected based on the direction of the collision. So, if the distance between them at time of collision is X=0.5, Y=0.5, then you should go from XSpeed=5, YSpeed=1 to XSpeed=-5, YSpeed=-1. (That might vary if you want an inelastic collision) – Katana314 Mar 10 '16 at 14:11
  • Yes, it looks slightly weird when two "flakes" moving the same way collides due to differing speeds, and suddenly they are both moving in opposite directions. You would most likely want to tweak the multipliers based on the velocity of the flakes colliding if you want realistic behaviour. – Robin Mar 10 '16 at 14:13
  • @Robin You are right, I tried this solution, but reinit it few times. If You have collision on init balls don't bounce. – Wojciech Parys Mar 10 '16 at 22:06
  • @Katana314 I just need to reverse left position. They can't "fall" up. They have to always go down. Just bounce horizontaly – Wojciech Parys Mar 10 '16 at 22:07
  • @Wojtek1150 yes, the easiest solution as said would be to make sure they never collide on init. If not, you would have to write some code which makes sure they don't reverse position if they collide for more than one cycle of the animation. – Robin Mar 11 '16 at 06:37
0

seems like a case of billiard physics. I looked it up and there are some interesting equations on the page real world physics problems

I also found this other question which was solved: Ball to Ball Collision - Detection and Handling

Community
  • 1
  • 1
w0ps
  • 11
  • 4