برنامه نویسی

حمله به دورترین دشمن در محدوده (برج دفاع)

Summarize this content to 400 words in Persian Lang
در مقاله قبلی، من نشان دادم که چگونه می توان دورترین دشمن را با استفاده از max heap به طور موثر ردیابی کرد. در این مقاله، نحوه ادغام آن را در مکانیک بازی خواهیم دید.

رویکرد رویداد محور

پیاده سازی موجود از معماری رویداد محور استفاده می کند. در این مقاله به رویدادهای دشمن می پردازیم. این رویدادها اقدامات فرعی را آغاز خواهند کرد.

هر دشمنی می تواند حوادث مختلفی را تجربه کند. در زیر نمونه ای از چرخه زندگی که دشمن ممکن است طی کند آورده شده است:

برای مقاله، من به دو رویداد علاقه مند هستم:

enemyMoved: هنگامی که موقعیت دشمن تغییر می کند شلیک می شود.

enemyRemoved*: هنگامی که دشمن از بازی حذف می شود (مثلاً شکست خورده) شلیک می شود.

(* من قصد دارم در آینده نام رویدادها را تنظیم کنم زیرا دشمن به دلایل مختلف می تواند حذف شود.)

برنامه ریزی کنید

من یک نمودار مدل رویداد ایجاد کردم تا نحوه تعامل رویدادهای مختلف را تجسم کنم. این به درک نحوه ارتباط اشیا کمک می کند.

برای هر رویداد، من دستوری دارم که آن را راه‌اندازی می‌کند. (بنابراین، یک رویداد نتیجه یک فرمان است.) در برخی موارد، در نتیجه یک رویداد، ما باید داده ها را به روز کنیم (یادداشت های چسبنده سبز این را نشان می دهند). ترکیبی از هر سه با هم a است برش عمودی.

تمرکز من روی یادداشت سبز رنگ “Eneemies into tower's range” خواهد بود.

پیاده سازی

هدف این است که هر زمان که دشمنی در محدوده برج قرار گرفت، دشمنان موجود را به روز کنیم و در غیر این صورت آنها را حذف کنیم.

ما با یک کلاس برج کار خواهیم کرد. در این کلاس یک متغیر برای ذخیره دشمنان داریم.

export class Tower implements ITower {
public enemies = new MaxHeap()

constructor(id: number, coords: Coordinate) {
this.id = id
this.coords = coords

// listeners will go here…
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قرار دادن شنوندگان رویداد در کلاس Tower منطق را متمرکز می کند و نیاز به حفظ نقشه برداری بین برج ها و دشمنان را کاهش می دهد. در حالی که این امر کمی پیچیدگی را به کلاس اضافه می کند، کپسوله سازی بهتر را تضمین می کند و اشکال زدایی را ساده می کند، که در حال حاضر مسیر آسان تری است.

اکشن: افزودن دشمنان در محدوده

تست: اضافه کردن یک دشمن

ابتدا، آزمایشی می نویسیم تا بررسی کنیم که دشمنی در محدوده به برج اضافه شده است enemies پشته:

it(‘should add an enemy to the tower when enemy is within range’, () => {
const tower = new Tower(1, { col: 0, row: 1 });
const enemy = new TinyEnemy();
enemy.currentPosition = { col: 0, row: 1 };

triggerEnemyMovedEvent(enemy);

expect(tower.enemies.length()).toBe(1);
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی: اضافه کردن یک دشمن

در اینجا پیاده سازی مربوطه است:

window.addEventListener(“enemyMoved”, event => {
const enemy: Enemy = event.detail.enemy;

if (enemyWithinRange(this, enemy)) {
this.enemies.insertOrUpdate(enemy.id, enemy.distanceTraveled);
}
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر زمان enemyMoved فعال می شود، بررسی می کنیم که آیا دشمن باید به پشته اضافه شود. من قبلا دارم enemyWithinRange تابع، موضوع اضافه کردن است insertOrUpdate تماس بگیرید.

اقدام: جلوگیری از افزودن دشمنان خارج از محدوده

تست: نادیده گرفتن دشمنان خارج از محدوده

در مرحله بعد، ما اطمینان می دهیم که دشمنان خارج از محدوده برج اضافه نمی شوند:

it(‘should not add an enemy to the tower if enemy is out of range’, () => {
const tower = new Tower(1, { col: 0, row: 1 });
const enemy = new TinyEnemy();
enemy.currentPosition = { col: 0, row: 99 };

triggerEnemyMovedEvent(enemy);

expect(tower.enemies.length()).toBe(0);
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی: نادیده گرفتن دشمنان خارج از محدوده

این سناریو قبلاً با استفاده از بررسی قبلی ما پوشش داده شده است enemyWithinRange، بنابراین نیازی به کد اضافی نیست.

اکشن: از بین بردن دشمنان خارج از محدوده

تست: از بین بردن دشمن خارج از محدوده

اکنون آزمایش می کنیم که دشمنانی که محدوده را ترک می کنند از دید برج حذف می شوند:

it(‘should remove an enemy from the tower when it moves out of range’, () => {
const tower = new Tower(1, { col: 0, row: 1 });
const enemy = new TinyEnemy();
enemy.currentPosition = { col: 0, row: 1 };

// enemy within range
triggerEnemyMovedEvent(enemy);
expect(tower.enemies.length()).toBe(1);

// enemy outside of the range
enemy.currentPosition = { col: 0, row: 99 };
triggerEnemyMovedEvent(enemy);

expect(tower.enemies.length()).toBe(0);
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی: از بین بردن دشمن خارج از محدوده

window.addEventListener(“enemyMoved”, event => {
const enemy: Enemy = event.detail.enemy;

if (enemyWithinRange(this, enemy)) {
this.enemies.insertOrUpdate(enemy.id, enemy.distanceTraveled);
} else if (this.enemies.hasEnemy(enemy.id)) {
this.enemies.deleteEnemy(enemy.id);
}
})

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر دشمن قبلاً در محدوده بود، می توانیم آن را حذف کنیم.

اکشن: حذف یک دشمن از بازی

تست: هندلینگ enemyRemoved رویداد

در نهایت، ما اطمینان می دهیم که دشمنان حذف شده از بازی نیز از پشته برج حذف می شوند:

it(‘should remove an enemy from the tower when the enemy is removed’, () => {
const tower = new Tower(1, { col: 0, row: 1 });
const enemy = new TinyEnemy();
enemy.currentPosition = { col: 0, row: 1 };

triggerEnemyMovedEvent(enemy);
expect(tower.enemies.length()).toBe(1);

triggerEnemyRemovedEvent(enemy);

expect(tower.enemies.length()).toBe(0);
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اجرا: هندلینگ enemyRemoved

window.addEventListener(“enemyRemoved”, event => {
const enemy: Enemy = event.detail.enemy;

if (this.enemies.hasEnemy(enemy.id)) {
this.enemies.deleteEnemy(enemy.id);
}
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر زمان که یک رویداد راه اندازی شود، اگر دشمن در محدوده باشد، می توانیم آنها را حذف کنیم.

نتیجه گیری

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

علاوه بر این، وقتی نوبت به آزمایش می رسد، استفاده از رویکرد رویداد محور نیاز به پیوند کدهای داخلی با آزمایش را از بین می برد. از این رو تست ها را کمتر شکننده می کند. ما می‌توانیم به هر شکلی که می‌خواهیم، ​​کدهای پشت رفتار را اصلاح کنیم، و تا زمانی که رویدادها/شنوندگان به درستی تنظیم شوند، آزمون‌ها همچنان باید بگذرند.

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

افزودن قابلیت حمله (اکنون که می دانیم به چه کسی حمله کنیم)
تعویض نحوه ذخیره اطلاعات برای دشمنان

با خیال راحت این رویکرد را برای بازی های برج دفاعی خود تطبیق دهید.

در مقاله قبلی، من نشان دادم که چگونه می توان دورترین دشمن را با استفاده از max heap به طور موثر ردیابی کرد. در این مقاله، نحوه ادغام آن را در مکانیک بازی خواهیم دید.

رویکرد رویداد محور

پیاده سازی موجود از معماری رویداد محور استفاده می کند. در این مقاله به رویدادهای دشمن می پردازیم. این رویدادها اقدامات فرعی را آغاز خواهند کرد.

هر دشمنی می تواند حوادث مختلفی را تجربه کند. در زیر نمونه ای از چرخه زندگی که دشمن ممکن است طی کند آورده شده است:

نمونه ای از رویدادهایی که دشمن می تواند به عنوان بخشی از چرخه زندگی تجربه کند

برای مقاله، من به دو رویداد علاقه مند هستم:

  • enemyMoved: هنگامی که موقعیت دشمن تغییر می کند شلیک می شود.
  • enemyRemoved*: هنگامی که دشمن از بازی حذف می شود (مثلاً شکست خورده) شلیک می شود.

(* من قصد دارم در آینده نام رویدادها را تنظیم کنم زیرا دشمن به دلایل مختلف می تواند حذف شود.)

برنامه ریزی کنید

من یک نمودار مدل رویداد ایجاد کردم تا نحوه تعامل رویدادهای مختلف را تجسم کنم. این به درک نحوه ارتباط اشیا کمک می کند.

نمایش مدل رویداد جریان مورد انتظار

برای هر رویداد، من دستوری دارم که آن را راه‌اندازی می‌کند. (بنابراین، یک رویداد نتیجه یک فرمان است.) در برخی موارد، در نتیجه یک رویداد، ما باید داده ها را به روز کنیم (یادداشت های چسبنده سبز این را نشان می دهند). ترکیبی از هر سه با هم a است برش عمودی.

تمرکز من روی یادداشت سبز رنگ “Eneemies into tower's range” خواهد بود.

پیاده سازی

هدف این است که هر زمان که دشمنی در محدوده برج قرار گرفت، دشمنان موجود را به روز کنیم و در غیر این صورت آنها را حذف کنیم.

ما با یک کلاس برج کار خواهیم کرد. در این کلاس یک متغیر برای ذخیره دشمنان داریم.

export class Tower implements ITower {
    public enemies = new MaxHeap()

    constructor(id: number, coords: Coordinate) {
        this.id = id
        this.coords = coords

        // listeners will go here...
    }
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

قرار دادن شنوندگان رویداد در کلاس Tower منطق را متمرکز می کند و نیاز به حفظ نقشه برداری بین برج ها و دشمنان را کاهش می دهد. در حالی که این امر کمی پیچیدگی را به کلاس اضافه می کند، کپسوله سازی بهتر را تضمین می کند و اشکال زدایی را ساده می کند، که در حال حاضر مسیر آسان تری است.

اکشن: افزودن دشمنان در محدوده

تست: اضافه کردن یک دشمن

ابتدا، آزمایشی می نویسیم تا بررسی کنیم که دشمنی در محدوده به برج اضافه شده است enemies پشته:

it('should add an enemy to the tower when enemy is within range', () => {
    const tower = new Tower(1, { col: 0, row: 1 });
    const enemy = new TinyEnemy();
    enemy.currentPosition = { col: 0, row: 1 };

    triggerEnemyMovedEvent(enemy);

    expect(tower.enemies.length()).toBe(1);
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی: اضافه کردن یک دشمن

در اینجا پیاده سازی مربوطه است:

window.addEventListener("enemyMoved", event => {
    const enemy: Enemy = event.detail.enemy;

    if (enemyWithinRange(this, enemy)) {
        this.enemies.insertOrUpdate(enemy.id, enemy.distanceTraveled);
    }
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر زمان enemyMoved فعال می شود، بررسی می کنیم که آیا دشمن باید به پشته اضافه شود. من قبلا دارم enemyWithinRange تابع، موضوع اضافه کردن است insertOrUpdate تماس بگیرید.


اقدام: جلوگیری از افزودن دشمنان خارج از محدوده

تست: نادیده گرفتن دشمنان خارج از محدوده

در مرحله بعد، ما اطمینان می دهیم که دشمنان خارج از محدوده برج اضافه نمی شوند:

it('should not add an enemy to the tower if enemy is out of range', () => {
    const tower = new Tower(1, { col: 0, row: 1 });
    const enemy = new TinyEnemy();
    enemy.currentPosition = { col: 0, row: 99 };

    triggerEnemyMovedEvent(enemy);

    expect(tower.enemies.length()).toBe(0);
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی: نادیده گرفتن دشمنان خارج از محدوده

این سناریو قبلاً با استفاده از بررسی قبلی ما پوشش داده شده است enemyWithinRange، بنابراین نیازی به کد اضافی نیست.


اکشن: از بین بردن دشمنان خارج از محدوده

تست: از بین بردن دشمن خارج از محدوده

اکنون آزمایش می کنیم که دشمنانی که محدوده را ترک می کنند از دید برج حذف می شوند:

it('should remove an enemy from the tower when it moves out of range', () => {
    const tower = new Tower(1, { col: 0, row: 1 });
    const enemy = new TinyEnemy();
    enemy.currentPosition = { col: 0, row: 1 };

    // enemy within range
    triggerEnemyMovedEvent(enemy);
    expect(tower.enemies.length()).toBe(1);

    // enemy outside of the range
    enemy.currentPosition = { col: 0, row: 99 };
    triggerEnemyMovedEvent(enemy);

    expect(tower.enemies.length()).toBe(0);
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پیاده سازی: از بین بردن دشمن خارج از محدوده

window.addEventListener("enemyMoved", event => {
    const enemy: Enemy = event.detail.enemy;

    if (enemyWithinRange(this, enemy)) {
        this.enemies.insertOrUpdate(enemy.id, enemy.distanceTraveled);
    } else if (this.enemies.hasEnemy(enemy.id)) {
        this.enemies.deleteEnemy(enemy.id);
    }
})
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اگر دشمن قبلاً در محدوده بود، می توانیم آن را حذف کنیم.


اکشن: حذف یک دشمن از بازی

تست: هندلینگ enemyRemoved رویداد

در نهایت، ما اطمینان می دهیم که دشمنان حذف شده از بازی نیز از پشته برج حذف می شوند:

it('should remove an enemy from the tower when the enemy is removed', () => {
    const tower = new Tower(1, { col: 0, row: 1 });
    const enemy = new TinyEnemy();
    enemy.currentPosition = { col: 0, row: 1 };

    triggerEnemyMovedEvent(enemy);
    expect(tower.enemies.length()).toBe(1);

    triggerEnemyRemovedEvent(enemy);

    expect(tower.enemies.length()).toBe(0);
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اجرا: هندلینگ enemyRemoved

window.addEventListener("enemyRemoved", event => {
    const enemy: Enemy = event.detail.enemy;

    if (this.enemies.hasEnemy(enemy.id)) {
        this.enemies.deleteEnemy(enemy.id);
    }
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر زمان که یک رویداد راه اندازی شود، اگر دشمن در محدوده باشد، می توانیم آنها را حذف کنیم.

نتیجه گیری

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

علاوه بر این، وقتی نوبت به آزمایش می رسد، استفاده از رویکرد رویداد محور نیاز به پیوند کدهای داخلی با آزمایش را از بین می برد. از این رو تست ها را کمتر شکننده می کند. ما می‌توانیم به هر شکلی که می‌خواهیم، ​​کدهای پشت رفتار را اصلاح کنیم، و تا زمانی که رویدادها/شنوندگان به درستی تنظیم شوند، آزمون‌ها همچنان باید بگذرند.

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

  • افزودن قابلیت حمله (اکنون که می دانیم به چه کسی حمله کنیم)
  • تعویض نحوه ذخیره اطلاعات برای دشمنان

با خیال راحت این رویکرد را برای بازی های برج دفاعی خود تطبیق دهید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا