JavaScript对象与div对象在碰撞时粘在一起

6

我正在尝试制作一个小游戏,用户可以在页面上点击一个位置,圆圈会跟随指针的位置移动,然后用户可以拖动鼠标使圆圈像弹弓一样移动。我希望圆圈能够从墙壁上弹开。

然而,似乎当圆圈与墙壁碰撞时,圆圈会“粘”在墙上而不是弹开。我认为这可能是由于圆圈因舍入误差而改变方向太快所致?此外,顶部墙壁的碰撞尚未实现,因为我认为我没有正确声明顶部墙壁 div 对象。

let windowHeight = window.innerHeight;
let windowWidth = window.innerWidth;
//console.log(`Window height: ${windowHeight}, Window width: ${windowWidth}`);

var $ = document.querySelector.bind(document);
var $on = document.addEventListener.bind(document);

var mouseX, mouseY;
$on('mousedown', function (e){
    mouseX = e.clientX || e.pageX;
    mouseY = e.clientY || e.pageY;

    initialX = mouseX;
    initialY = mouseY;
   //console.log('mousedown');
});

$on('mouseup', function (e){
    //var d = Math.hypot(e.clientX - mouseX, e.clientY - mouseY);
    var movebyX = (Math.abs(e.clientX - mouseX));
    var movebyY = (Math.abs(e.clientY - mouseY));
    // Move puck in opposite direction
    if (e.clientX > mouseX){
        mouseX -= movebyX;
    }
    else if(e.clientX < mouseX){
        mouseX += movebyX;
    }
    
    if (e.clientY > mouseY){
        mouseY -= movebyY;
    }
    else if(e.clientY < mouseY){
        mouseY += movebyY;
    }
    
    //console.log('mouseup');
});


var circle = $('#circle');


var top = $('#top');
var bottom = $('#bottom');
var left = $('#left');
var right = $('#right');
var top = $('#top');


var x = void 0,
    y = void 0,
    dx = void 0;
    dy = void 0;
    v0x = void 0;
    v0y = void 0;
    accelScalar = 0.3;
    key = -1;
    velocityScalar = 0.05;
    teleport = 0.1;
    isCollide = false;
    swap = false;
    initialX = void 0;
    initialY = void 0;

var followMouse = function followMouse(){
    key = requestAnimationFrame(followMouse);
    //tester();
    if(!x || !y){
        x = mouseX;
        y = mouseY;
    }
    else {
        makeMove(findVelocity().dx,findVelocity().dy);
    }
              
    };

function tester() {
    console.log(top.getBoundingClientRect());
}



function findVelocity(){
    v0x = (mouseX - x) * velocityScalar
    v0y = (mouseY - y) * velocityScalar
    return {
        dx: v0x * accelScalar,
        dy: v0y * accelScalar,
    };
}


function makeMove(vx,vy){
    //console.log(`x: ${x}, mouseX: ${mouseX}, vx: ${vx}`);
    
    // teleport, avoid asymptote
    if(Math.abs(vx) + Math.abs(vy) < teleport) {
        x = mouseX;
        y = mouseY;
        vx = 0;
        vy = 0;
   }
   
    // update position if collision

    if (x-41 < (left.getBoundingClientRect().x)){
        vx = -vx
        vy = -vy
    }
    if (x+41 > (right.getBoundingClientRect().x)){
        vx = -vx
        vy = -vy
    }
    if (y+41 > (bottom.getBoundingClientRect().y)){
        vx = -vx
        vy = -vy
    }
    x += vx;
    y += vy;
    // show circle position
    circle.style.left = (x-20) + 'px';
    circle.style.top = (y-20) + 'px';
}

followMouse();
html, body {
    margin: 0;
    height: 100%;
    background: #161616;


}

.wrap {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    overflow: hidden;
}

@keyframes animation {
    0% {
        transform: scale(0.9)
    }
    25% {
        transform: scale(1.1)
    }
    50% {
        transform: scale(0.9)
    }
    75% {
        transform: scale(1.1)
    }
    100% {
        transform: scale(0.9)
    }
}

#circle {
    
    width: 50px;
    height: 50px;
    background: none;
    border: 5px solid aqua;
    border-radius: 50%;
    position: absolute;
    left: 50%;
    top: 50%;
    margin: -10px 0 0 -10px;
    pointer-events: none;
    /*animation: animation 5s infinite
    
    */
}

#top, #bottom, #left, #right {
 background: #a5ebff;
 position: fixed;
 }
 #left, #right {
  top: 0; bottom: 0;
  width: 10px;
  }
  #left { left: 0; }
  #right { right: 0; }
  
 #top, #bottom {
  left: 0; right: 0;
  height: 10px;
  }
  #top { top: 0; }
  #bottom { bottom: 0; }
<!DOCTYPE html>
<html>
    <head>
        <title> Test Project </title>
        <link rel = "stylesheet" href = "main.css">
        
    </head>

    <body>
        <div class = "wrap">
            <div id = "circle"></div>
        </div>
        
        <div id="left"></div>
        <div id="right"></div>
        <div id="top"></div>
        <div id="bottom"></div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script type = "text/javascript" src = "./main.js"> </script>
    </body>
</html> 


这是一个非常好的问题,我会尽快添加答案,但我想赞扬你的出色帖子。已经有3个书签了哈哈。 - Lewis
1个回答

2

两个问题:

  1. top是顶层框架的保留变量。尝试访问ID为top的元素会与此冲突(应避免依赖它,而使用getElementById代替)。

  2. 仅仅反转速度是行不通的,因为你是在每一帧计算速度,使用上一个鼠标点击位置(这就是你通过衰减速度来实现缓动到位置的方式)。
    使其正常工作的最简单方法是使用鼠标点击位置和边界之间的距离来设置偏移了距离的边界内的新的鼠标点击位置。(基本上具有使用边界作为轴反转位置的相同效果。在这种情况下,还将圆的宽度的一半添加到此轴上。虽然使用硬编码数字,但如果需要改进,也可以从实际尺寸进行计算。)

let windowHeight = window.innerHeight;
let windowWidth = window.innerWidth;
//console.log(`Window height: ${windowHeight}, Window width: ${windowWidth}`);

var $ = document.querySelector.bind(document);
var $on = document.addEventListener.bind(document);

var mouseX, mouseY;
$on('mousedown', function (e){
    mouseX = e.clientX || e.pageX;
    mouseY = e.clientY || e.pageY;

    initialX = mouseX;
    initialY = mouseY;
   //console.log('mousedown');
});

$on('mouseup', function (e){
    //var d = Math.hypot(e.clientX - mouseX, e.clientY - mouseY);
    var movebyX = (Math.abs(e.clientX - mouseX));
    var movebyY = (Math.abs(e.clientY - mouseY));
    // Move puck in opposite direction
    if (e.clientX > mouseX){
        mouseX -= movebyX;
    }
    else if(e.clientX < mouseX){
        mouseX += movebyX;
    }
    
    if (e.clientY > mouseY){
        mouseY -= movebyY;
    }
    else if(e.clientY < mouseY){
        mouseY += movebyY;
    }
    
    //console.log('mouseup');
});


var circle = $('#circle');


var top = $('#top');
var bottom = $('#bottom');
var left = $('#left');
var right = $('#right');
var top = $('#top');


var x = void 0,
    y = void 0,
    dx = void 0;
    dy = void 0;
    v0x = void 0;
    v0y = void 0;
    accelScalar = 0.3;
    key = -1;
    velocityScalar = 0.05;
    teleport = 0.1;
    isCollide = false;
    swap = false;
    initialX = void 0;
    initialY = void 0;

var followMouse = function followMouse(){
    key = requestAnimationFrame(followMouse);
    //tester();
    if(!x || !y){
        x = mouseX;
        y = mouseY;
    }
    else {
        makeMove(findVelocity().dx,findVelocity().dy);
    }
              
    };

function tester() {
    console.log(top.getBoundingClientRect());
}



function findVelocity(){
    v0x = (mouseX - x) * velocityScalar
    v0y = (mouseY - y) * velocityScalar
    return {
        dx: v0x * accelScalar,
        dy: v0y * accelScalar,
    };
}


function makeMove(vx,vy){
    //console.log(`x: ${x}, mouseX: ${mouseX}, vx: ${vx}`);
    
    // teleport, avoid asymptote
    if(Math.abs(vx) + Math.abs(vy) < teleport) {
        x = mouseX;
        y = mouseY;
        vx = 0;
        vy = 0;
   }
   
    // update position if collision

    if (x-41 < (left.getBoundingClientRect().x)){
        mouseX = Math.abs(mouseX - x) + 41
    }
    if (x+31 > (right.getBoundingClientRect().x)){
        mouseX = right.getBoundingClientRect().x - Math.abs(mouseX - x) - 31
    }
    var top = document.getElementById('top')
    if (y-41 < (top.getBoundingClientRect().y)){
        mouseY = Math.abs(mouseY - y) + 41
    }
    if (y+31 > (bottom.getBoundingClientRect().y)){
        mouseY = bottom.getBoundingClientRect().y - Math.abs(mouseY - y) - 31
    }
    x += vx;
    y += vy;
    // show circle position
    circle.style.left = (x-20) + 'px';
    circle.style.top = (y-20) + 'px';
}

followMouse();
html, body {
    margin: 0;
    height: 100%;
    background: #161616;


}

.wrap {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    overflow: hidden;
}

@keyframes animation {
    0% {
        transform: scale(0.9)
    }
    25% {
        transform: scale(1.1)
    }
    50% {
        transform: scale(0.9)
    }
    75% {
        transform: scale(1.1)
    }
    100% {
        transform: scale(0.9)
    }
}

#circle {
    
    width: 50px;
    height: 50px;
    background: none;
    border: 5px solid aqua;
    border-radius: 50%;
    position: absolute;
    left: 50%;
    top: 50%;
    margin: -10px 0 0 -10px;
    pointer-events: none;
    /*animation: animation 5s infinite
    
    */
}

#top, #bottom, #left, #right {
 background: #a5ebff;
 position: fixed;
 }
 #left, #right {
  top: 0; bottom: 0;
  width: 10px;
  }
  #left { left: 0; }
  #right { right: 0; }
  
 #top, #bottom {
  left: 0; right: 0;
  height: 10px;
  }
  #top { top: 0; }
  #bottom { bottom: 0; }
<!DOCTYPE html>
<html>
    <head>
        <title> Test Project </title>
        <link rel = "stylesheet" href = "main.css">
        
    </head>

    <body>
        <div class = "wrap">
            <div id = "circle"></div>
        </div>
        
        <div id="left"></div>
        <div id="right"></div>
        <div id="top"></div>
        <div id="bottom"></div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script type = "text/javascript" src = "./main.js"> </script>
    </body>
</html>


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