I forked your JSFiddle and added a simple bouncing mechanic: 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
I changed the ball movement logic slightly, here are some pointers that explain my approach:
- Using CSS animations is perfectly fine for simple movements, but anything more dynamic and complex is best left to JS to save yourself a lot of CSS code.
- In this example, all movements are handled frame-by-frame in JS, with angle & friction calculations occurring before each frame is rendered, instead of calculating the final position and animating the path there. Each tick calculates the immediate next position (bouncing if necessary) and then displays to the user. The delay between ticks is
16ms
to make it ~62.5FPS.
- I moved your position variables to named properties in the
circle
class to make it easier to read than having pos1
, pos2
, pos3
... all as global variables.
- The math is quite googleable, I used pythag to get the distance to the mouse pointer and trig to get the angle to the pointer & move the circle. The bounce angle assumes that the angle of incidence equals angle of reflection. The bounce also assumes perfectly elastic collision, although you could decrease velocity on a bounce if you wanted.
- I changed the slight movement before release to use CSS translation instead of actually moving the element.
- One final note, I would suggest looking into HTML5
<canvas>
if you want to do more graphical stuff, it was built for stuff like this.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…