تکمیل دکمه Attack

Complete the Attack Button

Vue.JS 2: تکمیل دکمه ی Attack – قسمت 18

در قسمت قبل کدهای خود را تا قسمتی پیش بردیم که ضربه وارد شده ما به هیولا مشخص شد:

attack: function () {
    var max = 10;
    var min = 3;
    var damage = Math.max(Math.floor(Math.random() * max) + 1, min);
},

برای کم کردن این ضربه از health هیولا باید به سادگی آن را از monsterHealth کم کنیم:

attack: function () {
    var max = 10;
    var min = 3;
    var damage = Math.max(Math.floor(Math.random() * max) + 1, min);
    this.monsterHealth -= damage;
},

اما می خواهیم کاری کنیم که ضربه زدن هیولا بیشتر از ضربه زدن ما باشد. بنابراین می توان max (حداکثر ضربه هیولا) و min (حداقل ضربه هیولا) را به ترتیب روی 12 و 5 گذاشت:

attack: function () {
    var max = 10;
    var min = 3;
    var damage = Math.max(Math.floor(Math.random() * max) + 1, min);
    this.monsterHealth -= damage;

    var max = 12;
    var min = 5;
    damage = Math.max(Math.floor(Math.random() * max) + 1, min);
    this.playerHealth -= damage;
},

آیا مشکل کد بالا را می بینید؟ ما در کد بالا دائما یک حرف را تکرار کرده و چندین بار متغیر های max و min را تعریف کرده ایم. این نحوه نوشتن از کدها اصلا صحیح نیست و حتما به این قسمت برگشته و آن را تصحیح می کنیم اما فعلا بیایید عملکرد این کد را بررسی کنیم. آیا این کد کار خواهد کرد؟

مرورگر را باز کرده و پس از start a new game شروع به زدن دکمه Attack کنید. به احتمال بسیار زیاد بازنده بازی خواهید بود چرا که هیولا ضربات سنگین تری می زند (min و max بیشتری دارد) اما زمانی که health شما به صفر برسد هیچ اتفاقی نمی افتد بلکه باز هم از health کم می شود و با یک عدد منفی روبرو می شویم! با این حساب این بازی هیچ وقت تمام نمی شود. راه حل این است که پس از ضربه زدن به هیولا و دریافت ضربه از هیولا حتما health ها را چک کنیم تا به عدد منفی نرسند:

attack: function () {
    var max = 10;
    var min = 3;
    var damage = Math.max(Math.floor(Math.random() * max) + 1, min);
    this.monsterHealth -= damage;

    if (this.monsterHealth <= 0) {
        alert('You Won!');
        this.gameIsRunning = false;
        return;
    }

    var max = 12;
    var min = 5;
    damage = Math.max(Math.floor(Math.random() * max) + 1, min);
    this.playerHealth -= damage;

    if (this.playerHealth <= 0) {
        alert('You Lost!');
        this.gameIsRunning = false;
    }
},

در کد بالا پس از کم کردن damage از health هیولا یک شرط if را قرار داده ام که چک می کند تا health هویلا به صفر یا کمتر نرسیده باشد. اگر این چنین شد یک alert ساده دریافت می کنیم که می گوید You Won (یعنی «شما بُردید») سپس خصوصیت gameIsRunning را نیز روی false می گذارم چرا که بازی تمام شده است. دستور return من برای خارج شدن از این متد (متد Attack) است. چرا؟ به دلیل اینکه اگر بازی تمام شده است دیگر نیازی نیست که هیولا به ما ضربه ای را وارد کند بنابراین کدهای بعدی که مخصوص ضربه هیولا هستند نباید اجرا شوند. دستور return ما را به طور کامل از این متد خارج می کند و دستور های بعد از آن اجرا نمی شوند.

پس از آنکه هیولا نیز ضربه ای به ما زد یک شرط if را چک می کنیم که اگر health ما صفر یا کمتر شد، پیام You Lost (یعنی «شما باختید») نمایش داده شود. در نهایت gameIsRunning باز هم روی false می رود چرا که بازی تمام شده است. به دستور return نیز نیازی نداریم چرا که دیگر کدی برای اجرا باقی نمانده و همانجا از متد attack خارج می شویم.

حالا کد ما از نظر منطقی کار می کند اما همانطور که گفتم اصلا کد بهینه ای نیست (تکرار در آن بسیار زیاد است). برای پاک کردن این کدها ابتدا یک متد به نام calculateDamage (یعنی «ضربه را محاسبه کن») پس از giveUp (در انتهای متدها) می سازم:

giveUp: function () {

},
calculateDamage: function (min, max) {
    return Math.max(Math.floor(Math.random() * max) + 1, min);
},

حالا می توانیم به جای نوشتن کدهای تکراری در attack بگوییم:

attack: function () {
    var damage = this.calculateDamage(3, 10);
    this.monsterHealth -= damage;

    if (this.monsterHealth <= 0) {
        alert('You Won!');
        this.gameIsRunning = false;
        return;
    }

    damage = this.calculateDamage(12, 5);
    this.playerHealth -= damage;

    if (this.playerHealth <= 0) {
        alert('You Lost!');
        this.gameIsRunning = false;
    }
},

تابع calculateDamage این کار را به سادگی برای ما انجام می دهد. شما حتی می توانستید کد بالا را به شکل زیر نیز بنویسید:

this.monsterHealth -= this.calculateDamage(3, 10);

یعنی حتی متغیر damage را تعریف نکنید. حالا برای بررسی اینکه چه کسی برنده شده است به جای تکرار شرط های if، یک متد دیگر را تعریف می کنم:

calculateDamage: function(min, max) {
    return Math.max(Math.floor(Math.random() * max) + 1, min);
},
checkWin: function() {
    if (this.monsterHealth <= 0) {
        if (confirm('You won! New Game?')) {
            this.startGame();
        } else {
            this.gameIsRunning = false;
        }
        return true;
    } else if (this.playerHealth <= 0) {
        if (confirm('You lost! New Game?')) {
            this.startGame();
        } else {
            this.gameIsRunning = false;
        }
        return true;
    }
    return false;
}

من می خواهم زمانی که بازی تمام شد از کاربر بپرسم آیا دوست دارد یک بار دیگر بازی کند یا خیر. برای انجام این کار از یک پنجره confirm استفاده می کنم که یکی از متدهای جاوا اسکریپت است و به Vue مربوط نیست. اگر health هیولا کمتر از صفر یا صفر شد، کاربر برنده است و از او پرسیده می شود که آیا می خواهد بازی جدیدی را شروع کند؟ در صورت تایید، متد startGame را که قبلا نوشته بودیم صدا می زنیم، در غیر این صورت فقط gameIsRunning را روی false می گذاریم. همین منطق را برای قسمت کاربر نیز پیاده می کنیم. توجه داشته باشید که در هر صورت باید true برگردانده شود. چرا؟ به دلیل اینکه در متدهای بالاتر مانند attack باید معیاری برای مقایسه داشته باشیم و true یا false به سادگی این کار را ممکن می کنند. در شرایطی که نه ما ببریم نه هیولا (بازی در حال اجرا است و هنوز کسی برنده نشده است) باید false برگردانده شود.

حالا به متد attack برمی گردیم و می گوییم:

attack: function () {
    var damage = this.calculateDamage(3, 10);
    this.monsterHealth -= damage;

    if (this.checkWin()) {
        return;
    }

    damage = this.calculateDamage(12, 5);
    this.playerHealth -= damage;

    this.checkWin();
},

در اولین شرط if با استفاده از ckeckWin برنده شدن را چک می کنم و اگر صحیح بود دستور return را می زنم تا کد دیگری اجرا نشود اما برای قسمت دوم از آنجایی که نیازی به متوقف کردن کدهای دیگر نیست (کدهای دیگری وجود ندارد که متوقف شود)، مستقیما checkWin را اجرا می کنیم.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان Vue js از صفر تا صد توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.