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

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

ただいまの
回答率

88.35%

Listの内容が共有されてしまう

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 4,720

Ans

score 73

アクションRPGを作っています
敵味方の状態異常を実装しようと思い
とりあえず状態異常の管理にListを使いました
(5回毒を与えたら5個の毒がバラバラにダメージを与えそれぞれの効果時間で各自消滅する
各々が完全に独立しているタイプです)

しかし複数同じ敵(=同じプレハブ=同じスクリプト)がいる場合
Listを共有してしまうためうまくいきません

状態異常のcrassの中身は今の所
 効果回数と 効果間隔と 効果数値と 効果種類です。
 5回まで   1秒ごとに  10ダメージの 毒     といった感じです

質問です

Listのstatic属性は外せますか?

全く別のスマートな実装方法はありますか?

今考えている代替案は
Listを使わず状態異常のコンポーネントを作っておき
状態異常を与えるたびにaddcomponentするというものですが
これはスマートですか?

回答お待ちしています
よろしくお願いします

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

こんにちは。

HiroshiWatanabeさんの回答へのコメントの使い方でしたら、staticにはなっていません。
もし、List<A>にAdd()したAのインスタンスが共有されているように見えるとしたら、同じインスタンスをAdd()している可能性があります。

例えば、敵の種類毎に毒(クラスA)のインスタンスを作っておいて、そのインスタンスをList<A>へAdd()していた場合、同じ種類の敵の毒について1つしかインスタンスが作られていないので、全て共有されてしまいます。
もし、そのような使い方をされているなら、AにClone()メソッドを実装し、Clone()したインスタンスをAdd()すればうまくいくはずです。

上記問題が原因でしたら、これはプロでもハマり一度ハマったら簡単には抜け出せない問題です。(解っていてもたいへんですが、知らなければ地獄を見ると思います。)
C#はポインタを使っていないように見えて、実は参照や参照型で使っています。値渡しと参照渡し値型と参照型について、良く理解しておくことをお勧めします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/10 13:03 編集

    回答ありがとうございます
    なるほどズバリその通りでした(多分)

    はじめに
    void Aget(A a){
    As.add (a);}
    のようにしていて壁にぶち当たりました

    現在は
    void Aget(A doku){
    As.add (new A (doku.tuyosa,doku.count,doku.interval ));}
    のようにしています(しかしこれがなぜなのかわからず。
    理屈はわからんがこれなら通ることを知っているという感じでした)

    Chironianさんの回答を受けた
    今の自分の理解は

    3体の敵にA毒を1個ずつ送るには
    3体の敵にそれぞれA毒Clone1 A毒Clone2 A毒Clone3を送る必要がある

    Cloneを作るメソッドの中身は上記で言う
    As.add (new A (doku.tuyosa,doku.count,doku.interval )
    に相当する。(それをAというクラス内に作っとけとおっしゃっている?)

    自分が勘違いしていたのは
    [1つのリストを共有(static)してしまう]ではなく
    [3つのリストで1つの毒を共有してしまう]ということ

    以上理解はあっているでしょうか間違っていたらご指摘ください

    確かに3体に毒を付与すると3倍速で毒が治り想定の3分の1しかダメージがでませんでした。(1つの毒を3体で消費し 3体で1つの毒のダメージを受けていた)

    またアイテムにランダムステータスを付与すると
    アイテムデータベースの値も変わってしまうなどなど同じような問題に度々悩まされていました

    Cはポインタが大変
    C♯もポインタは実は出てくる
    知っていましたし
    午前中も「ほへーポインタ大変そうやね そのうち自分もぶつかるかね
    ゲームセーブデータ改変みたいなもんかね」
    とか思ってました。まさにぶつかってたんですね
    値渡しと参照渡しもなんやそれでしたが一気にいけそうです
    勉強します

    最近のもやもやがまとめて吹き飛んだ気がします(理解があってればですが)
    自分の理解があっているかだけあと一度よろしくお願いします!

    キャンセル

  • 2016/05/10 13:37

    kzy419さん。

    > 以上理解はあっているでしょうか間違っていたらご指摘ください

    それであってますよ。

    C#の参照型はなかなか歯ごたえがありますが、そこまで分かっていれば、後は熟練です。
    頑張って下さい。

    キャンセル

  • 2016/05/10 14:01

    それはよかったです
    では解決としたいと思います
    皆さんの反応のおかげでたどり着いたので
    ベストアンサーとか選びにくいのですがつけます
    Chironian さん
    HiroshiWatanabe さん
    tkow さん
    ありがとうございました 頑張ります。

    キャンセル

0

実装自体自由度が高いのでListを共有する方法でもできると思いますよ。
勿論クラス内の内部変数として定義すればstaticでリストを定義する必要もありません。
ただ,こういう実装する時って大体エネミークラスみたいな抽象クラスに状態異常typeをenumで持たせてて,このenumの値で,状態異常レベルみたいな変数を持たせてインデクサアクセス出来るようにしてメソッド経由でインクリメントしたりしますね。
それぞれのインスタンスに独立して持たせた方がプロセスを分離しやすいです。同期的に判定を行いたいなどの理由があればこの抽象クラスを継承したサブクラスのインスタンスをポリモーフィズムを利用して同じリストに入れて管理することも出来ます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/10 10:33

    回答ありがとうございます

    >>リストをstaticでリストを定義する必要もありません。
    とのこですが「デフォルトでstaticで定義されてしまうよ〜」というのが自分の現状です
    説明不足でした。

    enumからインデクサも試してみます

    共有する方法で考えた結果
    とりあえず状態異常を受けたオブジェクトが
    リストに状態異常を追加する際そのオブジェクトの名前も記録するようにしました
    やりたいことはできたのですが
    Listに関する理解が間違っている?ようなのでもう少しご教授いただきたいです。

    ポリモーフィズムはまだ手をつけていないので勉強します。

    キャンセル

  • 2016/05/10 13:10

    Chironianさんが書かれているようにリストがstaticではなくインスタンスの参照コピーをリストに入れてしまってるんでしょうね。
    参照型オブジェクトはコンストラクタ経由で複製しましょう。

    キャンセル

  • 2016/05/10 13:26

    new というやつですよね
    ということはオブジェクトの名前も記録する云々はいらなかったということですね。
    (同じ時にnewに置き換えていました)
    自分がぶつかっている壁がなんなのかわかっていなかったということでした。
    質問してよかったです ありがとうございます。

    キャンセル

0

逆になぜstaticをつけているのかがわかりません。
同じprefabだろうが同じscriptだろうがそれぞれの敵毎に(staticをつけずに)Listを持たせればいいだけのように思えますが…?
もしかして単に特定の敵へのアクセス方法がわからずにstaticアクセスにしてしまっている的な事でしょうか?
対象のオブジェクト(GameObject)が特定できているのならそこから欲しいコンポーネント(スクリプト)をGetComponent等でゲットしてやれば後はそれにアクセスするだけですが…
prefabが同じでもそれを元にそれぞれ別のオブジェクトとして配置されているので別物ですしもちろん同じスクリプトでもコンポーネントとしてアタッチしているオブジェクトが別なのでスクリプトとしてもそれぞれ別物として個別に機能していますからそもそも今回のケースでstaticをつける事が誤りな状況のように読めます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/10 10:19 編集

    回答ありがとうございます
    敵へのアクセス方法はわかります
    後半の部分も理解できますし全くもってその通りだと思います

    Listの使い方が根本的に間違っているのでしょうか
    あるいはstaticの理解が間違っているのかも



    public class enemystates : MonoBehaviour {
    List<A >As = new List<A>() ;
    int a ;
    float b ;//以下いろいろ
    }
    void hogehoge(){}//以下スクリプトが続く

    という指定の仕方なのですが
    このスクリプトが刺さっているオブジェクトでList Asは共有されてしまいます
    自分でstaticをつけたつもりはないのですが
    独立させる記述があるのでしょうか

    キャンセル

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

  • ただいまの回答率 88.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る