Java

オブジェクト指向でRPGを作ってみる – クラスの役割分担

更新日:

モンスターを生成する仕事を Rpg から分割する

現在は Rpg クラスの getMonster() メソッドで、どのようなモンスターに遭遇するのかを実装しています。

実際の RPG では、勇者のレベルや勇者がいる場所、所有しているアイテムなどによって、出現するモンスターが変わってきます。

これらの諸条件を getMonster() メソッドに書いていると、非常に長いコードになり読みにくくなってしまいます。

遭遇するモンスターを生成するのは、別のクラスが責任を持つほうがよさそうです。

MonsterCreator クラスを作成して、遭遇するモンスターを生成する責任を持たせましょう。

public class MonsterCreator {
  public Monster createMonster() {
    double v = Math.random();
    Monster m = null;
    if (v < 0.4) {yo
      m = new Slime();
    } else if (v < 0.7) {
      m = new Dracky();
    } else {
      m = new Ghost();
    }
    return m;
  }
}

Rpgクラスでは、以下のように変更します。

public class Rpg {
  private Brave brave;
  public Rpg() {
    brave = new Brave();
    brave.setName("ヨシヒコ");
  }
  public Brave getBrave() {
    return brave;
  }
  public Monster getMonster() {
    MonsterCreator mc = new MonsterCreator();
    return mc.createMonster();
  }
}

モンスターのビューを生成する役割も MonsterCreator に任せるようにしましょう。

public class MonsterCreator {
  public Monster createMonster() {
    double v = Math.random();
    Monster m = null;
    if (v < 0.4) {
      m = new Slime();
    } else if (v < 0.7) {
      m = new Dracky();
    } else {
      m = new Ghost();
    }
    return m;
  }

  public IconLabel getMonsterLabel(Monster m) {
    IconLabel l = null;
    if (m instanceof Slime) {
      l = new SlimeLabel();
    }
    if (m instanceof Dracky) {
      l = new DrackyLabel();
    }
    if (m instanceof Ghost) {
      l = new GhostLabel();
    }
    return l;
  }
}

これにより、RpgFrame の処理が簡単になります。

  private IconLabel getMonsterLabel(Monster m) {
    MonsterCreator mc = new MonsterCreator();
    return mc.getMonsterLabel(m);
  }

「かいふく」ボタンを追加する

現状では勇者はHPを消耗するばかりなので「かいふく」ボタンを追加してHPを回復できるようにしましょう。

  public BattleFrame() {
    super("戦闘");
    Container pane = getContentPane();
    pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
    iconsPanel = new JPanel();
    iconsPanel.setLayout(new BoxLayout(iconsPanel, BoxLayout.X_AXIS));
    JPanel buttonsPanel = new JPanel();
    buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.Y_AXIS));
    pane.add(iconsPanel);
    pane.add(buttonsPanel);
    braveLabel = new BraveLabel();
    iconsPanel.add(braveLabel);
    JButton battleButton = new JButton("こうげき");
    battleButton.addActionListener(new BattleAction(this));
    buttonsPanel.add(battleButton);
    JButton escapeButton = new JButton("にげる");
    escapeButton.addActionListener(new EscapeAction(this));
    buttonsPanel.add(escapeButton);
    JButton healButton = new JButton("かいふく");
    healButton.addActionListener(new HealAction(this));
    buttonsPanel.add(healButton);
  }

HealActionを新規作成します。

「かいふく」ボタンを押せばHPが回復するようになりました。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class HealAction implements ActionListener {
  private BattleFrame battleFrame;
  public HealAction(BattleFrame battleFrame) {
    this.battleFrame = battleFrame;
  }
  @Override
  public void actionPerformed(ActionEvent e) {
    System.out.println("かいふく");
    Brave brave = battleFrame.getBrave();
    brave.recoverHp(5);
    BraveLabel bl = battleFrame.getBraveLabel();
    bl.setText(brave.getName() + " HP:" + brave.getHp());
  }

}

勇者に経験値を追加する

どのRPGでも、主人公の経験値が増えていくように作られていると思います。

ここでも、モンスターと戦うたびに勇者の経験値が増えていくようにしてみましょう。

まず勇者に経験値の属性を追加し、経験値を取得するメソッドと経験値を増やすメソッドを追加します。

import java.util.ArrayList;
import java.util.List;

public class Brave extends Chara {
  private int exp = 1;
  private int mp = 10;
  private int gold = 0;
  private Arms arms;
  private List<Item> items = new ArrayList<>();
  public Brave() {
    hp = 10;
    setName("ヨシヒコ");
  }
  public int getExp() {
    return exp;
  }
  public void addExp(int p) {
    exp += p;
  }

  // 以下略

経験値を戦闘画面に表示するようにしてみましょう。

現状の戦闘画面では、上からIconsPanelとButtonsPanelが並んでいますが、その上にJLabelを追加して経験値を表示するようにします。

public class BattleFrame extends JFrame {
  private Brave brave;
  private Monster monster;
  private BraveLabel braveLabel;
  private JLabel expLabel;
  private IconLabel monsterLabel;
  private JPanel iconsPanel;
  public BattleFrame() {
    super("戦闘");
    Container pane = getContentPane();
    pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
    expLabel = new JLabel("経験値:");
    pane.add(expLabel);
    iconsPanel = new JPanel();
    iconsPanel.setLayout(new BoxLayout(iconsPanel, BoxLayout.X_AXIS));
    JPanel buttonsPanel = new JPanel();
    buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.Y_AXIS));
    pane.add(iconsPanel);
    pane.add(buttonsPanel);
    braveLabel = new BraveLabel();
    iconsPanel.add(braveLabel);
    JButton battleButton = new JButton("こうげき");
    battleButton.addActionListener(new BattleAction(this));
    buttonsPanel.add(battleButton);
    JButton escapeButton = new JButton("にげる");
    escapeButton.addActionListener(new EscapeAction(this));
    buttonsPanel.add(escapeButton);
    JButton healButton = new JButton("かいふく");
    healButton.addActionListener(new HealAction(this));
    buttonsPanel.add(healButton);
  }

これで戦闘画面に経験値を表示するようになりました。

戦闘で勝利した時に、経験値が増えていくようにします。

戦闘内容は BattleAction で実装していますので、そこを変更します。

モンスターから勝利した時の経験値を取得し、その値をメッセージに表示し、勇者の経験値を増やします。

import java.awt.event.ActionEventEvent;;
import java.awt.event.ActionListener;

import javax.swing.JOptionPane;

public class BattleAction implements ActionListener {
  private BattleFrame battleFrame;
  public BattleAction(BattleFrame bf) {
    battleFrame = bf;
  }
  @Override
  public void actionPerformed(ActionEvent e) {
    Brave brave = battleFrame.getBrave();
    Monster monster = battleFrame.getMonster();
    System.out.println(brave.getName() + "のこうげき");
    System.out.println(monster.getName() + "のこうげき");
    monster.damage(1);
    brave.damage(1);
    BraveLabel bl = battleFrame.getBraveLabel();
    IconLabel sl = battleFrame.getMonsterLabel();
    bl.setText(brave.getName() + " HP:" + brave.getHp());
    sl.setText(monster.getName() + " HP:" + monster.getHp()); 
    if (monster.getHp() <= 0) {
      int gold = monster.getGold();
      int exp = monster.getExp();
      String msg = monster.getName() + "をやっつけた!\n";
      msg += gold + "ゴールドを獲得した!\n";
      msg += "経験値が " + exp + "増えた!";
      brave.addGold(gold);
      brave.addExp(exp);
      JOptionPane.showMessageDialog(
        battleFrame, msg,
        "勝利", JOptionPane.INFORMATION_MESSAGE);
      battleFrame.setVisible(false);
    }
    if (brave.getHp() <= 0) {
      JOptionPane.showMessageDialog(
        battleFrame, brave.getName() + "はしんでしまった。",
        "敗北", JOptionPane.INFORMATION_MESSAGE);
      battleFrame.setVisible(false);
    }
  }
}

フィールドで動いたときに確率でアイテムを拾うようにする

よくあるRPGではアイテムを獲得するには村や町のお店に行って買ったりしますが、今のプログラムに村や町やお店を追加するのはちょっと難しいので、勇者がフィールド内を移動したときに、確率でアイテムを拾うようにします。

勇者を移動させているのは、RpgFrameなので、ここに確率でアイテムを拾う機能を追加します。

モンスターと遭遇した時と同じように、確率でアイテムを拾うようにするために、isItemFound()メソッドを追加します。

また、確率で異なるアイテムを拾うようにするために、ItemCreatorクラスを追加して、createItem()メソッド内でアイテムを生成します。

  @Override
  public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_LEFT) {
      if (braveX > 0) braveX--;
    }
    if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
      if (braveX < FieldWidth - 1) braveX++;
    }
    if (e.getKeyCode() == KeyEvent.VK_UP) {
      if (braveY > 0) braveY--;
    }
    if (e.getKeyCode() == KeyEvent.VK_DOWN) {
      if (braveY < FieldHeight - 1) braveY++;
    }
    drawField();
    System.out.println("x=" + braveX + ", y=" + braveY);
    if (isEncount()) {
      System.out.println("敵と遭遇しました。");
      BattleFrame bf = new BattleFrame();
      bf.setBrave(rpg.getBrave());
      Monster m = rpg.getMonster();
      bf.setMonster(m);
      bf.setMonsterLabel(getMonsterLabel(m));
      SwingUtilities.invokeLater(new WindowInvoker(bf));
    } else if (isItemFound()) {
      //アイテムを拾う処理
      Item item = rpg.getItem();
      Brave brave = rpg.getBrave();
      brave.addItem(item);
      System.out.println(item.getName() + "を見つけた");
    }
  }
  private IconLabel getMonsterLabel(Monster m) {
    MonsterCreator mc = new MonsterCreator();
    return mc.getMonsterLabel(m);
  }
  @Override
  public void keyReleased(KeyEvent e) {
    //
  }
  private boolean isEncount() {
    double v = Math.random();
    return v < 0.01;
  }
  private boolean isItemFound() {
    double v = Math.random();
    return v < 0.05;
  }

RpgクラスにはgetItem()メソッドを追加します。

public class Rpg {
  private Brave brave;
  public Rpg() {
    brave = new Brave();
    brave.setName("ヨシヒコ");
  }
  public Brave getBrave() {
    return brave;
  }
  public Monster getMonster() {
    MonsterCreator mc = new MonsterCreator();
    return mc.createMonster();
  }
  public Item getItem() {
    ItemCreator ic = new ItemCreator();
    return ic.createItem();
  }
}

ItemCreatorでは、アイテムを確率で生成します。

public class ItemCreator {
  public Item createItem() {
    double v = Math.random();
    Item item = null;
    if (v < 0.8) {
      item = new Herb();
    } else {
      item = new SuperHerb();
    }
    return item;
  }
}

アイテムを拾った時に、何を拾ったのかをダイアログで表示するようにします。

    } else if (isItemFound()) {
      //アイテムを拾う処理
      Item item = rpg.getItem();
      Brave brave = rpg.getBrave();
      brave.addItem(item);
      System.out.println(item.getName() + "を見つけた");
      String msg = item.getName() + "を見つけた!";
      JOptionPane.showMessageDialog(
        this, msg,
        "アイテム", JOptionPane.INFORMATION_MESSAGE);
    }
  }

-Java
-,

Copyright© UMLとJavaで学ぶオブジェクト指向プログラミング入門 , 2024 All Rights Reserved Powered by STINGER.