ساخت یک بازی مارپیچ تایمردار با استفاده از HTML 5 و JavaScript

دوشنبه 8 شهریور 1395

این مقاله نحوه ساخت یک مارپیچ همراه با یک تایمر دیجیتالی را نشان می دهد. برای ساخت این بازی از HTML5 و JavaScript استفاده شده است. (ولی به هیچ وجه از Flash استفاده نشده است. )

ساخت یک بازی مارپیچ تایمردار با استفاده از HTML 5 و JavaScript

نکته مهم : اگر مرورگر شما از JavaScript  و یا HTML5 پشتیبانی نکند، ممکن است بازی مارپیچ برای شما اجرا نشود. اگر فایل ضمیمه را دانلود کردید و بازی برای شما به درستی کار نکرد، می توانید نسخه آزمایشی آن که به صورت آنلاین است را در این قسمت مشاهده کنید :

https://programfox.github.io/HTML5-Maze/[^]

ساخت مارپیچ :

نخستین گام برای ساخت یک مارپیچ ، داشتن یک تصویر اولیه از مارپیچ است. برای ایجاد این تصویر اولیه، ما از ابزار ساخت آنلاین مارپیچ استفاده می کنیم :

http://www.hereandabove.com/maze/mazeorig.form.html[^]

تصویری که در زیر می بینید، مارپیچی است که این سایت، به ما داده است :

 

تنظیم موقعیت عناصر بر روی canvas

گام بعدی قرار دادن مستطیل به صورتی است که شما بتوانید آن را با استفاده از کلیدهای جهتی و یا WASD حرکت بدهید و همچنین قرار دادن نقطه پایانی در جای مناسب است. (که به صورت دایره نشان داده شده است). در مارپیچی که ما ساخته ایم، محل قرارگیری مستطیل 425, 3px و سایز آن 15px Z 15px است و نقطه مرکزی دایره 524px, 122px و میزان انحنای آن 7 px است. به عنوان اولین مرحله، باید canvas را ایجاد کنیم:

<canvas width="616" height="556" id="mazecanvas">Can't load the maze game, because your browser doesn't support HTML5.</canvas>
<noscript>JavaScript is not enabled. To play the game, you should enable it.</noscript>

اگر مرورگر شما از HTML5 پشتیبانی نکند، پیغام "Can't load the maze game ..." (خطا در بارگذاری بازی مارپیچ) به شما نشان داده خواهد شد. سایز مارپیچ 556 x 556 است ولی ما به دلیل وجود تایمر ، مقدار عرض را به 616  تغییر دادیم. گام بعدی کشیدن مارپیچ بر روی canvas با استفاده از JavaScript است. ما از متد drawImage برای کشیدن تصویر استفاده کرده ایم و از متدهای beginPath, closePath, rect  و  fill برای کشیدن مستطیل و همچنین از متدهای beginPath, closePath, arc  و  fill برای کشیدن دایره استفاده کرده ایم.

var canvas = document.getElementById("mazecanvas");
var context = canvas.getContext("2d");
var currRectX = 425;
var currRectY = 3;
var mazeWidth = 556;
var mazeHeight = 556;
var intervalVar;
function drawMazeAndRectangle(rectX, rectY) {
    makeWhite(0, 0, canvas.width, canvas.height);
    var mazeImg = new Image();
    mazeImg.onload = function () { // when the image is loaded, draw the image, the rectangle and the circle
        context.drawImage(mazeImg, 0, 0);
        drawRectangle(rectX, rectY, "#0000FF", false, true);
        context.beginPath();
        context.arc(542, 122, 7, 0, 2 * Math.PI, false);
        context.closePath();
        context.fillStyle = '#00FF00';
        context.fill();
    };
    mazeImg.src = "maze.gif";
}
function drawRectangle(x, y, style) {
    makeWhite(currRectX, currRectY, 15, 15);
    currRectX = x;
    currRectY = y;
    context.beginPath();
    context.rect(x, y, 15, 15);
    context.closePath();
    context.fillStyle = style;
    context.fill();
}

برای کشیدن مارپیچ در canvas ، تکه کد زیر را به انتهای script خودتان اضافه کنید:

drawMazeAndRectangle(425, 3); // { 425, 3 } is the position of the blue rectangle on the canvas

currRectX  و  currRectY مکان مستطیل را نمایش می دهند و intervalVar متغیر زمان است، که بعدا آن را ایجاد خواهیم کرد.

متدهای rect(), fill()  و  stroke()

بعد از آغاز کردن یک مسیر (با استفاده از beginPath()) می توانید از متد rect() استفاده کنید تا یک مستطیل ایجاد کنید. اما اگرمی خواهید فقط از متد rect() استفاده کنید، مستطیلی برای شما کشیده نخواهد شد. برای این که بتوانید مستطیل کشیده شده را بر روی canvas بیاورید ، باید از متدهای fill()  و یا  stroke() استفاده کنید. متد fill() ، یک مسیر را پر می کند و متد stroke() کار کشیدن در آن مسیر را انجام می دهد.

پارامتر های متد rect()

متد arc()

متد arc() یک کمان (منحنی) بر روی canvas می کشد. بعد از کشیدن یک منحنی، باید متد stroke()      و یا   fill() را فراخوانی کنید. شما می توانید از این متد برای کشیدن یک دایره و یا بخشی از یک دایره استفاده کنید.

پارامترهای متد arc()

تصویر :

 

 

تابع makeWhite()

 در تکه کد قبلی، ما از یک تابع makeWhite() استفاده کرده بودیم. این تابع توسط خودمان ایجاد شده است . این تابع ، یک مستطیل را بر روی canvas به رنگ سفید در می آورد. ممکن است این سوال برای شما پیش بیاید که چرا از متد clear استفاده نکرده ایم؟ متد clear() ، تمامی پیکسل های مستطیل داده شده را به صورت شفاف درمیاورد که ما در این برنامه به آن ها نیازی نداریم. کد های مربوط به تابع makeWhite() به صورت زیر هستند :

function makeWhite(x, y, w, h) {
    context.beginPath();
    context.rect(x, y, w, h);
    context.closePath();
    context.fillStyle = "white";
    context.fill();
}

حرکت دادن مستطیل با استفاده از کلید های جهت دار و یا WASD

کار بعدی که باید انجام بدهیم این است که حرکت مستطیل آّبی را با استفاده از کلیدهای جهتی و یا WASD امکان پذیر کنیم. اولین قدم ، محاسبه مختصات X  و Y مربوط به مستطیل آبی است. دومین قدم، حرکت دادن مستطیل آبی است، البته در صورتی که قابل حرکت کردن باشد، و سپس نشان دادن یک پیغام موفقیت است، در صورتی که کاربر بتواند به نقطه نهایی برسد.

function moveRect(e) {
    var newX;
    var newY;
    var canMove;
    e = e || window.event;
    switch (e.keyCode) {
        case 38:   // arrow up key
        case 87: // W key
            newX = currRectX;
            newY = currRectY - 3;
            break;
        case 37: // arrow left key
        case 65: // A key
            newX = currRectX - 3;
            newY = currRectY;
            break;
        case 40: // arrow down key
        case 83: // S key
            newX = currRectX;
            newY = currRectY + 3;
            break;
        case 39: // arrow right key
        case 68: // D key
            newX = currRectX + 3;
            newY = currRectY;
            break;
        default: return;
    }
    movingAllowed = canMoveTo(newX, newY);
    if (movingAllowed === 1) {      // 1 means 'the rectangle can move'
        drawRectangle(newX, newY, "#0000FF");
        currRectX = newX;
        currRectY = newY;
    }
    else if (movingAllowed === 2) { // 2 means 'the rectangle reached the end point'
        clearInterval(intervalVar); // we'll set the timer later in this article
        makeWhite(0, 0, canvas.width, canvas.height);
        context.font = "40px Arial";
        context.fillStyle = "blue";
        context.textAlign = "center";
        context.textBaseline = "middle";
        context.fillText("Congratulations!", canvas.width / 2, canvas.height / 2);
        window.removeEventListener("keydown", moveRect, true);
    }
}

اگر مستطیل به نقطه نهایی برسد، از متد clearInterval() برای متوقف کردن زمان استفاده می کنیم. اگر کاربر موفق شود به نقطه نهایی برسد، بلافاصله یک پیغام موفقیت در canvas ظاهر می شود  و اطلاع رسانی های مربوط به رویداد keydown حذف می شود، زیرا مستطیل آبی ، دیگر نباید قادر به حرکت باشد.

برای این که به مستطیل آبی قابلیت تحرک ببخشیم باید رویداد زیر را اضافه کنیم:

drawMazeAndRectangle(425, 3); // this line is already added
window.addEventListener("keydown", moveRect, true); // add this at the bottom of your script

بررسی قابلیت تحرک مستطیل آّبی : تابع canMoveTo()

در قطعه کد قبلی ، تابع canMoveTo() را دیدید. این تابع به این منظور ایجاد شده است که چک کند آیا مستطیل آبی قادر به حرکت است یا خیر. منطقی که در این تابع به کار گرفته شده است ، عبارت است از :

1-بررسی این که آیا مستطیل آبی در محدوده canvas هست یا خیر

2-اگر در داخل canvas قرار دارد، داده های مربوط به تصویر به وسیله ی x = destinationX, y = destinationY, width = 15, height = 15 گرفته شوند. 

3- از یک حلقه for برای بررسی همه ی پیکسل ها استفاده می کنیم. اگر پیکسل ها به رنگ مشکی بودند، مستطیل آبی قادر به حرکت نیست و اگر پیکسلی به رنگ لیمویی بود، به این معنی است که کاربر به هدف رسیده است.

کدهای موجود در تابع canMoveTo() به صورت زیر است :


function canMoveTo(destX, destY) {
    var imgData = context.getImageData(destX, destY, 15, 15);
    var data = imgData.data;
    var canMove = 1; // 1 means: the rectangle can move
    if (destX >= 0 && destX <= mazeWidth - 15 && destY >= 0 && destY <= mazeHeight - 15) { // check whether the rectangle would move inside the bounds of the canvas
        for (var i = 0; i < 4 * 15 * 15; i += 4) { // look at all pixels
            if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0) { // black
                canMove = 0; // 0 means: the rectangle can't move
                break;
            }
            else if (data[i] === 0 && data[i + 1] === 255 && data[i + 2] === 0) { // lime: #00FF00
                canMove = 2; // 2 means: the end point is reached
                break;
            }
        }
    }
    else {
        canMove = 0;
    }
    return canMove;
}

متد getImageData()

با استفاده از متد getImageData() ، شما می توانید اطلاعات مربوط به یک منطقه خاص از canvas را دریافت کنید. این متد یک شی ImageData برمی گرداند و property ای به نام data یک آرایه شامل داده های پیکسلی RGBA است . بنابراین :

data[0] شامل مقدار R (red) اولین پیکسل در ImageData است.

data[1] شامل مقدار  G (green) اولین پیکسل در ImageData است.

data[2] شامل مقدار B (blue) اولین پیکسل در ImageData است.

data[3] شامل مقدار A (alpha) اولین پیکسل در ImageData است.

data[4] شامل مقدار R (red) دومین پیکسل در ImageData است.

data[5] شامل مقدار G (green) دومین پیکسل در ImageData  است.

data[6] شامل مقدار B (blue) دومین پیکسل در ImageData است.

data[7] شامل مقدار A (alpha) دومین پیکسل در ImageData است.

پارامترهای متد getImageData()

 

پیاده سازی تایمر

قدم بعدی ، پیاده سازی تایمر است. برای این کار، ما از متد setInterval() استفاده کرده ایم که زمان را هر یک ثانیه یک بار، کاهش می دهد. اگر زمان به اتمام برسد، کل پس زمینه canvas را به رنگ سفید درمی اوریم و سپس پیغام "زمان به پایان رسید" را نمایش می دهیم.

function createTimer(seconds) {
    intervalVar = setInterval(function () {
        makeWhite(mazeWidth, 0, canvas.width - mazeWidth, canvas.height);
        if (seconds === 0) {
            clearInterval(intervalVar);
            window.removeEventListener("keydown", moveRect, true);
            makeWhite(0, 0, canvas.width, canvas.height);
            context.font = "40px Arial";
            context.fillStyle = "red";
            context.textAlign = "center";
            context.textBaseline = "middle";
            context.fillText("Time's up!", canvas.width / 2, canvas.height / 2);
            return;
        }
        context.font = "20px Arial";
        if (seconds <= 10 && seconds > 5) {
            context.fillStyle = "orangered";
        }
        else if (seconds <= 5) {
            context.fillStyle = "red";
        }
        else {
            context.fillStyle = "green";
        }
        context.textAlign = "center";
        context.textBaseline = "middle";
        var minutes = Math.floor(seconds / 60);
        var secondsToShow = (seconds - minutes * 60).toString();
        if (secondsToShow.length === 1) {
            secondsToShow = "0" + secondsToShow; // if the number of seconds is '5' for example, make sure that it is shown as '05'
        }
        context.fillText(minutes.toString() + ":" + secondsToShow, mazeWidth + 30, canvas.height / 2);
        seconds--;
    }, 1000);
}

در تابع createTimer() من یک تابع ایجاد کرده ام که در هر ثانیه فراخوانی خواهد شد. متد setInterval() یک ID منحصر بفرد برمی گرداند که شما می توانید متد clearInterval() را پاس بدهید اگر میخواهید تابع متوقف شود.در خط اول تابع ، یک منطقه مشخصی از canvas را پاک کردیم که مربوط به منطقه تایمر می باشد. در مارپیچ، canvas به دو بخش تقسیم می شود که در بخش اول، مارپیچ ظاهر می شود و در بخش دیگر، تایمر جایگزین می شود.

اگر seconds برابر با صفر باشد، ما متد clearInterval() را فراخوانی می کنیم، زیرا می خواهیم روند اجرای تابع متوقف شود. سپس keydown event listener را پاک می کنیم زیرا دیگر حرکت مستطیل آبی ، ضروری نیست. در این صورت، کل ناحیه canvas را پاک می کنیم تا پیغام "زمان به اتمام رسید " نمایش داده شود.

اگر seconds برابر با صفر نباشد، زمان باقی مانده را بر روی canvas نمایش می دهیم. اگر زمان باقی مانده بیشتر از 10 ثانیه باشد، زمان به رنگ سبز نمایش داده می شود. . اگر زمان مساوی و یا کوچک تر از 10 باشد، اما از 5 بیشتر باشد، رنگ به نارنجی تغییر خواهد کرد. اگر زمان کمتر از 5 باشد، رنگ قرمز نمایش داده خواهد  شد. بنابراین ما ابتدا زمان باقی مانده را محاسبه می کنیم . برای تبدیل به ثانیه، ما  مقدار seconds / 60 را محاسبه می کنیم و برای به دست آوردن زمان باقی مانده seconds - minutes * 60 را محاسبه می کنیم.

برای ایجاد تایمر، کد زیر را به انتهای script تان اضافه کنید.

drawMazeAndRectangle(425, 3); // added already
window.addEventListener("keydown", moveRect, true); // added already
createTimer(120); // add this line
                  // 120 seconds -> 2 minutes

امیدوارم از این مقاله لذت برده باشید.

 

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان
  • HTML
  • 5k بازدید
  • 2 تشکر

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید