質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
RPG

RPG (Report Program Generator)とは、IBMの System i(AS/400)サーバ向けのプログラミング言語です。

Q&A

解決済

3回答

3959閲覧

RPGのアイテム(装備品)で、パワーアップの実装方法

chankane

総合スコア139

RPG

RPG (Report Program Generator)とは、IBMの System i(AS/400)サーバ向けのプログラミング言語です。

0グッド

1クリップ

投稿2017/07/01 13:43

###前提・実現したいこと
RPGをつくっています。装備品によってプレーヤーをパワーアップさせようかなと考えています。具体的には攻撃力や防御力などが該当します。
その実装方法について友達と相談して、意見が分かれたので意見をください。1が友人、2が私です。また、2つの意見のいいとこ取りをするいい意見がある場合はそれがベストです。
以上、よろしくお願いいたします。

  1. プレイヤー側にpowerup(アイテム)関数を作り、その中でアイテムの種類によってパワーアップする値を変える方法
  2. アイテム側にpowerup(プレイヤー)関数を作り、プレイヤーのメソッド(powerupAtack(),powerupDefense())を実行する方法

###メリット

  1. 攻撃力や防御力といった変数が外部から隠ぺいされる
  2. アイテム側に実装(どんな効果か)を隠ぺいできる。つまり、プレイヤー側はアイテムの存在を意識しなくてよい。

###デメリット

  1. アイテムが増えたとき、プレイヤー側のpowerup(アイテム)関数に処理を追加しなてはならない。アイテムの数が200,300に増えたときに、その関数もデカくなる
  2. 外から値をいじり放題

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

追記:ここで前提にしているアイテムは、装備品だけに限定した話で、消耗品は含んでいません。

いろいろな考え方があり、正解はないのですが、ゲームの仕様に合わせて都合よく作るのが良いと思います。

自分が前に作ったゲームでは、ステータスにはデフォルト値と現在の値の2つを用意し、
アイテムには、全ステータスの増加分(パーセント)を返すメソッドを用意しました。

cpp

1// 攻撃力が10%アップするアイテムの例 2// 全ステータス分のメソッドを用意し、効果がないステータスは0を返す 3// マイナス効果があるなら、単に-5などとすれば良い。 4item.getAttack(); // 10 5item.getDefense(); // 0 6item.getCritical(); // 0

ステージの効果とか、敵の魔法などにより、プレイヤーのステータスへマイナス効果を与えるような仕様もあるため、いったんパーセントに直して最終的なステータス値を決める必要がありました。

デフォルト値は、アイテム効果を除いた素の値を返します。
レベルアップによって変化するのであれば、メンバ変数をreturnする事になります。

これはあくまでも例で、だいたいこんな事をやっていたという事を思い出しながら書いています。
アイテム効果の増加分については、固定となるためバトル前に計算してメンバ変数に持っておいても良いと思います。
ただ、戦闘中にアイテムが壊れるとか、敵から受ける状態異常などの都合もあり、必ず毎回計算する部分は出てきます。

cpp

1// 防御力(デフォルト値) 2int Player::getDefaultDefense() const { 3 return mDefaultDefense; 4} 5 6// 防御力(アイテム効果を含めた現在の値) 7// バトルではこの値を使用 8int Player::getDefense() { 9 int base = getDefaultDefense(); 10 11 // 現在装備しているアイテム 12 std::vector<Item*> items = getItems(); 13 14 // アイテム効果(増加分のパーセント)を計算 15 int addPercent = 0; 16 for(auto item: items) { 17 // 防御力を返すメソッドなので、アイテムの防御力のところだけ考えればいい 18 addPercent += item->getDefense(); 19 } 20 21 // バトル中の敵の魔法などにより防御力が下がるような仕様があるなら 22 // ここで、その分だけaddPercentから引いておく 23 24 // 最終的な割合を計算 25 // 80, 90, 100, 105などの値になる 26 float percent = 100 + addPercent; 27 28 // 割合が0以下となったら、計算するまでもないので0を返す 29 if(percent <= 0.0f) { 30 return 0; 31 } 32 33 // デフォルト値を元に最終的な値を計算 34 float value = (float)base * (percent / 100.0f); 35 36 // ここでは整数にしたいので、四捨五入して値を決定 37 return (int)(value + 0.5f); 38}

投稿2017/07/01 15:07

編集2017/07/01 15:09
mingos

総合スコア4025

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chankane

2017/07/01 15:29

こんばんは、0を返すという考えかたは思いつきませんでした。 使わせていただきます。 今現在の状況として、今度は消費型アイテムのほうの実装を知りたいです。 >その場合、プレイヤーにaddMP()のようなメソッドをつけ加え、アイテム側でuse()メソッドをつくり、>そのuse()の中でaddMP()を呼び出すといった形になりますか? と下でコメントした通りのことを考えています。 具体を提供ください。よろしくお願いいたします。 今回の質問には装備品と書いてある。別の質問として質問するべきだとお考えならそうします。そのときはコメント下さい<(_ _)>
chankane

2017/07/01 15:39

ちなみに、自分の中では、 装備品はパラメータを持つもの(プレイヤー側にて、装備品からパラメータをgetしてくる) 消費型はパラメータを増やすもの(アイテム側にて、プレイヤーのパラメータをsetする) といった解釈です。
mingos

2017/07/01 15:42

なるほど。 その定義はゲームごとに異なるのが自然ですので、今回はその定義にしますという事でOKです。 それに沿って考えれば良いので。 ちなみに、装備品は消えない、消費型は使った瞬間に消えるという事で良いでしょうか? さらに、消費型の効果は一定時間で消えるという事もあるのでしょうか?
chankane

2017/07/01 15:45

>ちなみに、装備品は消えない、消費型は使った瞬間に消えるという事で良いでしょうか? YES >さらに、消費型の効果は一定時間で消えるという事もあるのでしょうか? NO。全てアイテムはつかった瞬間に消えて、その効果は死ぬまで永続です。 となります。
chankane

2017/07/01 15:53

ただ、 >消費型はパラメータを増やすもの(アイテム側にて、プレイヤーのパラメータをsetする) という考え方のsetterがなんだか落ちつかないです。消費型アイテムがパラメータを持ってもいいんじゃない?と考えたりもします(お二人の意見を否定しているわけではございません。オブジェクト指向としての自然な考え方をとるか、プレイヤーのパラメータに対しての隠ぺいをとるか、どちらが優先なのだろうかといったことに関して理解が浅いだけです(´;ω;`)ウゥゥ)
mingos

2017/07/01 16:24 編集

setterがpublicなのが落ち着かないという事でしょうか。 であれば、setterはprivateでも良いですよ。 otsuki_takayaさんと同じ考え方ですが、 例えば防御力がアップする消費型アイテムA(アイテムID=100)を使うのなら、 ConsumableItem* item = ConsumableItemFactory::createWithId(100); player.use(item); // 消費型アイテムを使う で良いですよね。 プレイヤーの内部でsetすればいいので、外部に対してはuseだけ公開すれば良いです。 で、アイテムを使った結果、最終的な防御力が増えていれば良いはずです。 // 今の防御力(素の値+装備品効果+消費型効果) int vaue = player.getDefense(); // 自分が作るならこうします // まぁ装備品とやることは同じです。 // 説明を簡単にするために、パーセントではなくただの数値として足す例としています class Player { public: void use(ConsumableItem* item); int getAttack() const; int getDefense() const; private: void setAttack(int value); void setDefense(int value); }; void Player::use(ConsumableItem* item) { // アイテムごとにif文を作る気はないので、必要な分だけ書く // 増える効果がないなら、装備品と同様に0を返せば良い setAttack(getAttack() + item->getAttack()); setDefense(getDefense() + item->getDefense()); .... }
chankane

2017/07/01 17:18

その考えかたで落ち着きそうです ありがとうございましたm(._.)m わからないことがあったらまた明日に質問します それまでベストアンサーは延長させてください
chankane

2017/07/01 23:25

おはようございます。 結局消費型アイテムと装備型アイテムの構造の違いがわかりません。どちらも似たようなパラメータを保持するのですか? で、消費型ならuse(アイテム)、装備型ならequip(アイテム)&remove(アイテム)といったように、メソッドの違いで使い分けるといった感覚でよいのでしょうか? 例えば、”持っているアイテム”・”使っているアイテム”の2つの領域があったとしましょう equip(アイテム)では ・引数のアイテムを”持っているアイテム”欄から削除する ・引数のアイテムを”使っているアイテム”欄に追加する ・効果を反映させる use(アイテム)では ・引数のアイテムを”持っているアイテム”欄から削除する ・効果を反映させる といった感じに使い分ければよいのでしょうか?
mingos

2017/07/02 00:10

やり取りした中で、消費型と装備型で効果に違いはないと感じました。 ご自身でも書いているように、「効果を反映させる」という点で同じです。 であれば、同じメソッドを持つのが自然です。 使った後にアイテムが消えるという違いはありますが、構造というか効果は同じですよね。 私の当初の消費型のイメージは回復薬などのイメージだったので、 ステータスアップではなく、状態を回復すると言った効果を考えていました。 しかし、chankaneさんの中では、装備型も消費型もステータスをアップするものという事だったので、 このゲームにおいては、装備品も消費型も違いはないのだろうと思いました。 一方で、区別はつけるべきであると考えています。 そもそも区別をつける必要がないなら、アイテムという1つのクラスで済みます。 equip(アイテム)と、use(アイテム) としてしまうと微妙過ぎます。 結果は同じでも「意図」が異なるわけです。 equip(装備型アイテム)、use(消費アイテム)とするべきです。 プログラムコードは、文章と同じあって読み手に書き手の意図を伝えなくてはいけません。 ※私の場合、仕事でやっているので私以外の人がコードを見て修正を行う事が頻繁にあります。 また、その逆で私が他の人のコードを直すこともあります。 間違った使い方をされないように、可能な限りデータ型や関数名、変数名、コメントでカバーします。 その中で、データ型が最も確実に意図を伝える手段です。 誤解をさせてしまった場合は、誤解させてしまうコードを書いた側の責任という事にしています。 だからといって責めるわけじゃなくて、どうしたら改善できるか話し合って今後の書き方の指針を統一するという風にやっているので、けんかになることはありません。 そういう前提で考える癖がついているため、物の定義については明確に決めたいです。 私の場合、equip()には装備型、use()には消費型を渡して欲しいと考えています。 // 例1 // どれもItemを渡せるようにする => 間違ったアイテムを渡してしまう事が起こる // 変数名を一応変えているが、強制力がないので役に立たない void equip(Item equipItem); void use(Item consumableItem); // 例2 // データ型を分ける事で、明確に何をしているのか、何を渡して欲しいのか示す // データ型を分けたので、変数名は変える必要なし void equip(EquipItem item); void use(ConsumableItem item);
mingos

2017/07/02 00:27

上のコメントは、これまでのやり取りの流れを踏まえて、消費型と装備型を明確に区別すべしという私の考え方に沿って書きました。 オブジェクト指向におけるクラスは概念を表すと私は考えています。 実装詳細に引っ張られ過ぎない事が大切です。 実装が同じだからクラスも同じで良いではなく、 概念が異なるならクラスを分けるべしという方針で私はやっています。 似たようなコードが出てくるのは問題ではありません。 それよりも同じ効果なのに、なんで違うメソッド名にしてるの?というほうが私にとってはストレスになります。 これも正解があるわけじゃないと思いますが、このやり方でうまく行くことが多いという事、 時間が経過して、なんでこう書いたのか自分でも分からないコードのメンテナンスをする時にも 把握しやすかったなどの経験に基づいています。 ただ、これは私のやり方にすぎないので、今回の話だと 消費型も装備型もクラスを「アイテム」という1つのクラス=概念で良い、 区別はつけないという考え方も十分にありだと思います。 equip(アイテム)ではアイテムが消えない use(アイテム)ではアイテムが消える というだけなので。間違って装備型をuse()に渡すこともあり得ますが、そこは気を付ければよいでしょう。 あとは、アイテムに消費可能かどうかをbooleanで返すメソッドを作って、 use()の中ではtrueの場合だけ処理するという事にしてもいいです。
chankane

2017/07/02 00:32

そうですか、違いはありませんか。確かにアイテムが対象とするデータは同じです。お察しの通りです。 データ型を区別することで、意図を伝える&強制力を持たせるといった効果があるよといった感じで理解しています。たしかに間違ったアイテムが渡せてしまいますね(この勇者、食べると攻撃的があがるバナナを装備しやがったぞ!!みたいなことがおこるかも)
mingos

2017/07/02 00:38

それはそれで面白いんですけどねw この質問の中で出てきた内容だけで判断するしかないので、構造的に違いはないのかなと思いました。 消費する、しないという違いがありますので、これをどう表現するかだけかなと。 私は、データ型(クラス)を分ける派ですが、クラスは分けずに消費型かどうかを返すメソッドを作る派というのも正しいです。 実はもっと違う仕様があるか、作っていく中で違いが出てくる可能性も当然あると思います。 でも考えすぎると、手が止まってしまうので、ある程度ざっくり方針を決めて実装してみる。 実装してみたところ、うまく行かないかしっくり来ないので後で書き直すという事でも良い気もします。 荒くても全体を作り切るほうが大切ですので。
chankane

2017/07/02 00:46

そうなんです。いままさに考えすぎて手が止まっている状態です(笑) 私の悪いところです(゚д゚lll)ガーン たぶん私もデータ型を分ける派になりそうです。 相談しているなかで、あらかた方針に関してのアドバイスをもらったので、自分なりにカスタマイズしながら”とりあえず”つくってみようかなと思います。 ご回答ありがとうございました。
guest

0

既にベストアンサーでクローズですが、
残念ながら退会されたユーザの回答にコメントさせてもらったので具体を示しておきます。
mingosさんとchankaneさんのやり取りのJava実装と言えるものになってます。
ちなみに、2017/07/02 08:25のchankaneさんの発想はGoodでした。

GitHubにソースをアップしたので見てみてください。
以下にMainのソースだけ抜粋しておきます。
※当然ながらこの抜粋ソースだけでは動きません。

Java

1package org.pygmy.rpg; 2 3import org.pygmy.rpg.character.Character; 4import org.pygmy.rpg.item.Item; 5import org.pygmy.rpg.item.armor.concrete.IronArmor; 6import org.pygmy.rpg.item.concrete.Portion; 7import org.pygmy.rpg.item.weapon.concrete.IronSword; 8import org.pygmy.rpg.item.weapon.concrete.SteelAxe; 9 10public class Main { 11 12 public static void main(String[] args) { 13 14 // プレーヤーと敵を作成 15 Character player = new Character("player", 100, 10, 10); 16 Character enemy = new Character("enemy", 100, 10, 10); 17 18 // プレーヤーにポーションを持たせる 19 System.out.println("アイテム:ポーションを持たせる"); 20 dumpCountOfItems(player); 21 player.giveItem(Portion.create()); 22 dumpCountOfItems(player); 23 24 // 攻撃 25 System.out.println("攻撃"); 26 dumpPointOfLife(player); 27 enemy.attackTo(player); 28 dumpPointOfLife(player); 29 30 // 武器と防具を装備 31 player.equip(IronSword.create()); 32 player.equip(IronArmor.create()); 33 34 enemy.equip(SteelAxe.create()); 35 36 // 攻撃(装備後) 37 System.out.println("攻撃(装備後)"); 38 dumpPointOfLife(player); 39 enemy.attackTo(player); 40 dumpPointOfLife(player); 41 42 // プレーヤーのポーションを使う 43 // 1) ポーションを取り出して… 44 System.out.println("アイテム:ポーションを取り出して…"); 45 dumpCountOfItems(player); 46 Item item = player.takeItem(Portion.class); 47 dumpCountOfItems(player); 48 // 2) 使う 49 System.out.println("アイテム:使って…"); 50 dumpPointOfLife(player); 51 item.useTo(player); 52 dumpPointOfLife(player); 53 // 3)使い切った? 54 if (item.isUsedup()) { 55 System.out.println("アイテム:捨てる"); 56 } else { 57 System.out.println("アイテム:戻す"); 58 dumpCountOfItems(player); 59 player.giveItem(item); 60 dumpCountOfItems(player); 61 } 62 } 63 64 private static void dumpPointOfLife(Character character) { 65 System.out.println(character.getName() + " -> Point of Life = " + character.getPointOfLife()); 66 } 67 68 private static void dumpCountOfItems(Character character) { 69 System.out.println(character.getName() + " -> Count of Items = " + character.getCountOfItems()); 70 } 71}

アイテムの取り回し方がポイントです。
GitHubにアップしたソースには設計や実装上のエッセンスも少し入れてみました。
ゲームの仕様によってメリット・デメリットはあると思いますが、
気付いてもらえれば発想の幅が広がったり、実装スキル向上になると思います。

マップの件以来の回答です。
着々と進められているようで良かったです。
是非、完成させてくださいね。

投稿2017/07/03 18:46

編集2017/07/03 18:48
Hiroshi-Aoki

総合スコア804

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chankane

2017/07/03 23:17

おはようございます 早速参考にさせて頂きます おそらく完成させるまでまたお世話になることがあると思いますので、よろしくお願いいたしますm(._.)m
guest

0

これはどのように設計するか、という問題ですね。正解は無いと思います。ですが指針になるものはあります。

オブジェクト指向で考えます。
オブジェクト指向であれば、プレイヤー、アイテムは別々のオブジェクトとして存在することになります。
プレイヤーが属性として持っているのは、HP,MP,力,素早さなどになります。
アイテムが属性として持っているのはHP+5,MP+5,力+1,素早さ-1などになります。

この時にオブジェクトとしての振る舞いを考えると、アイテムとプレイヤーの関係はプレイヤーがアイテムを使用する(装備する)という関係です。ですので、プレイヤー.equip(アイテム)のようなメソッドによりパワーアップ(またはダウン)をするのが自然です。装備を外した場合はプレイヤー.remove(アイテム)ということになります。

いまいち投稿者の方とご友人の想定されているメリットデメリットがわかりませんが、デメリット1はオブジェクト指向で考えることで解消されるはずです。また、メリット1,2とも言える事ですが隠ぺいする事が目的では無く、隠ぺいすることでどのようなメリットがあるかを考えた方が良いように思います。メリットがないのであれば隠ぺいすることに意味はありません。

他の方のご意見も聞きたいですが、ぜひベストな設計目指して試行錯誤して見てください。

投稿2017/07/01 14:30

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chankane

2017/07/01 14:48

アイテムに、プレイヤーのパラメータと同じパラメータを持たせるということですか?例えばMP回復薬だったら (HP,MP,力,素早さ)=(0,200,0,0) といった具合でしょうか? ちょっと参考にさせて頂きます。 それから隠ぺいについては理解が足りていないようでした...。学校の先生にはとりあえず隠せと教わったので。目的を考えることを大事にしたいと思います。
退会済みユーザー

退会済みユーザー

2017/07/01 14:51

プレイヤーとアイテムで同じパラメータを持たせる必要はありません。プレイヤーはプレイヤーオブジェクトとして持つべきパラメータを持たせます。アイテムはアイテムオブジェクトが持つべきパラメータを持たせます。
chankane

2017/07/01 14:52

さっきの例でいくと (HP,MP,力,素早さ)=(0,200,0,0) ではなく (MP)=(200) ということですか?
退会済みユーザー

退会済みユーザー

2017/07/01 15:06

さらに混乱させてしまうかもしれないのですが、 MP回復薬であればプレイヤーとの関係は"使用される"ということになります。ですので、オブジェクトとして例えば"消費アイテムオブジェクト"とします。"消費アイテムオブジェクト"は、プレイヤーが使用することでアイテムは消えますが、プレイヤーのパラメータを増加させるものとします。 ですのでMP回復薬はパラメータを持つというよりは、使用される事で使用した人プレイヤーのパラメータを増やす、という設計にします。
Hiroshi-Aoki

2017/07/01 15:16

回答に賛同します。 回答意図について質問文から引用すると、「powerup(〇〇)って考え方じゃないよ」ってことですね。 chankaneさんのレスによっては当方で一つのやり方としての具体を示そうかと思います。
chankane

2017/07/01 15:16

混乱はしておりません大丈夫です。 その場合、プレイヤーにaddMP()のようなメソッドをつけ加え、アイテム側でuse()メソッドをつくり、そのuse()の中でaddMP()を呼び出すといった形になりますか?
退会済みユーザー

退会済みユーザー

2017/07/01 15:59

いえ、少し違いますね。わたしの考えでは、 ・プレイヤーは各種パラメータを持ちます。また、itemを消費するuse(Item)メソッドを持ちます。 ・アイテムはプレイヤーのパラメータを変動させる数値を持ちます。 ・プレイヤーオブジェクトを生成する際に各種パラメータが決定されます。(力=5など) ・アイテムオブジェクトを生成する際に変動させるパラメータが決定されます。(力+3など) 具体的にします。 ・プレイヤーである勇者Lv5のオブジェクトを生成するとHP:15,MP:3,力:5などが決定されます。 ・アイテムである薬草のオブジェクトを生成するとHP+10というパラメータが決定されます。 勇者はHPが減った5の状態になったとします。ここで以下の命令をしたとします。 勇者.use(薬草); すると勇者のパラメータに+10される。 このような実装にすれば良いと思います。薬草がMP回復薬に変わってもその都度コードを増やすような設計にはならないようにできるはずです。
chankane

2017/07/01 16:13

>アイテムはプレイヤーのパラメータを変動させる数値を持ちます >アイテムオブジェクトを生成する際に変動させるパラメータが決定されます。(力+3など) ということは、その勇者.use(薬草)の実装は、 ・薬草から変動させるパラメータをget ・プレイヤーのパラメータにそれを反映させる といった流れになると思います。たぶん。 そういった場合、getしてきた値がなんの値(HPなのか MPなのか 力なのか)か判別する必要が出てきます。その判別はどのようにしたらよいですか?正直思いつきません。勘違いをしていたらすみません。あと、急ぎではないので、日付をまたいでしまっても大丈夫です。
退会済みユーザー

退会済みユーザー

2017/07/01 16:21

アイテムによりHPを増やす、MPを増やす、力を増やす、などバラバラなので、結局全パラメータを追加するようにすればよいのではないでしょうか。そのうえで、HP増減なしであれば変わらず、MPの増加があれば増加、などではどうでしょう。
chankane

2017/07/01 17:11

mingos様の最初の回答の通りですね 実装の手順などいろいろ参考にさせて頂きます ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問