Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                
<body>
    <a target="_blank" class="github-link" href="https://github.com/ashwin-pc/pong" title="Source on GitHub">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 60.5 60.5" width="40" height="40">
            <polygon class="bg" points="60.5,60.5 0,0 60.5,0 "></polygon>
            <path class="icon" d="M43.1,5.8c-6.6,0-12,5.4-12,12c0,5.3,3.4,9.8,8.2,11.4c0.6,0.1,0.8-0.3,0.8-0.6c0-0.3,0-1,0-2c-3.3,0.7-4-1.6-4-1.6c-0.5-1.4-1.3-1.8-1.3-1.8c-1.1-0.7,0.1-0.7,0.1-0.7c1.2,0.1,1.8,1.2,1.8,1.2c1.1,1.8,2.8,1.3,3.5,1c0.1-0.8,0.4-1.3,0.8-1.6c-2.7-0.3-5.5-1.3-5.5-5.9c0-1.3,0.5-2.4,1.2-3.2c-0.1-0.3-0.5-1.5,0.1-3.2c0,0,1-0.3,3.3,1.2c1-0.3,2-0.4,3-0.4c1,0,2,0.1,3,0.4c2.3-1.6,3.3-1.2,3.3-1.2c0.7,1.7,0.2,2.9,0.1,3.2c0.8,0.8,1.2,1.9,1.2,3.2c0,4.6-2.8,5.6-5.5,5.9c0.4,0.4,0.8,1.1,0.8,2.2c0,1.6,0,2.9,0,3.3c0,0.3,0.2,0.7,0.8,0.6c4.8-1.6,8.2-6.1,8.2-11.4C55.1,11.2,49.7,5.8,43.1,5.8z"></path>
        </svg>
    </a>
    <h1 class="title">Pong</h1>
    <div class="score" id="p1-score">0</div>
    <div class="score" id="p2-score">0</div>
    <canvas id="pongContainer"></canvas>
</body>
              
            
!

CSS

              
                body {
    margin: 0;
    background: #FFC107;
}

.title {
    text-align: center;
    font-size: 4rem;
    font-family: "Roboto Condensed", Arial, sans-serif;
    text-transform: uppercase;
    color: white;
    text-shadow: 1px 1px 1px #b7720d;
}

.score {
    color: white;
    font-size: 4rem;
    position: fixed;
    top: 0;
    font-family: "Roboto Condensed", Arial, sans-serif;
    text-shadow: 1px 1px 1px #b7720d;
    font-weight: bold;
    left: 0;
    background: #2196F3;
    padding: 10px 30px;
    border-radius: 0 0 10px 0;
    z-index: -1;
    box-shadow: 0px 3px 7px 0px rgba(0, 0, 0, 0.3);
}

#p2-score {
    border-radius: 0 0 0 10px;
    right: 0;
    left: inherit;
    background-color: #FF5722;
}

canvas {
    display: block;
    width: 80vw;
    max-width: 900px;
    margin: auto;
    background-color: rgb(255, 255, 255);
    border-radius: 4px;
    box-shadow: 0px 3px 20px 0px rgba(0, 0, 0, 0.3);
}

.github-link {
    width: 40px;
    height: 40px;
    position: absolute;
    display: block;
    top: 0;
    right: 0;
    z-index: 1000;
}

.github-link .bg {
    fill: #424242;
    fill-opacity: 0.2;
}

.github-link .icon {
    fill: #fff;
    fill-opacity: 0.6;
}

@media screen and (max-width: 560px){
    .title {
        margin-bottom: 6rem;
    }

    .score {
        border-radius: 0 10px 10px 0;
        top: 9rem;
        font-size: 3rem;
    }

    #p2-score {
        border-radius: 10px 0 0 10px;
    }
}
              
            
!

JS

              
                var canvas = document.getElementById("pongContainer");

document.addEventListener("pongReady", function () {
    pong.initializeGame(canvas);

    pong.setGameOver(function (scores) {
        document.getElementById("p1-score").innerText = scores.p1
        document.getElementById("p2-score").innerText = scores.p2
    })

    addStartListener();
	
		setTimeout(() => {
    	toast("Player 1: use 'Q' and 'A' to move paddle");
    	toast("Player 2: use 'Up arrow' and 'Down arrow' to move paddle");
		}, 0)
});

// Ball Class
function Ball(params) {
    var b = this;
    var size = 10;
    var sb2 = size / 2;
    var color = 'rgb(200, 0, 0)';
    var ctx = params.ctx;
    var canvas = params.canvas;
    var x = canvas.width / 2;
    var y = canvas.height / 2;
    var v = 5;
    var deg = 0 * (Math.PI / 180);
    var MAXDEG = 75 * (Math.PI / 180); // To convert degrees to radians

    // Draw the current ball state
    this.draw = function () {
        ctx.fillStyle = color;
        ctx.fillRect(x - sb2, y - sb2, size, size);
    }

    // Update the velocity, angle, position of the ball
    this.update = function (p1, p2) {
        // Check collision with paddles
        var p1Bounds = p1.getBounds();
        var p2Bounds = p2.getBounds();

        // Check which side of the board the ball is
        if (x > canvas.width / 2) {
            // Check if the ball is within the paddle area (x-axis)
            if (x + sb2 >= p2Bounds.sleft) {
                // Check if the ball is in the paddle surface region (y-axis)
                if (!(y < p2Bounds.top || y > p2Bounds.bottom)) {
                    rely = y - p2Bounds.y;
                    nory = 2 * rely / p2Bounds.l
                    deg = -(nory * MAXDEG);
                    v = - v;
                } else {
                    return "p1"
                }
            }
        } else {
            // Check if the ball is within the paddle area (x-axis)
            if (x - sb2 <= p1Bounds.sright ) {
                // Check if the ball is in the paddle surface region (y-axis)
                if (!(y < p1Bounds.top || y > p1Bounds.bottom)) {
                    rely = y - p1Bounds.y;
                    nory = 2 * rely / p1Bounds.l
                    deg = (nory * MAXDEG);
                    v = - v;
                } else {
                    return "p2"
                }
            }
        }
        // Check if the ball is within the paddle area (x-axis)
        if (y - sb2 < 0 || y + sb2 > canvas.height) {
            deg = -deg;
        }

        var dx = v * Math.cos(deg);
        var dy = v * Math.sin(deg);

        x += dx;
        y += dy;

        return (x > canvas.width || x < 0);
    }

};

// Paddle Class
function Paddle(pong, player) {
    var p = this;
    var length = 50;
    var width = 10;
    var lb2 =  length/2;
    var wb2 = width/2;
    var dy = 5;
    var color = "rgb(0,0,0)";
    
    var x = (player) ? 15 : pong.canvas.width - 15;
    var y = pong.canvas.height/2;
    p.ctx = pong.ctx;
    p.canvas = pong.canvas;
    p.keypressed = false;

    p.draw = function () {
        p.ctx.fillStyle = color;
        p.ctx.fillRect(x - wb2, y - lb2, width, length);
    }

    p.move = function (up) {
        y = (up) ? y - dy : y + dy;
        y = (y - lb2 < 0) ? lb2 : y;
        y = (y + lb2 > p.canvas.height) ? p.canvas.height - lb2 : y;
    }

    p.getBounds = function () {
        return {
            x: x,
            y: y,
            w: width,
            l: length,
            sleft: x - wb2,
            sright: x + wb2,
            top: y - lb2,
            bottom: y + lb2
        }
    }
};

// Pong Functions
(function (window) {
    // Private Variables
    var width = 500;
    var height = 300;
    var pong = {};
    var keypressed = false;
    var ball, p1, p2;
    var score = {
        p1: 0,
        p2: 0
    };
    var gameover = null;

    // State machine
    var states = {
        running: "running",
        reset: "reset",
        gameover: "gameover",
        paused: "paused",
        stopped: "stopped",
    }

    var currentState = states.stopped;

    // Private functions
    function drawBoard() {
        pong.ctx.clearRect(0, 0, width, height);
        pong.ctx.beginPath();
        pong.ctx.setLineDash([5]);
        pong.ctx.moveTo(width / 2, 0);
        pong.ctx.lineTo(width / 2, height);
        pong.ctx.stroke();

        // Draw ball and paddles
        ball.draw();
        p1.draw();
        p2.draw();
    }

    /**
     * Sceduler (Private)
     * Self calling function that executes a task from the scheduled list of tasks to execute
     */
    function scheduler() {
        // Check state
        switch (currentState) {
            case "running":
                window.requestAnimationFrame(scheduler)
                
                // Move the paddle
                if (p1.keypressed) {
                    p1.move(p1.keypressed.up);
                }
                if (p2.keypressed) {
                    p2.move(p2.keypressed.up);
                }

                // Move the ball
                var crashed = ball.update(p1, p2);
                if (crashed) {
                    currentState = states.gameover
                    score[crashed]++;
                }

                // Draw the Current board state
                drawBoard();
                break;

            case "reset":
                addStartListener();
                publicFunctions.initializeGame(pong.canvas);
                break;

            case "gameover":
                window.requestAnimationFrame(scheduler)
                currentState = states.reset;
                if (gameover) {
                    gameover(score);
                }

            case "stopped":
                break;

            case "paused":
            default:
                break;
        }
    }


    // Public funtions
    var publicFunctions = {
        initializeGame: function (canvas) {
            canvas.width = width;
            canvas.height = height;

            pong.canvas = canvas;
            pong.ctx = canvas.getContext('2d');

            ball = new Ball(pong);
            p1 = new Paddle(pong, true);
            p2 = new Paddle(pong, false);

            document.addEventListener("keydown", function (e) {
                if (e.code == "KeyQ" || e.key == "a") {
                    p1.keypressed = {
                        up: (e.code == "KeyQ") ? true : false,
                        code: e.code
                    }
                }

                if (e.code == "ArrowDown" || e.key == "ArrowUp") {
                    p2.keypressed = {
                        up: (e.code == "ArrowUp") ? true : false,
                        code: e.code
                    }
                }
            })

            document.addEventListener("keyup", function (e) {
                if (p1.keypressed && e.code == p1.keypressed.code) {
                    p1.keypressed = false;
                }

                if (p2.keypressed && e.code == p2.keypressed.code) {
                    p2.keypressed = false;
                }
            })

            drawBoard();
        },

        start: function () {
            currentState = states.running;
            scheduler();
        },

        setGameOver: function (callback) {
            gameover = callback;
        }
    }

    if (window.pong == undefined) {
			window.pong = publicFunctions
			document.dispatchEvent(new Event("pongReady"));
    }
})(window);

function addStartListener() {
    document.addEventListener("keydown", function startKeystroke(e) {
        var keyPressed = ["KeyQ", "a", "Space", "ArrowDown", "ArrowUp"].filter(function (key) {
            return key == e.code
        }).length;

        if (keyPressed) {
            pong.start();
            document.removeEventListener("keydown", startKeystroke);
        }
    })
}
              
            
!
999px

Console