弹跳可拖动球
Bouncing draggable ball
当你拖动和释放时,我有这个可拖动的球,它是相反的。我怎样才能使它从墙上反弹?此外,如果它应该移动 600 像素并且在 200 像素后撞到墙上,它应该再移动 400 像素。
http://jsfiddle.net/bepcmsgo/5/
let circle = document.getElementById("circle");
let pos1 = 0;
let pos2 = 0;
let pos3 = 0;
let pos4 = 0;
let mouseDown = false;
let currentCircleTop = 0;
let currentCircleLeft = 0;
circle.addEventListener("mousedown", function(e){
mouseDown = true;
pos3 = e.pageX;
pos4 = e.pageY;
currentCircleTop = circle.offsetTop;
currentCircleLeft = circle.offsetLeft;
this.style.transition = "0.3s all";
})
document.addEventListener("mousemove", function(e){
if(mouseDown){
pos1 = pos3 - e.pageX;
pos2 = pos4 - e.pageY;
pos3 = e.pageX;
pos4 = e.pageY;
circle.style.top = circle.offsetTop - pos2 + "px";
circle.style.left = circle.offsetLeft - pos1 + "px";
}
})
document.addEventListener("mouseup", function(){
if(mouseDown){
mouseDown = false;
circle.style.transition = "0.8s all";
circle.style.top = currentCircleTop + ((currentCircleTop - circle.offsetTop) * 20) + "px";
circle.style.left = currentCircleLeft + ((currentCircleLeft - circle.offsetLeft) * 20) + "px";
}
})
我分叉了你的 JSFiddle 并添加了一个简单的弹跳机制:jsfiddle.net/SydLambert/hnkL392x/2
let circle = document.getElementById("circle");
circle.x=300;
circle.y=150;
circle.direction=0; //in radians
circle.velocity=0;
circle.friction=0.05; //0 to 1
let container=document.getElementById("circleContainer");
container.width=parseInt(container.style.width.slice(0,-2)); //Gets width and height as usable integers
container.height=parseInt(container.style.height.slice(0,-2));
let mouse={
x:0,
y:0,
down:false,
};
let dragDisplayMultiplier=0.2; //How much the circle moves while a drag is in progress.
let velocityDampener=5; //How much the velocity is reduced immediately after the circle is released
function displayCircle(){ //Sets the position of the circle
circle.style.top=circle.y+"px";
circle.style.left=circle.x+"px"
}
function step(){ //Uses trig to work out the next positon of the circle
return {
x:circle.x+circle.velocity*Math.cos(circle.direction),
y:circle.y+circle.velocity*Math.sin(circle.direction),
}
}
function tick(){ //Physics function
circle.velocity*=1-circle.friction; //Decrease the circle's velocity with friction
let newLocation=step(); //Determine the next location after the circle has travelled
//If the next location of the circle is outside the container, the direction is changed.
//Angle of incidence equals angle of reflection.
if(newLocation.x<0 || newLocation.x+20>container.width)
circle.direction=Math.PI-(circle.direction);
if(newLocation.y<0 || newLocation.y+20>container.height)
circle.direction*=-1;
//The next location is now inside the container, so the circle's position can be updated
newLocation=step();
circle.x=newLocation.x;
circle.y=newLocation.y;
//Displays the circle's new position to the user
displayCircle();
//If the circle still has reasonable velocity, the simulation is continued after waiting 16ms
if(circle.velocity>1){
setTimeout(tick,16);
}
}
circle.addEventListener("mousedown", function(e){
mouse.down=true;
});
document.addEventListener("mousemove", function(e){
mouse.x=e.pageX;
mouse.y=e.pageY;
if(mouse.down) //Offsets the ball whilst the drag is in progress using CSS translation
circle.style.transform=`translate(${((circle.x+mouse.x)/2-circle.x)*dragDisplayMultiplier}px, ${((circle.y+mouse.y)/2-circle.y)*dragDisplayMultiplier}px)`;
});
document.addEventListener("mouseup", function(){
if(mouse.down){
mouse.down = false;
circle.style.transform="translate(0px, 0px)"; //Resets the CSS translation from the "mousemove" event
circle.velocity=Math.sqrt((circle.x-mouse.x+10)**2 + (circle.y-mouse.y+10)**2); //Sets the velocity to the distance bewteen the circle and mouse pointer
circle.velocity/=velocityDampener; //Reduces the velocity slightly for ease of use
circle.direction=Math.atan2((circle.y-mouse.y+10),(circle.x-mouse.x+10)); //Uses atan2 to find the angle between the circle and the mouse pointer
setTimeout(tick,16); //Starts the physics simulation
}
});
displayCircle(); //Sets the initial circle top and left to match x and y
我稍微改变了球的移动逻辑,这里有一些解释我方法的要点:
- 使用 CSS 动画对于简单的动作来说非常好,但是任何更动态和复杂的东西最好留给 JS 来节省大量 CSS 代码。
- 在此示例中,所有运动都在 JS 中逐帧处理,在渲染每一帧之前进行角度和摩擦力计算,而不是计算最终位置并在那里设置路径动画。每个刻度计算紧接的下一个位置(必要时弹跳),然后显示给用户。滴答之间的延迟是
16ms
使其达到 ~62.5FPS。
- 我将您的位置变量移动到
circle
class 中的命名属性,以便比 pos1
、pos2
、pos3
更易于阅读...全部作为全局变量。
- 数学非常适合谷歌搜索,我使用 pythag 获取到鼠标指针的距离并使用 trig 获取指针的角度并移动圆圈。反射角假定入射角等于反射角。弹跳还假定完全弹性碰撞,但如果需要,您可以降低弹跳的速度。
- 我将发布前的轻微移动更改为使用 CSS 翻译而不是实际移动元素。
- 最后一点,我建议查看 HTML5
<canvas>
如果你想做更多图形化的东西,它就是为这样的东西而构建的。
当你拖动和释放时,我有这个可拖动的球,它是相反的。我怎样才能使它从墙上反弹?此外,如果它应该移动 600 像素并且在 200 像素后撞到墙上,它应该再移动 400 像素。 http://jsfiddle.net/bepcmsgo/5/
let circle = document.getElementById("circle");
let pos1 = 0;
let pos2 = 0;
let pos3 = 0;
let pos4 = 0;
let mouseDown = false;
let currentCircleTop = 0;
let currentCircleLeft = 0;
circle.addEventListener("mousedown", function(e){
mouseDown = true;
pos3 = e.pageX;
pos4 = e.pageY;
currentCircleTop = circle.offsetTop;
currentCircleLeft = circle.offsetLeft;
this.style.transition = "0.3s all";
})
document.addEventListener("mousemove", function(e){
if(mouseDown){
pos1 = pos3 - e.pageX;
pos2 = pos4 - e.pageY;
pos3 = e.pageX;
pos4 = e.pageY;
circle.style.top = circle.offsetTop - pos2 + "px";
circle.style.left = circle.offsetLeft - pos1 + "px";
}
})
document.addEventListener("mouseup", function(){
if(mouseDown){
mouseDown = false;
circle.style.transition = "0.8s all";
circle.style.top = currentCircleTop + ((currentCircleTop - circle.offsetTop) * 20) + "px";
circle.style.left = currentCircleLeft + ((currentCircleLeft - circle.offsetLeft) * 20) + "px";
}
})
我分叉了你的 JSFiddle 并添加了一个简单的弹跳机制:jsfiddle.net/SydLambert/hnkL392x/2
let circle = document.getElementById("circle");
circle.x=300;
circle.y=150;
circle.direction=0; //in radians
circle.velocity=0;
circle.friction=0.05; //0 to 1
let container=document.getElementById("circleContainer");
container.width=parseInt(container.style.width.slice(0,-2)); //Gets width and height as usable integers
container.height=parseInt(container.style.height.slice(0,-2));
let mouse={
x:0,
y:0,
down:false,
};
let dragDisplayMultiplier=0.2; //How much the circle moves while a drag is in progress.
let velocityDampener=5; //How much the velocity is reduced immediately after the circle is released
function displayCircle(){ //Sets the position of the circle
circle.style.top=circle.y+"px";
circle.style.left=circle.x+"px"
}
function step(){ //Uses trig to work out the next positon of the circle
return {
x:circle.x+circle.velocity*Math.cos(circle.direction),
y:circle.y+circle.velocity*Math.sin(circle.direction),
}
}
function tick(){ //Physics function
circle.velocity*=1-circle.friction; //Decrease the circle's velocity with friction
let newLocation=step(); //Determine the next location after the circle has travelled
//If the next location of the circle is outside the container, the direction is changed.
//Angle of incidence equals angle of reflection.
if(newLocation.x<0 || newLocation.x+20>container.width)
circle.direction=Math.PI-(circle.direction);
if(newLocation.y<0 || newLocation.y+20>container.height)
circle.direction*=-1;
//The next location is now inside the container, so the circle's position can be updated
newLocation=step();
circle.x=newLocation.x;
circle.y=newLocation.y;
//Displays the circle's new position to the user
displayCircle();
//If the circle still has reasonable velocity, the simulation is continued after waiting 16ms
if(circle.velocity>1){
setTimeout(tick,16);
}
}
circle.addEventListener("mousedown", function(e){
mouse.down=true;
});
document.addEventListener("mousemove", function(e){
mouse.x=e.pageX;
mouse.y=e.pageY;
if(mouse.down) //Offsets the ball whilst the drag is in progress using CSS translation
circle.style.transform=`translate(${((circle.x+mouse.x)/2-circle.x)*dragDisplayMultiplier}px, ${((circle.y+mouse.y)/2-circle.y)*dragDisplayMultiplier}px)`;
});
document.addEventListener("mouseup", function(){
if(mouse.down){
mouse.down = false;
circle.style.transform="translate(0px, 0px)"; //Resets the CSS translation from the "mousemove" event
circle.velocity=Math.sqrt((circle.x-mouse.x+10)**2 + (circle.y-mouse.y+10)**2); //Sets the velocity to the distance bewteen the circle and mouse pointer
circle.velocity/=velocityDampener; //Reduces the velocity slightly for ease of use
circle.direction=Math.atan2((circle.y-mouse.y+10),(circle.x-mouse.x+10)); //Uses atan2 to find the angle between the circle and the mouse pointer
setTimeout(tick,16); //Starts the physics simulation
}
});
displayCircle(); //Sets the initial circle top and left to match x and y
我稍微改变了球的移动逻辑,这里有一些解释我方法的要点:
- 使用 CSS 动画对于简单的动作来说非常好,但是任何更动态和复杂的东西最好留给 JS 来节省大量 CSS 代码。
- 在此示例中,所有运动都在 JS 中逐帧处理,在渲染每一帧之前进行角度和摩擦力计算,而不是计算最终位置并在那里设置路径动画。每个刻度计算紧接的下一个位置(必要时弹跳),然后显示给用户。滴答之间的延迟是
16ms
使其达到 ~62.5FPS。 - 我将您的位置变量移动到
circle
class 中的命名属性,以便比pos1
、pos2
、pos3
更易于阅读...全部作为全局变量。 - 数学非常适合谷歌搜索,我使用 pythag 获取到鼠标指针的距离并使用 trig 获取指针的角度并移动圆圈。反射角假定入射角等于反射角。弹跳还假定完全弹性碰撞,但如果需要,您可以降低弹跳的速度。
- 我将发布前的轻微移动更改为使用 CSS 翻译而不是实际移动元素。
- 最后一点,我建议查看 HTML5
<canvas>
如果你想做更多图形化的东西,它就是为这样的东西而构建的。