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

3
我需要在JavaScript中创建一些下落的雪花,但如果它们与其他雪花碰撞,它们必须更改当前路径。类似于这个图像: enter image description here 这是我目前的代码:http://codepen.io/wojtek1150/pen/QyaYdY

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;
}
<button id="startstop">Start/stop</button>
 <div id="snow"> </div>

我已经知道如何获取位置并使用if语句检查是否有任何碰撞。但是我不知道如何以正确的方式改变路径,即使只是弹跳 :(

有什么建议吗?


1
你看过这个问题吗?它可能会有帮助。https://dev59.com/xXRC5IYBdhLWcg3wS_AF?rq=1 - jpw
1
为什么要重新发明轮子,当你可以使用一个成熟的物理库呢? - Derek 朕會功夫
我不能使用现成的解决方案。这是学校的练习。我只是想知道如何创建它以获得更好的成绩 ;) - Wojciech Parys
1个回答

1
当你进行这种操作时,需要考虑的关键问题之一是实施此类功能的成本/回报。我认为这些碰撞不会帮助你创造雪花飘落的幻觉。当你当前版本中的雪花互相错过时,会给人以三维的幻觉。如果它们相互碰撞并弹跳,可能会产生错误的二维平面上球体下落的幻觉。
话虽如此,如果不使用库来实现你所要求的功能,将会耗费大量时间。我建议看一下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 );



    };

} );

我不需要制造下雪的幻觉,我只需要学习如何创建像You send(例如PhysicsJS)这样的东西。这是一个学校项目。下雪是我的讲师提出的想法。所以我不能使用插件来完成它 :( - Wojciech Parys
好的,非常抱歉让您等了这么久才回复。我有一个函数可以为您完成此操作,但目前我没有太多时间来解释它,以下是代码: - hyphnKnight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接