How can I deflect the ball properly in a Javascript pong game? - javascript

I have written a simple pong game in Javascript. But I am having two problems with it.
I don't know why the ball doesn't deflect off of the computer's paddle which is the "playerB" according to the code.
How can I create some randomness when the ball deflects from the paddles? Currently the game seems very repetitive.
How can I fix these two problems?
Link to Jsfiddle
HTML
<!DOCTYPE html>
<html>
<head>
<title>Pong game</title>
<script type="text/javascript" src="jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="js/pong.js"></script>
<link rel="stylesheet" href="css/pong.css">
</head>
<body>
<header>
<p>
Computer:<span id="scoreB"></span> Human:<span id="scoreA"></span>
</p>
</header>
<div id="playground">
<div id="ball"></div>
<div id="playerA" class="paddle right"></div>
<div id="playerB" class="paddle left"></div>
</div>
</body>
</html>
CSS
html,body{
margin: 0 atuo;
height:100%;
}
#playground{
position: relative;
width:700px;
height:400px;
border: 1px solid grey;
overflow:hidden;
}
#ball{
position: absolute;
background: #fbb;
width:20px;
height:20px;
left:200px;
top:100px;
border-radius:10px;
}
.paddle{
position: absolute;
border:1px solid grey;
width:10px;
height:80px;
}
.left.paddle{
left:0px;
background-color: green;
}
.right.paddle{
right:0px;
background-color: blue;
}
Javascript
$(document).ready(function(){
var values = {
ball:{
speed:5,
x:50,
y:50,
directionX: 1,
directionY: 1,
radius: 10
},
playground:{
width: parseInt($("#playground").width()),
height: parseInt($("#playground").height())
},
playerA:{
y:0,
top: $("#playerA").offset().top,
height: $("#playerA").height(),
width: $("#playerA").width(),
score:0
},
playerB:{
y:0,
top: $("#playerB").offset().top,
height: $("#playerB").height(),
width: $("#playerB").width(),
score:0
}
};
//collision detection
function hitsTopBottom(){
var y = values.ball.y;
return y>values.playground.height-20 || y < 0;
}
function hitsRight(){
return values.ball.x > values.playground.width-20;
}
function hitsLeft(){
return values.ball.x < 0;
}
//ball hits playerA's paddle. Works properly but open to improvement
function hitsPlayerA(){
var ballX = values.ball.x;
var ballY = values.ball.y;
var playerAY = values.playerA.y;
return ballY<=playerAY+values.playerA.height && ballY>playerAY && ballX>=700-values.playerA.width-values.ball.radius;
}
//ball hits playerB's paddle. Doesn't work at all
function hitsPlayerB(){
var ballX = values.ball.x;
var ballY = values.ball.y;
var playerBY = values.playerB.y;
return ballY<=playerBY+values.playerB.height && ballY>=playerBY && ballX<=values.playerB.width-values.ball.radius;
}
//rendering the position of the ball
function renderball(){
$("#ball").css("left",values.ball.x);
$("#ball").css("top",values.ball.y);
$("#scoreB").text(values.playerB.score);
$("#scoreA").text(values.playerA.score);
}
//moving ball
function moveball(){
if(hitsTopBottom()){
values.ball.directionY *= -1;
}
if(hitsPlayerA()){
values.ball.directionX *= -1;
}
if(hitsPlayerB()){
values.ball.directionX = 1;
}
if(hitsRight()){
values.ball.x = 200;
values.ball.y = 200;
values.playerB.score += 1;
}
if(hitsLeft()){
values.ball.x = 200;
values.ball.y = 200;
values.playerA.score += 1;
}
values.ball.x += values.ball.speed*values.ball.directionX;
values.ball.y += values.ball.speed*values.ball.directionY;
renderball();
var playerB_pos = values.ball.y - values.playerB.height/2;
$("#playerB").css("top",playerB_pos);
}
//player movements
$("#playground").mousemove(function(e){
values.playerA.y = e.pageY-values.playerA.top-parseInt($("#playerA").height()/2);
$("#playerA").css("top",values.playerA.y);
});
setInterval(moveball,1000/30);
});

The ball was not deflecting off the computer paddle because its position was not being stored. By setting values.playerB.y = playerB_pos in the loop it will correctly bounce off now. However since it is the same as the y position of the ball the computer will never lose. To correct for this and add some randomness I used jQuery's animate function to tween the computer paddle between points and fake momentum:
if(!isAnimating) {
isAnimating = true;
$("#playerB").animate({"top": playerB_pos}, {
duration: (values.ball.speed*16),
easing: "linear",
step: function( now, fx ) {
values.playerB.y = parseInt($("#playerB").offset().top - parseInt($("#playerA").height()));
},
complete: function() {
isAnimating = false;
}
});
}
You can see it in action here: http://jsfiddle.net/yb290ow9/5/

You forgot to edit the actual playerB.y value (you just changed the css):
var playerB_pos = values.ball.y - values.playerB.height/2;
values.playerB.y = playerB_pos; // Forgot this!
$("#playerB").css("top",playerB_pos);
Working JSFiddle: http://jsfiddle.net/yb290ow9/6/
About the randomness: you could make the paddle "bouncy": change the speed of the ball, not just the direction

Related

Why does my <div> element start shaking when I try to move it?

I'm new to Stack Overflow.
I have a simple webpage which tries to move a colored div element back and forth.
However when I run it the div element starts moving correctly but after a few seconds it starts shaking madly, as if its boss refused to give it the salary.
Here is my code:
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Move</title>
<link rel="stylesheet" href="D:\Web\CSS\CSS.css"/>
<script src="D:\Web\JS\JS.js">
</script>
</head>
<body>
<div id="container">
<div id="box">
</div>
</div>
</body>
</html>
JavaScript:
window.onload = function() {
var x = 0;
var box = document.getElementById("box");
setInterval(moveRight, 5);
function moveRight() {
if(x >= 150) {
clearInterval();
setInterval(moveLeft, 5);
} else {
x += 1;
box.style.left = x + "px";
}
}
function moveLeft() {
if(x <= 0) {
clearInterval();
setInterval(moveRight, 5);
} else {
x -= 1;
box.style.left = x + "px";
}
}
}
CSS:
body {
background-color: #246;
}
#container {
width: 200px;
height: 50px;
background: #268;
position: relative;
}
#box {
width: 50px;
height: 50px;
background: #2ac;
position: absolute;
}
Plz help me
Thanks
You're not clearing the interval since you're not passing a variable to it, therefore it's not doing anything. If you set the interval to a variable, you can clear the interval when you switch the direction.
Reference: https://www.w3schools.com/jsref/met_win_clearinterval.asp
Here's an example:
(function() {
var direction;
var x = 0;
var box = document.getElementById("box");
// set the initial direction
direction = setInterval(moveRight, 5);
function moveRight() {
if (x >= 150) {
clearInterval(direction);
direction = setInterval(moveLeft, 5);
} else {
x += 1;
box.style.left = x + "px";
}
}
function moveLeft() {
if (x <= 0) {
clearInterval(direction);
direction = setInterval(moveRight, 5);
} else {
x -= 1;
box.style.left = x + "px";
}
}
})();
body {
background-color: #246;
}
#container {
width: 200px;
height: 50px;
background: #268;
position: relative;
}
#box {
width: 50px;
height: 50px;
background: #2ac;
position: absolute;
}
<!DOCTYPE html>
<html>
<head>
<title>Move</title>
</head>
<body>
<div id="container">
<div id="box">
</div>
</div>
</body>
</html>

jQuery hover is too slow

Please run the snippet and drag you mouse over the bar to make it red.
If you drag the mouse very slowly, you will fill it red, but if you move it fast, there will be white holes in it.
How to fix it? (the white holes)
I want to make a bar divided into 500 parts and if you hover it, it becomes red and being able to drag fast and fill it without holes.
Any help appreciated :)
$(function() {
var line = $("#line");
for ( var i = 0; i < 500; i++) {
line.append('<div class="tile" id="t'+(i+1)+'"></div>');
}
var tile = $(".tile");
tile.hover (
function() { //hover-in
$(this).css("background-color","red");
},
function() { //hover-out
}
);
});
#line{
height: 50px;
background-color: #000;
width: 500px;
}
.tile {
height: 50px;
float: left;
background-color: #ddd;
width: 1px;
}
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<div id="line"></div>
With your design one way would be to iterate over the first to your current hovered element and fill it, which would lead no spaces. That said you may want to consider using the HTML5 Canvas and drawing a rectangle from 0 to your mouse position, which will perform significantly faster.
$(function() {
var line = $("#line");
for ( var i = 0; i < 500; i++) {
line.append('<div class="tile" id="t'+(i+1)+'"></div>');
}
var tile = $(".tile");
tile.hover (
function() { //hover-in
var self = this;
$("#line").children().each(function(){
$(this).css("background-color","red");
if(this == self) return false;
});
},
function() { //hover-out
}
);
});
#line{
height: 50px;
background-color: #000;
width: 500px;
}
.tile {
height: 50px;
float: left;
background-color: #ddd;
width: 1px;
}
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<div id="line"></div>
Edit
Below is an example doing the same task but using the HTML 5 Canvas:
$("#line").mousemove(function(e){
var canvas = $(this)[0];
var ctx = canvas.getContext("2d");
var rect = canvas.getBoundingClientRect()
var x = e.clientX - rect.left;
ctx.fillStyle="red";
ctx.fillRect(0, 0, x, canvas.height);
});
#line{ background-color: #ddd; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="line" width=500 height=50 ></canvas>
This is another approach with nextUntil to select siblings..
$(function() {
var line = $("#line");
for ( var i = 0; i < 500; i++) {
line.append('<div class="tile" id="t'+(i+1)+'"></div>');
}
var tile = $(".tile");
line.on( 'mouseover', function(ev){
$('.tile').first().nextUntil( $('.tile').eq(ev.pageX) ).css("background-color","red");
});
line.on( 'mouseleave', function(ev){
$('.tile').css("background-color","#ddd");
});
});
#line{
height: 50px;
background-color: #000;
width: 500px;
}
.tile {
height: 50px;
float: left;
background-color: #ddd;
width: 1px;
}
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<div id="line"></div>
Another solution makes use of jQuery's mousemove method. This allows the bar to go both forward and backwards, simply following the cursors position.
This detects movement inside of the div, then I calculate the position of the cursor within the div as a percentage and apply it as the width of the red bar.
$( ".bar" ).mousemove(function( event ) {
var xCord = event.pageX;
xPercent = (xCord + $('.pct').width()) / $( document ).width() * 100;
$('.pct').width(xPercent+'%');
});
.bar{
background:'#999999';
width:50%;
height:50px;
}
.pct{
height:100%;
background:red;
width:0%;
}
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js">
</script>
<div class="bar" style="background:#999999">
<div class="pct"></div>
</div>

Javascript Animation trouble

My code is for a website where when you press the movement button the two squares will move and if you press the change colour button both squares will alternate colours. The shapes do these actions at the same time. However, only one square does this while the other does nothing... please help?
<!DOCTYPE html>
<html>
<style>
#container {
width: 400px;
height: 400px;
position: relative;
background: CadetBlue;
}
div#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: Maroon;
}
</style>
<style>
#containertwo {
width: 400px;
height: 400px;
position: relative;
background: CadetBlue;
}
div#animatetwo {
width: 50px;
height: 50px;
position: absolute;
left: 350px;
top: 0px;
background-color: Olive;
}
</style>
<body>
<p>
<button onClick="myMove()">Movement</button>
</p>
<p>
<button onClick="button_click()">Change Colour</button>
</p>
<div id ="container">
<div id ="animate"></div>
<div id ="animatetwo"></div>
</div>
<div id="box" onClick="button_click();"></div>
<script>
var colors = ["Maroon","Olive"];
function button_click() {
var box = document.getElementById("animate");
var background_color = box.style.backgroundColor;
var i = colors.indexOf(background_color);
if (i === colors.length-1) {
i = -1;
}
animate.style.backgroundColor = colors[i+1];
}
</script>
<div id="box" onClick="myMove();"></div>
<script>
function myMove() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 1);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
</script>
<div id="box" onClick="button_click();"></div>
<script>
var colorstwo = ["Maroon","Olive"];
function button_clicktwo() {
var box = document.getElementById("animatetwo");
var background_color = box.style.backgroundColor;
var i = colorstwo.indexOf(background_color);
if (i === colorstwo.length-1) {
i = -1;
}
animatetwo.style.backgroundColor = colorstwo[i+1];
}
</script>
<div id="box" onClick="myMove();"></div>
<script>
function myMovetwo() {
var elem = document.getElementById("animatetwo");
var pos = 0;
var id = setInterval(frame, 1);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
</script>
</body>
</html>
Ok... I'll talk about the problem you're having first, then I'll try to give you some advice.
1) First of all upon clicking the "Movement" button you're only calling the myMove() function which is only responsible for moving the animated div, as you select it with:
var elem = document.getElementById("animate");
So if you desire to move both at the same time make sure you're activating the right functions, since I imagine you wanted to call myMovetwo() at the same time perhaps you could do:
function move() {
myMove();
myMovetwo();
}
That way you would call move() and both calls will run.
2) Now about your code, you should really consider isolating the different aspects of your page, and by that I mean isolating CSS, HTML and JavaScript, you can do that using the <link> tag to import your styles and the <script src="path"></script> tag to include your javascript code.
The other advice would be to remove onclick from your html tags and get the click event from your javascript code.
There are some great sources to learn this basics concepts, perhaps codecademy is a great one for starters https://www.codecademy.com/courses/html-javascript-css/0/1
Cheers!

difficulty in comparing and assigning datatypes

to move red box over yellow container - onmouseover-> move right , onmouseout-> move left
I tried pos=document.getElementById("animate").style.left;
then by setinterval, I tried to move it using pos++ and pos--. but it didn't work. Please Help.
here's the code.
var id_l, id_r;
function right() {
clearInterval(id_l);
var box = document.getElementById("animate");
var pos=box.style.left;
id_r=setInterval(move,5);
function move() {
if(pos==900) {
clearInterval(id_r);
}
else {
pos++;
box.style.left = pos + "px";
}
}
}
function left() {
clearInterval(id_r);
var box = document.getElementById("animate");
var pos=box.style.left;
id_l=setInterval(move,5);
function move() {
if(pos==0) {
clearInterval(id_l);
}
else {
pos--;
box.style.left = pos + "px";
}
}
}
#container {
position: relative;
width: 1000px;
height: 100px;
background-color: yellow;
}
#animate {
position: absolute;
width: 100px;
height: 100px;
background-color: red;
left: "200px";
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles/styles.css">
</head>
<body>
<div id="container" onmouseover="right()" onmouseout="left()">
<div id="animate">
</div>
</div>
<script src="scripts/javascript.js"></script>
</body>
</html>
You were doing it wrong. When you get the position, it gives you in format 100px etc. You have to trim px and then do your computation
var id_l, id_r;
function right() {
clearInterval(id_l);
var box = document.getElementById("animate");
var pos=box.style.left;
pos = pos.toString().substr(0, pos.length-2); // do not read `px`
id_r=setInterval(move,5);
function move() {
if(pos==900) {
clearInterval(id_r);
}
else {
pos++;
box.style.left = pos + "px";
}
}
}
function left() {
clearInterval(id_r);
var box = document.getElementById("animate");
var pos=box.style.left;
pos = pos.toString().substr(0, pos.length-2); // do not read px
id_l=setInterval(left,5);
function left() {
if(pos==0) {
clearInterval(id_l);
}
else {
pos--;
box.style.left = pos+"px";
}
}
}
#container {
position: relative;
width: 1000px;
height: 100px;
background-color: yellow;
}
#animate {
position: absolute;
width: 100px;
height: 100px;
background-color: red;
left: "200px";
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles/styles.css">
</head>
<body>
<div id="container" onmouseover="right()" onmouseout="left()">
<div id="animate">
</div>
</div>
<script src="scripts/javascript.js"></script>
</body>
</html>
You can do correct by adding parseInt in both move() because it's get a string!
element.style.left is only work in inline style ! so use getComputedStyle is better
var pos = window.getComputedStyle(box).getPropertyValue('left');
function move() {
pos = parseInt(pos);
if(pos==900) {
clearInterval(id_r);
}
else {
pos++;
box.style.left = pos + "px";
}
}

How to implement a sliding animation in javascript correctly?

In my pursuit to learn javascript I am making the same slider, but with the animation on javascript (using css it is not an issue for me - it was made on the site google), as the one below:
Original Google slider (animation with css):
http://www.google.com/about/datacenters/inside/
My work so far:
http://jsfiddle.net/TS7Xu/3/
<!-- language-all: lang-html -->
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#promo{
display:block;
height: 354px;
width: 790px;
}
.promo-item {
width: 81px;
height: 354px;
float: left;
}
.promo-item.wide {
width: 613px;
}
.threeP {
background-color: rgb(206, 203, 203);
}
.oneP {
background-color: rgb(241, 220, 182);
}
.twoP {
background-color: rgb(187, 217, 226);
}
</style>
</head>
<body>
<div id="promo">
<div class="promo-item twoP wide" id="twoP">
<div>
</div>
</div>
<div class="promo-item threeP" id="threeP">
<div>
</div>
</div>
<div class="promo-item oneP" id="oneP">
<div>
</div>
</div>
</div>
<script type="text/javascript">
var oneP = document.getElementById('oneP');
var twoP = document.getElementById('twoP');
var threeP = document.getElementById('threeP');
step = 1;
function expandPanel1(){
var h = oneP.clientWidth + step;
oneP.style.width = h+"px";
if (h < 614 || h !=614) {
setTimeout("expandPanel1()", 5);
} else { oneP.style.width = 613+"px"; }
}
function expandPanel2(){
var h = twoP.clientWidth + step;
twoP.style.width = h+"px";
if (h < 614 || h !=614) {
setTimeout("expandPanel2()", 5)
} else { twoP.style.width = 613+"px"; }
}
function expandPanel3(){
var h = threeP.clientWidth + step;
threeP.style.width = h+"px";
if (h < 614 || h !=614) {
setTimeout("expandPanel3()", 5)
} else { threeP.style.width = 613+"px"; }
}
//---------------------------------------------
function expandPanel1Minus(){
var h = oneP.clientWidth - step;
oneP.style.width = h+"px";
if (h > 80 || h !=80) {
setTimeout("expandPanel1Minus()", 5)
} else { oneP.style.width = 81+"px"; }
}
function expandPanel2Minus(){
var h = twoP.clientWidth - step;
twoP.style.width = h+"px";
if (h > 80 || h !=80) {
setTimeout("expandPanel2Minus()", 5)
} else { twoP.style.width = 81+"px"; }
}
function expandPanel3Minus(){
var h = threeP.clientWidth - step;
threeP.style.width = h+"px";
if (h > 80 || h !=80) {
setTimeout("expandPanel3Minus()", 5)
} else { threeP.style.width = 81+"px"; }
}
//---------------------------------------------
oneP.onmouseover = function () {
expandPanel1()
expandPanel3Minus()
expandPanel2Minus()
}
twoP.onmouseover = function () {
expandPanel2()
expandPanel3Minus()
expandPanel1Minus()
}
threeP.onmouseover = function () {
expandPanel3()
expandPanel2Minus()
expandPanel1Minus()
}
</script>
I know this example has errors because if a long drive with the mouse on the slider, it begins to "violently" run :) I deliberately lowered animation speed.
Can someone give me some guidance on how to implement this correctly?
Here's a pure JS implementation - JSFiddle link. In case the fiddle didn't get saved, here's the JS bit only. The rest of the HTML is same as the OP. the function go is called on body load.
var f, s, t;
var which;
function go() {
f = document.getElementById('oneP');
s = document.getElementById('twoP');
t = document.getElementById('threeP');
which = s;
f.onmouseover = function() {
foo(this)
};
s.onmouseover = function() {
foo(this)
};
t.onmouseover = function() {
foo(this)
};
}
function foo(e) {
if (e.clientWidth < 613) {
e.style.width = (e.clientWidth) + 10 + "px";
which.style.width = (which.clientWidth - 10) + "px";
setTimeout(function() {
foo(e);
}, 5);
}
else if (e.clientWidth > 613) {
e.style.width = "613px";
which.style.width = "81px";
which = e;
}
}​
There is a bit of work left I think, the animation is not fast enough so it is possible to mouse over on another section while the animation is running. I leave that bit to you :)
If you want to save a lot of time, you should do it with jQuery. Try this http://jsfiddle.net/QXRVb/ sollution. In that example, I didn't preferd to resizing divs. I used Z-indexes and jQuery animate to move them. In that way its easier to make a right position for them.
<style>
#promo{
width:900px;
height:300px;
position:absolute;
top:0px;
left:0px;
overflow:hidden;
}
#oneP{
width:600px;
height:300px;
position:absolute;
top:0px;
left:0px;
background:#999;
z-index:1;
}
#twoP{
width:600px;
height:300px;
position:absolute;
top:0px;
left:150px;
background:#ddd;
z-index:0;
}
#threeP{
width:600px;
height:300px;
position:absolute;
top:0px;
left:750px;
background:#666;
z-index:1;
}
</style>
<html>
<div id="promo">
<div id="oneP">
</div>
<div id="twoP">
</div>
<div id="threeP">
</div>
</div>
</html>
<script>
$('#oneP').mouseover(function() {
$('#oneP').animate({
left: 0
},200);
$('#threeP').animate({
left: 750
},200);
$('#twoP').animate({
left: 450
},200);
});
$('#twoP').mouseover(function() {
$('#oneP').animate({
left: -450
},200);
$('#threeP').animate({
left: 750
},200);
$('#twoP').animate({
left: 150
},200);
});
$('#threeP').mouseover(function() {
$('#threeP').animate({
left: 300
},200);
$('#oneP').animate({
left: -450
},200);
$('#twoP').animate({
left: -150
},200);
});​
</script>`
With this method you can easily put image tag inside divs.

Categories