After this, we check for the top edge, left edge and right edge of the playground. If ball reaches the left or the right edge of the playground the ball position is reset (centered on the playground) and the score board is updated accordingly.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
//check top edge if (ball.y + ball.speed*ball.directionY < 0) { ball.directionY = 1 }; //check right edge if (ball.x + ball.speed*ball.directionX > playgroundWidth ) { //if player B scores, re-initialize ball position, moving orientation on X axis, increment score by 1 and update it on score board ball.x = 290; ball.y = 140; $("#ball").css({"left": ball.x, "top": ball.y}); ball.directionX = -1; pingpong.scoreA++; if (parseInt(pingpong.scoreA) < 10) { pingpong.scoreA = "" + 0 + pingpong.scoreA; $("#scoreA").html(pingpong.scoreA); } else { $("#scoreA").html(pingpong.scoreA); } } //check left edge if (ball.x + ball.speed*ball.directionX < 0) { //if player A scores, re-initialize ball position and moving orientation on X axis, increment score by 1 and update it on score board ball.x = 290; ball.y = 140; $("#ball").css({"left": ball.x, "top": ball.y}); ball.directionX = 1; pingpong.scoreB++; if (parseInt(pingpong.scoreB) < 10) { pingpong.scoreB = "" + 0 + pingpong.scoreB; $("#scoreB").html(pingpong.scoreB); } else { $("#scoreB").html(pingpong.scoreB); } } |
The next step is to increment ball position on X and Y axis based on ball speed and orientation:
|
1 2 3 |
//increment ball position on X and Y axes based on ball speed and orientation ball.x += ball.speed*ball.directionX; ball.y += ball.speed*ball.directionY; |
After this we need to check if ball will “hit” the paddles and if it does, it has to bounce back on playground. In some circumstances, when ball is moving from top to bottom and passes very near to the top edge of the paddles without hitting it, after the ball passes behind paddle it bounces back on playground which is not a desirable effect. To avoid this we need to make a correction. Practically the game engine is set to perform calculation based on distance between the top/bottom edge of the paddle against top/bottom edge of the playground and the ball position, and to perform actions accordingly. So, making the ball top/bottom position against top/bottom edges of playground greater/smaller than the top/bottom paddles’ position against top/bottom playground’s edges will make the ball move more accurately.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
//check left paddle //position on X axis var paddleAX = parseInt($("#paddleA").css("left")) + parseInt($("#paddleA").css("width")); //need to correct the paddle position against ball position on Y axis var ballCorrection = parseInt($("#paddleA").css("left")) - parseInt($("#ball").css("left")); if (ballCorrection > 0) { var ballCorrection = ballCorrection; var paddleAYBottom = parseInt($("#paddleA").css("top")) + parseInt($("#paddleA").css("height")) - Math.round(parseInt($("ballspeed").val())*ballCorrection/parseInt($("paddlespeed").val())); var paddleAYTop = parseInt($("#paddleA").css("top")) - Math.round(parseInt($("ballspeed").val())*ballCorrection/parseInt($("paddlespeed").val())); } else { var paddleAYBottom = parseInt($("#paddleA").css("top")) + parseInt($("#paddleA").css("height")); var paddleAYTop = parseInt($("#paddleA").css("top")); } if (ball.x + ball.speed*ball.directionX < paddleAX) { if ((ball.y + ball.speed*ball.directionY <= paddleAYBottom) && (ball.y + ball.speed*ball.directionY >=paddleAYTop)) { ball.directionX = 1 } }; //check right paddle var paddleBX = parseInt($("#paddleB").css("left")) - parseInt($("#paddleB").css("width")); var ballCorrection = parseInt($("#ball").css("left")) - parseInt($("#paddleB").css("left")); if (ballCorrection > 0) { var ballCorrection = ballCorrection; var paddleBYBottom = parseInt($("#paddleB").css("top")) + parseInt($("#paddleB").css("height")) - Math.round(parseInt($("ballspeed").val())*ballCorrection/parseInt($("paddlespeed").val())); var paddleBYTop = parseInt($("#paddleB").css("top")) - Math.round(parseInt($("ballspeed").val())*ballCorrection/parseInt($("paddlespeed").val())); } else { var paddleBYBottom = parseInt($("#paddleB").css("top")) + parseInt($("#paddleB").css("height")); var paddleBYTop = parseInt($("#paddleB").css("top")); } if (ball.x + ball.speed*ball.directionX >=paddleBX) { if ((ball.y + ball.speed*ball.directionY <= paddleBYBottom) && (ball.y + ball.speed*ball.directionY >=paddleBYTop)) { ball.directionX = -1 } }; |
The last thing to do is to move the ball with speed and direction:
|
1 2 |
//actually move the ball with speed and direction $("#ball").css({"left": ball.x, "top": ball.y}); |
Styling the elements
I used some of the CSS3 style properties to give a neat appearance to this game. Unfortunately, not all the browsers’ engines implemented them in the general way, and to target them is necessary to use custom addressing (-o-, -webkit- and so on) to achieve the same effect. border-radius seems to be implemented in all major browsers, but transform, box-shadow, linear-gradient etc. are not. The game was tested on Mozilla Firefox, Safari, Google Chrome, Opera and Internet Explorer. Obviously the IE is making (as always) a different opinion so, it might look ugly (but the game functions well) to some corners
.
Resources
- Cascading Style Sheets (CSS)
- HTML5
- Useful CSS3, HTML5, jQuery tutorials
- HTML5 Games Development by Example: Beginner’s Guide
- Background Patterns
Please don’t use Space to pause the game if you play it on Internet Explorer (the alert message appears in game loop until the end of the game). I found a bug and need to fix it.
Until I develop a convenient way yo pause the game, the pause action is disabled by default.
A solution was found. Now the game flows as it should be. Enjoy it.





