Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Object sticks to div object on collision

I'm trying to make a little game where the user can click on a place on the page, the circle will follow to the pointer's position, and from there, the user can drag their mouse to make the circle move like a slingshot. I want the circle to be able to bounce off the walls.

However, it seems that on the circle's collision with a wall, the circle seems to 'stick' to the wall instead of bouncing right off. I think it might be because of the circle changing directions too quickly due to a rounding error? Also the top wall's collision hasn't been implemented yet because I don't think I declared the top wall div object properly.

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> 
like image 598
William Nguyen Avatar asked Jun 10 '20 20:06

William Nguyen


1 Answers

Two issues:

  1. top is a reserved variable for the top level frame. Conflicts with trying to access element with id top, (which you should avoid depending on, use getElementById instead)

  2. Just inverting velocity will not work, because you are calculating the velocity every frame using the last mouse clicked position (which is how your easing into position works by decaying velocity as it gets closer to mouseX/Y).
    The easiest way to make this work is to use the distance between mouse click outside of borders to set a new mouse clicked position inside the borders offset by distance. (Basically having the same effect as inverting the position using the border as an axis. In this case it also adds in half of the circles width to this axis that it inverts on. Using hardcoded numbers, but if wanted as an improvement calculating from actual dimensions can also be done.)

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>
like image 156
user120242 Avatar answered Nov 19 '22 13:11

user120242