Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
184 views
in Technique[技术] by (71.8m points)

javascript - Bouncing draggable ball

I have this draggable ball when you drag and release, it is going the oposite way. How can I make this bounce from the walls? Also if it is supposed to travel 600px and it hit a wall after 200px, it should go for 400px more. 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";
    }
})
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...