JavaScript:如果检测到碰撞,则更改对象路径

时间:2016-01-21 21:03:30

标签: javascript collision-detection physics

我必须在javascript中创建一些飘落的雪花,但如果它们与其他碎片发生碰撞,它们会改变当前的路径。像这张图片上的东西: enter image description here

以下是我当前的代码:http://codepen.io/wojtek1150/pen/QyaYdY

el.parent();
var flakePositions = [[]];  
var temp = 0;
// snowflake proto
function Snowflake() {
    this.pos = new Physics();
    // snowflake guid
    this.id = '';
    // inits
    this.MAX_X_START_POS = 100;
    this.X_START_OFFSET = 0;
    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 = 100;
    // 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.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
        flakePositions[temp] = [];      
        flakePositions[temp]['id'] = this.id;
        flakePositions[temp]['x'] = this.flakeDOM.style.top;
        flakePositions[temp]['y'] = this.flakeDOM.style.left;
        flakePositions[temp]['width'] = this.flakeDOM.style.width;
        flakePositions[temp]['height'] = this.flakeDOM.style.height;
        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[temp]['x'] = this.flakeDOM.style.top;
        flakePositions[temp]['y'] = this.flakeDOM.style.left;
      
            
        //check position with rest
        for (var i = 1, len = flakePositions.length; i < len-1; i++) {
                        
            var rect1 = flakePositions[i];
            var rect1d = rect1['id'];
            var rect1sx = rect1['xspeed'];
            var rect1sy = rect1['yspeed'];
            var rect1x = parseInt(rect1['x']);
            var rect1y = parseInt(rect1['y']);
            
            for (var j = 2, len = flakePositions.length; j < len; j++) {
                var rect2 = flakePositions[j];
                
                var rect2d = rect2['id'];
                var rect2x = parseInt(rect2['x']);
                var rect2y = parseInt(rect2['y']);
                
                //if(rect1x == rect2x && rect1y == rect2y)
                if(rect1x < rect2x + 10 && rect1x + 10 > rect2x &&
                rect1y < rect2y  + 10 && 10 + rect1y  > rect2y )
                {
                    console.log('collision detected');
                    var t = document.getElementById(rect1d);
                    t.style.top = t.style.top+rect1sx+10;
                    t.style.left = t.style.left+rect1sy-10;
                }
            }
            
            
        }
    }
}


    

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 = 20;
    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;
  /*background: -moz-radial-gradient(center, ellipse cover, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%);
  background: -webkit-radial-gradient(center, ellipse cover, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%);
  background: radial-gradient(ellipse at center, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%);
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#00ffffff',GradientType=1 );
  */
  border-radius:50%;
  display:block;
  width:20px; height:20px;
  /* FOR DEV ONLY */
  background:#FFF;
  opacity:1!important;
}
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;
}

我已经知道如何获得职位,我得到if语句来检查是否有任何冲突。但我不知道如何以正确的方式改变路径,甚至只是反弹它:(

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

在执行此操作时,您需要考虑的关键事项之一是实施此类功能的成本/回报。我不认为这些碰撞会帮助你创造降雪的错觉。当你当前迭代中的雪花相互错过时,它会产生3d的幻觉。如果他们互相撞击并反弹,可能会给出错误的球落在二维飞机上的错觉。

话虽这么说,在不使用库的情况下实现您的要求将是一个巨大的时间同步。我建议您查看PhysicsJSmatter-js

下面你可以看到我个人在我正在使用的库中使用的功能。您可以根据自己的需要调整大部分内容。事实是这是一个复杂的问题。

define( 'detect/detectCircleCircleCollision' , [ 'lib/underscore' ] , function ( _ ) {

    return function detectCircleCircleCollision (   circlePositionA,
                                                    circleRadiusA,
                                                    circleDisplacementA,
                                                    circlePositionB,
                                                    circleRadiusB,
                                                    circleDisplacementB,
                                                    boolean,
                                                    normalBody ) {

        boolean = _.isUndefined( boolean ) || boolean ? true : false;

        normalBody = _.isUndefined( normalBody ) || normalBody ? true : false;

        var
            relativePosition            = circlePositionA.subtract.new( circlePositionB ),
            combineRadius               = circleRadiusA + circleRadiusB,
            relativePositionDotProduct  = relativePosition.lengthSqr(),
            relativeDisplacement        = circleDisplacementA.subtract.new( circleDisplacementB ),
            a,b,c,r,t,newCircleOnePosition,newCircleTwoPosition,newCirclePositionDifference,collisionPoint;

        if ( relativePositionDotProduct < combineRadius * combineRadius ) {

            if ( boolean ) return true;

            return collision(   0,//Time
                                circlePositionB.add.new( vector( relativePosition ).magnitude.set( circleRadiusA ) ),//point
                                relativePosition.normalize(),//Normal
                                normalBody,//normalbody
                                vector( relativePosition ).magnitude.set( circleRadiusA + circleRadiusB - relativePosition.magnitude() ) );//intersection

        }

        a = relativeDisplacement.dotProduct( relativeDisplacement );
        b = relativePosition.dotProduct( relativePosition );
        c = relativePositionDotProduct - combineRadius * combineRadius;
        r = b * b - a * c;

        if ( r < 0 ) return false;

        t = -b - r * r / a;

        if ( t > 1 || t < 0 ) return false;
        else if ( boolean ) return true;

        newCircleOnePosition        = circleDisplacementA.scale.new( t ).add( circlePositionA );
        newCircleTwoPosition        = circleDisplacementB.scale.new( t ).add( circlePositionB );
        newCirclePositionDifference = newCircleTwoPosition.subtract.new( newCircleOnePosition ).normalize();
        collisionPoint              = newCirclePositionDifference.scale.new( circleRadiusA );

        return collision(   t,
                            collisionPoint.add( newCircleOnePosition ),
                            newCirclePositionDifference,
                            normalBody,
                            false );



    };

} );