Cara Membuat Game 2048 dengan JavaScript

Game 2048

Game 2048 merupakan game daring yang dikembangkan pada bulan Maret 2014 lalu oleh seorang developer Italia Gabriele Cirrulli. pemain harus menggabungkan kotak-kotak bernomor sampai membentuk nomor 2048.

Nah, kali ini kita akan mencoba membuat game 2048 tampil di website. Bahasa pemrograman CSS digunakan untuk membuat background game, sedangkan bahasa pemrograman JavaScript digunakan untuk membuat dan menjalankan game.

Lalu, bagaimana caranya membuat game 2048 dengan bahasa pemrograman CSS dan JavaScript? Mudah kok, yuk buka komputer kamu dan ikuti beberapa langkah mudah di bawah ini.

Tutorial

1. Buka XAMPP Control Panel, serta aktifkan Apache.

2. Buka program teks editor yang ter-install di komputer kamu, disini saya menggunakan teks editor Notepad++. Ketikkan kode HTML5 berikut ini.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Membuat Game 2048 dengan JavaScript</title>
        <!--Using the p5.js third-party JavaScript library-->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.dom.min.js"></script>
        <link href="style.css" rel="stylesheet">
    </head>
    <body>
        <div class="container">
            <h1 id="title">2048</h1>
            <div id="score-container">
                <div id="score-title">SKOR</div>
                <div id="score"></div>
            </div>
            <p id="instructions">klik tombol panah untuk menggeser ubin dan mencapai <span>2048</span> ubin!</p>
        </div>
        <script src="script.js"></script>
    </body>
</html>

Simpan kode HTML5 di atas di folder xampplite – htdocs – buat folder baru dengan nama Game2048 – simpan kode di atas dengan nama index.html.

3. Untuk melihat hasil script code di atas, kamu bisa buka browser kamu ketiklah http://localhost/Game2048.

4. Ketikkan kode CSS berikut ini untuk membuat background game.

body {
    background-color: #b22222;
    color: #fff;
    font-family: Arial, Helvetica, sans-serif;
    padding-top: 2%;
}

/* header container */
.container {
    width: 450px;
    margin-left: auto;
    margin-right: auto;
}

/* 2048 title */
h1#title {
    font-size: 70px;
    font-weight: bold;
    margin: 0;
    display: block;
    float: left;
}

/* score container and score title */
div#score-container {
    position: relative;
    float: right;
    background-color: #776E65;
    color: rgb(205, 192, 180);
    height: 25px;
    padding: 15px 20px;
    padding-bottom: 30px;
    margin-top: 10px;
    text-align: center;
}

/*  numeric score */
div#score {
    font-weight: bold;
    font-size: 25px;
    color: white;
}

/* instructions subheader */
p#instructions {
    position: relative;
    float: left;
}

/* bolded 2048 in instructions */
span {
    font-weight: bold;
}

Simpan kode CSS di atas di folder xampplite – htdocs – buka folder Game2048 – simpan kode di atas dengan nama style.css.

5. Reload alamat url : http://localhost/Game2048. Tampilan background game.

6. Untuk menampilkan game, buka lembar kerja baru di teks editor dan ketikkan kode JavaScript berikut ini.

//Using the p5.js third-party JavaScript library

//constant declarations
const GRID_SIZE = 4;
const CELL_SIZE = 100;

//variable declarations
var canvas;
var grid;
var gameOver;
var score;
var gameWon;

//DOM
scoreContainer = document.getElementById("score");

/* automatically called by third-party p5 */
function setup() {
    canvas = createCanvas(GRID_SIZE * CELL_SIZE + 50, GRID_SIZE * CELL_SIZE + 50);
    background(187, 173, 160);
    centerCanvas(canvas);
    newGame();
    noLoop();
    updateGrid();
}

/* centers the game canvavs on window */
function centerCanvas() {
    var x = (windowWidth - width) / 2;
    var y = (windowHeight - height) / 2 + 40;
    canvas.position(x, y);
}

/* recenters the game canvas if the window is resized */
function windowResized() {
    centerCanvas();
}

/* creates a new game with the starting game board */
function newGame() {
    //fill grid with empty values (aka 0) 
    grid = new Array(GRID_SIZE * GRID_SIZE).fill(0);
    gameOver = false;
    gameWon = false;
    score = 0;
    //add the two starting tiles
    addRandomTile();
    addRandomTile();
}

/* updates the game grid with the correct tiles/tile colors, displays the score, and stops
   the game if there are no moves left or the 2048 tile is reached */
function updateGrid() {
    displayScore();
    drawGrid();
    if (gameOver) {
        displayGameOver();
    }
    else if (gameWon) {
        displayGameWon();
    }
}

/* automatically called when a key is pressed. Mmoves the tiles on the grid
   respective to which arrow key is pressed. If Enter is pressed when the game
   is over, a new game is started. */
function keyPressed() {
    if (!gameOver && !gameWon) {
        switch (keyCode) {
            case UP_ARROW:
                verticalSlide(keyCode);
                updateGrid();
                break;
            case DOWN_ARROW:
                verticalSlide(keyCode);
                updateGrid();
                break;
            case RIGHT_ARROW:
                horizontalSlide(keyCode);
                updateGrid();
                break;
            case LEFT_ARROW:
                horizontalSlide(keyCode);
                updateGrid();
                break;
        }
    }
    //if game won/over and enter key is pressed, refresh page to start new game
    else if (keyCode === ENTER) {
        if (gameWon) {
            location.reload();
        }
        else {
            location.reload();
        }
    }
}

/* slides the tiles vertically (up or down) and combines tiles of the
   same value if they collide. */
function verticalSlide(direction) {
    var previousGrid = [];
    var column;
    var filler;

    arrayCopy(grid, previousGrid);

    for (var i = 0; i < GRID_SIZE; i++) {
        column = [];
        //get column
        for (var j = i; j < GRID_SIZE * GRID_SIZE; j += 4) {
            column.push(grid[j]);
        }

        //combine like values in given vertical  direction
        column = combine(column, direction);

        //remove all empty values
        column = column.filter(notEmpty);

        //add the correct number of empty values after the nonempty values
        filler = new Array(GRID_SIZE - column.length).fill(0);
        if (direction === UP_ARROW) {
            column = column.concat(filler);
        }
        else {
            column = filler.concat(column);
        }

        //update the current column in the grid
        for (var k = 0; k < column.length; k++) {
            grid[k * GRID_SIZE + i] = column[k];
        }

        //combine values that were previously separated, but now adajacent
        combine(column, direction);
    }
    checkSlide(previousGrid);
}

/* slides the tiles horizontally (left or right) and combines tiles of the
   same value if they collide. */
function horizontalSlide(direction) {
    var previousGrid = [];
    var row;
    var filler;

    arrayCopy(grid, previousGrid);

    for (var i = 0; i < GRID_SIZE; i++) {
        //get row
        row = grid.slice(i * GRID_SIZE, i * GRID_SIZE + GRID_SIZE);

        //combine like values in given horizontal direction
        row = combine(row, direction);

        //remove all empty values
        row = row.filter(notEmpty);

        //add the correct number of empty values after the nonempty values
        filler = new Array(GRID_SIZE - row.length).fill(0);
        if (direction === LEFT_ARROW) {
            row = row.concat(filler);
        }
        else {
            row = filler.concat(row);
        }

        //remove the current row from the grid and add the updated row
        grid.splice(i * GRID_SIZE, GRID_SIZE);
        grid.splice(i * GRID_SIZE, 0, ...row);
    }
    checkSlide(previousGrid);
}

/* checks that a title is nonempty (value is not zero). Used to filter a row of tiles */
function notEmpty(x) {
    return x > 0;
}

/* checks, after a key is pressed, if anything on the grid actually moved or if the
   game is over */
function checkSlide(previousGrid) {
    if (!(grid.every((x, i) => x === previousGrid[i]))) {
        addRandomTile();
    }
    if (!movesLeft()) {
        gameOver = true;
    }
}

/* checks if there are any moves to play. In other words, there is either an empty
   tile or if two adjacent tiles have the same value. */
function movesLeft() {
    var movesLeft = false;
    var flag = false;
    var currentTile;
    var right;
    var bottom;

    for (var i = 0; i < GRID_SIZE; i++) {
        for (var j = 0; j < GRID_SIZE; j++) {
            if (!flag) {
                currentTile = grid[i * GRID_SIZE + j];

                //if grid still has empty spots, there are moves left
                if (currentTile === 0) {
                    movesLeft = true;
                    flag = true;
                }
                else {
                    if (j < GRID_SIZE - 1) {
                        right = grid[i * GRID_SIZE + j + 1];
                    }
                    else {
                        right = 0;
                    }
                    if (i < GRID_SIZE - 1) {
                        bottom = grid[(i + 1) * GRID_SIZE + j];
                    }
                    else {
                        bottom = 0;
                    }
                    //if a neighbor of the current tile has the same value, there are moves left
                    if (currentTile === right || currentTile === bottom) {
                        movesLeft = true;
                        flag = true;
                    }
                }
            }
        }
    }

    return movesLeft;
}

/* combines tiles of the same values together of a specific row in a given direction */
function combine(row, direction) {
    switch (direction) {
        case DOWN_ARROW:
            row = combineDownRight(row);
            break;
        case RIGHT_ARROW:
            row = combineDownRight(row);
            break;
        case UP_ARROW:
            row = combineUpLeft(row);
            break;
        case LEFT_ARROW:
            row = combineUpLeft(row);
            break;
    }

    return row;
}

/* combines tiles of the same value togther downwards or to the right */
function combineDownRight(row) {
    var x;
    var y;

    for (var i = row.length - 1; i > 0; i--) {
        //get current and subseqent tiles
        x = row[i];
        index = i - 1;
        y = row[index];

        //skip empty tiles until a nonempty tile or the beginning of the row is reached
        while (y === 0 && index > 0) {
            y = row[index--];
        }

        //if the adjacent tiles have equal value, combine and update score
        if (x === y && x !== 0) {
            row[i] = x + y;
            score += row[i];
            row[index] = 0;
            if (row[i] === 2048) {
                gameWon = true;
            }
        }
    }

    return row;
}

/* combines tiles of the same value together upwards or to the left */
function combineUpLeft(row) {
    var x;
    var y;

    for (var i = 0; i < row.length - 1; i++) {
        //get current and subsequent tiles
        x = row[i];
        index = i + 1;
        y = row[index];

        //skip empty tiles until a nonempty tile or the end of the row is reached
        while (y === 0 && index < row.length - 1) {
            y = row[index++];
        }

        //if the adjacent tiles have equal value, combine and update score
        if (x === y && x !== 0) {
            row[i] = x + y;
            score += row[i];
            row[index] = 0;
            if (row[i] === 2048) {
                gameWon = true;
            }
        }
    }

    return row;
}

/* adds a 2 or 4 tile to an empty spot in the grid randomly */
function addRandomTile() {
    var emptyTiles = [];
    var index;
    var newTile = [2, 4];

    //add the indices of all empty tiles to the emptyTiles array
    grid.forEach(function(value, index) {
        if (value === 0) {
            emptyTiles.push(index);
        }
    });

    if (emptyTiles.length > 0) {
        //get the index of a random empty tile in the grid
        index = emptyTiles[Math.floor(Math.random() * emptyTiles.length)];
        //set the value of that empty tile to 2 or 4, randomly chosen
        grid[index] = newTile[Math.floor(Math.random() * newTile.length)];
    }
}

/*----------------STYLE----------------*/
/* insert the score in the score container */
function displayScore() {
    scoreContainer.innerHTML = `${score}`;
}

/* displays the Game Over message */
function displayGameOver() {
    displayText("Game Over!nHit Enter to Play Again", color(119, 110, 101), 32, width / 2, height / 2);
}

/* displays the Game Won message */
function displayGameWon() {
    displayText("You Win!nHit Enter to Play Again", color(119, 110, 101), 32, width / 2, height / 2);
}

/* general function to display text on the canvas */
function displayText(message, color, size, xpos, ypos) {
    textAlign(CENTER);
    textSize(size);
    fill(color);
    text(message, xpos, ypos);
}

/* draw and style the game grid */
function drawGrid() {
    var c;

    for (var i = 0; i < GRID_SIZE; i++) {
        for (var j = 0; j < GRID_SIZE; j++) {
            //color of tile depends on value of tile
            switch (grid[i * GRID_SIZE + j]) {
                case 0:
                    c = color("#cd5c5c");
                    break;
                case 2:
                    c = color("#008000");
                    break;
                case 4:
                    c = color("#32cd32");
                    break;
                case 8:
                    c = color("#adff2f");
                    break;
                case 16:
                    c = color("#80CBC4");
                    break;
                case 32:
                    c = color("#4DB6AC");
                    break;
                case 64:
                    c = color("#26A69A");
                    break;
                case 128:
                    c = color("#009688");
                    break;
                case 256:
                    c = color("#00897B");
                    break;
                case 512:
                    c = color("#00796B");
                    break;
                case 1024:
                    c = color("#00695C");
                    break;
                case 2048:
                    c = color("#004D40");
                    break;
            }

            //fill tile
            fill(c);
            //thickness of tile border
            strokeWeight(2);
            //color of tile border
            stroke(c); 
            //draw rectangle with rounded edges for each tile
            rect(j * CELL_SIZE + j * 10 + 10, i * CELL_SIZE + i * 10 + 10, CELL_SIZE, CELL_SIZE, 5);

            if (grid[i * GRID_SIZE + j] !== 0) {
                displayText(`${grid[i * GRID_SIZE + j]}`,
                color(255, 255, 255),
                45,
                j * CELL_SIZE + j * 10 + 10 + CELL_SIZE / 2,
                i * CELL_SIZE + i * 10 + 20 + CELL_SIZE / 2);
            }
        }
    }
}

Simpan kode JavaScript di atas di folder xampplite – htdocs – buka folder Game2048 – simpan kode di atas dengan nama script.js.

7. Reload alamat url : http://localhost/Game2048. Tampilan awal game 2048.

Gunakan tombol panah atas-bawah dan tombol kanan-kiri di keyboard komputer untuk memainkan game ini.

Tampilan game over, klik tombol enter untuk memulai game yang baru.

8. Selesai, menarik sekali bukan?.

Demikian penjelasan dari tutorial ‘Cara Membuat Game 2048 dengan JavaScript’. Selamat mencoba.

Komentar

Leave a Reply

Your email address will not be published. Required fields are marked *

Inwepo adalah media platform yang membantu setiap orang untuk belajar dan berbagi tutorial, tips dan trik cara penyelesaian suatu masalah di kehidupan sehari-hari dalam bentuk teks, gambar. dan video.

Dengan bergabung bersama kami dan membuat 1 tutorial terbaik yang kamu miliki dapat membantu jutaan orang di Indonesia untuk mendapatkan solusinya. Ayo berbagi tutorial terbaikmu.

Ikuti Kami di Sosmed

Copyright © 2020 Inwepo - All Rights Reserved.

To Top