Пишу рпг на JavaScript, есть два массива объектов. Задача такая: как при нанесённом уроне вычитать количество урона из поля в объекте

Пример объекта

moves: [
            {
                "name": "Удар боевым кадилом",
                "physicalDmg": 2,
                "magicDmg": 0,
                "physicArmorPercents": 0,
                "magicArmorPercents": 50,
                "cooldown": 0
            },
            {
                "name": "Вертушка левой пяткой",
                "physicalDmg": 4,
                "magicDmg": 0,
                "physicArmorPercents": 0,
                "magicArmorPercents": 0,
                "cooldown": 4
            },
            {
                "name": "Каноничный фаербол",
                "physicalDmg": 0,
                "magicDmg": 5,
                "physicArmorPercents": 0,
                "magicArmorPercents": 0,
                "cooldown": 3
            },
            {
                "name": "Магический блок",
                "physicalDmg": 0,
                "magicDmg": 0,
                "physicArmorPercents": 100,
                "magicArmorPercents": 100,
                "cooldown": 4
            },
        ]

Ответы (2 шт):

Автор решения: Алексей Шиманский

Находим дамагу по наименованию например

let kick = moves.find(el => el.name === 'Удар боевым кадилом');

берём значение

let damage = kick.physicalDmg;

и дальше у бойца вычитаем это значение

→ Ссылка
Автор решения: Neverm1ndo

Самый простой способ обращаться к элементу массива с помощью индекса:

const player = {
 moves: [ { "name": "Удар боевым кадилом", "physicalDmg": 2, "magicDmg": 0, "physicArmorPercents": 0, "magicArmorPercents": 50, "cooldown": 0 }, { "name": "Вертушка левой пяткой", "physicalDmg": 4, "magicDmg": 0, "physicArmorPercents": 0, "magicArmorPercents": 0, "cooldown": 4 }, { "name": "Каноничный фаербол", "physicalDmg": 0, "magicDmg": 5, "physicArmorPercents": 0, "magicArmorPercents": 0, "cooldown": 3 }, { "name": "Магический блок", "physicalDmg": 0, "magicDmg": 0, "physicArmorPercents": 100, "magicArmorPercents": 100, "cooldown": 4 }, ],
 attack: function(target, move) { target.takeDamage(move); } 
}
const enemy = {
 health: 100,
 resists: {
  physical: 0.5,
  magic: 0.5
 },
 takeDamage: function(move) {
   const { physicalDmg, magicDmg } = move;
   this.health -= Math.floor((1 - this.resists.magic)*magicDmg + (1 - this.resists.physical)*physicalDmg);
 },
}

console.log(enemy.health); // 100

player.attack(enemy, player.moves[0]); // кадило
console.log(enemy.health); // 99 (2*50% резиста)

player.attack(enemy, player.moves[1]); // вертушка
console.log(enemy.health);

Вообще, такой подход не особо хорош, как по мне. Если собираешься писать игру, то лучше сразу пиши в объектно-ориентированном стиле. Будет меньше путанницы. Кода будет много, а так его будет проще читать и расширять.

Вот пример. Так можно сделать пошаговую РПГ:

class Ability { // класс способности
  constructor(options) {
    if (!options) return;
    this.name = options?.name || 'no_attack_name';
    this.cooldown = options?.cooldown ?? 0;
    this.cooldownTimer = 0;
  }
  use() {
    this.cooldownTimer = this.cooldown;
  }
}

class AttackAbility extends Ability { // атакующая способность наследуется от общего класса способности
  constructor(options, selfEffect) {
    super(options);
    this.damage = {
      physical: options?.physicalDmg ?? 1,
      magic: options?.magicDmg ?? 1
    };
  }
}

const Abilities = new Map([
  [
    'BATTLE_KADILO_ATTACK', 
    { "name": "Удар боевым кадилом", "physicalDmg": 2, "magicDmg": 0, "physicArmorPercents": 0, "magicArmorPercents": 50, "cooldown": 0 }
  ],
  [
    'LEFT_HEEL_ATTACK', 
    { "name": "Вертушка левой пяткой", "physicalDmg": 4, "magicDmg": 0, "physicArmorPercents": 0, "magicArmorPercents": 0, "cooldown": 4 }
  ],
  [
    'CANONICAL_FIREBALL_ATTACK', 
    { "name": "Каноничный фаербол", "physicalDmg": 0, "magicDmg": 5, "physicArmorPercents": 0, "magicArmorPercents": 0, "cooldown": 3 }
  ]
].map(([key, options]) => [key, new AttackAbility(options)]));

class Actor {
  possibleToAttack = false;
  canAttack = false;
  #health = 1;
  #armor = 1;
  abilities = new Map();
  resists = {
    magic: 0, 
    physical: 0,
  };
  name;
  
  constructor(health) {
    this.#health = health;
  }
  
  get health() {
    return this.#health;
  }
  get armor() {
    return this.#health;
  }
  
  static isActor(actor) {
    return actor instanceof Actor;
  }
  
  isDead() {
    return this.#health === 0;
  }
  
  useAbility(targer, abilityId) {
    if (!Actor.isActor(target)) return;
    if (this.abilities.has(abilityId)) target.takeEffect(this.abilities.get(abilityId));
  }
  
  takeEffect(effect) {
    if (effect instanceof AttackAbility) return void(this.takeDamage(effect));
    // Дальше могут быть другие эффекты типа бафов или дебафов, дот и тп.
  }
  
  #applyResists(move) {
    const { physical, magic } = move;
    return Math.floor((1 - this.resists.magic)*magic + (1 - this.resists.physical)*physical);
  }
  
  takeDamage(ability) {
    const damage = this.#applyResists(ability.damage)
    this.#health -= damage;
    console.log(`${this.name} получает урон: ${damage} (Физ.:${ability.damage.physical}, Маг.:${ability.damage.magic}). Текущее здоровье ${this.name}: ${this.#health}`);
    if (this.#health < 0) this.#health = 0;
  }
  
  attack(target, abilityId) {
    if (!this.canAttack) return void(console.log(`${this.name} не может атаковать`));
    if (!target.possibleToAttack) return void(console.log(`${this.name} не может быть атакован`));
    if (!target instanceof Enemy) return;
    if (target.isDead()) return;
    if (!this.abilities.includes(abilityId)) return;
    const move = Abilities.get(abilityId);
    if (!move) return;
    console.log(`${this.name} атакует ${target.name} => ${move.name} с уроном (Физ.:${move.damage.physical}, Маг.:${move.damage.magic})`)
    target.takeDamage(move);
  };
}

class Player extends Actor {
  #health = 100;
  name = 'Герой';
  canAttack = true;
  possibleToAttack = true;
  abilities = [
    'BATTLE_KADILO_ATTACK',
    'LEFT_HEEL_ATTACK',
    'CANONICAL_FIREBALL_ATTACK',
  ];
}

class Enemy extends Actor {
  possibleToAttack = true;
  canAttack = true;
}

class Mage extends Enemy {
  abilities = [
    'CANONICAL_FIREBALL_ATTACK'
  ];
  resists = {
    physical: 0,
    magic: 0.7, // 70% 
  }
  name = 'Маг';
}

const player = new Player(100); // создаем игрока

const mage = new Mage(50); // создаем врага мага

player.attack(mage, 'BATTLE_KADILO_ATTACK'); // кадило
mage.attack(player, 'CANONICAL_FIREBALL_ATTACK');
player.attack(mage, 'LEFT_HEEL_ATTACK'); // вертушка
mage.attack(player, 'CANONICAL_FIREBALL_ATTACK');
player.attack(mage, 'CANONICAL_FIREBALL_ATTACK'); // файрбол, маг срезистил 4 дамага из 5

→ Ссылка