我必须在javascript中创建一些飘落的雪花,但如果它们与其他碎片发生碰撞,它们会改变当前的路径。像这张图片上的东西:
以下是我当前的代码: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语句来检查是否有任何冲突。但我不知道如何以正确的方式改变路径,甚至只是反弹它:(
有什么建议吗?
答案 0 :(得分:1)
在执行此操作时,您需要考虑的关键事项之一是实施此类功能的成本/回报。我不认为这些碰撞会帮助你创造降雪的错觉。当你当前迭代中的雪花相互错过时,它会产生3d的幻觉。如果他们互相撞击并反弹,可能会给出错误的球落在二维飞机上的错觉。
话虽这么说,在不使用库的情况下实现您的要求将是一个巨大的时间同步。我建议您查看PhysicsJS或matter-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 );
};
} );