🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

1627閲覧

prefabから出現させたクローンに力を加える

actionstudio

総合スコア39

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

1クリップ

投稿2021/01/29 13:39

編集2021/01/30 23:38

#現在行っていること
prefabから出現させたクローンに、力を加えて吹き飛ばそうとしています。

C#

1Rigidbody nomalEnemyRigidbody = nomalEnemyPrefab.GetComponent<Rigidbody>(); 2Vector3 nomalEnemyAwayFromPlayer = nomalEnemyPrefab.transform.position - transform.position; 3nomalEnemyRigidbody.AddForce(nomalEnemyAwayFromPlayer * blowOffStrengh, ForceMode.Impulse);

として、playerのスクリプトから力を加えようとしているのですが、うまく実行されません。
エラーコードは出ていません。
nomalEnemyPrefabはpabulicにして、指定しています。
はじめ、このコードをnomalEnemyのPrefabのほうに書き、実行していましたが、ほかの吹き飛ばすコードがplayerの方に書いてあったため、統一するためにplayerの方に書きました。そしたらなぜかうまくいかなくなってしまいました。

このような場合、クローンとして出現させた物体には力を加えることができないのでしょうか。
また、出現させたクローンすべてに力を加えたいため、findObjectsOfTypeをつかおうとしましたが、うまくできませんでした。

どうすればいいか教えてください。
また、あるオブジェクトに力を加えるような場合、プレイやーにアタッチされたスクリプトか吹き飛ばす方にアタッチされたスクリプトどちらに書いた方がいいのでしょうか。

##最終的に行ったこと
boolで吹き飛ばす命令をPlayerControllerから受け取り、教えていただいたAddExplosionForceで爆発の影響を受けるようにしました。

C#

1using System; 2using System.Collections; 3using System.Collections.Generic; 4using UnityEngine; 5 6public class NomalEnemy : MonoBehaviour 7{ 8 private Rigidbody nomalEnemyRb; 9 private GameObject player; 10 public GameObject bigEnemyPrefab; 11 12 public float nomalEnemySpeed = 30.0f; 13 public float blowOffStrengh = 50.0f; 14 15 public float power; 16 public float radius; 17 public float upwardsModifier; 18 19 private PlayerController playerControllerScript; 20 21 // Start is called before the first frame update 22 void Start() 23 { 24 player = GameObject.Find("Player"); 25 nomalEnemyRb = GetComponent<Rigidbody>(); 26 playerControllerScript = GameObject.Find("Player").GetComponent<PlayerController>(); 27 } 28 29 // Update is called once per frame 30 void Update() 31 { 32 moveToPlayer(); 33 34 if (playerControllerScript.blownAwayByPlayerWithSpecialWeapon) 35 { 36 StartCoroutine(BlownAwayByPlayerWithSpecialWeapon()); 37 } 38 } 39 40 private void moveToPlayer() 41 { 42 if (!playerControllerScript.gameOver) 43 { 44 if (playerControllerScript.readyToRanchSpecialWeapon) 45 { 46 nomalEnemyRb.velocity = Vector3.zero; 47 } 48 else 49 { 50 Vector3 lookDirection = (player.transform.position - transform.position).normalized; 51 52 nomalEnemyRb.AddForce(lookDirection * nomalEnemySpeed); 53 } 54 } 55 } 56 57 58 IEnumerator BlownAwayByPlayerWithSpecialWeapon() 59 { 60 GetComponent<Rigidbody>().AddExplosionForce(power, player.transform.position, radius, upwardsModifier, ForceMode.Impulse); 61 yield return null; 62 playerControllerScript.blownAwayByPlayerWithSpecialWeapon = false; 63 } 64}

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

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

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

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

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

Bongo

2021/01/29 23:53

クローンに対して力を加えることについては、入門記事でもよく「弾プレハブをインスタンス化し、力を加えて発射する」みたいな例を見かけるように思いますし、特に問題ないと思うんですがね(たとえば https://gametukurikata.com/program/addforcebullet )... もしかして、ご質問の文面や変数名から予想しますに「nomalEnemyPrefab」というのはプレハブそのものということでしょうか(つまりクローンの方ではなくオリジナルの方)? 例として挙げました「Unityのアクションゲームで物理的な弾を飛ばして敵との当たり判定をする」の記事では // 敵を撃つ void Shot() { var bulletInstance = Instantiate<GameObject>(bulletPrefab, muzzle.position, muzzle.rotation); bulletInstance.GetComponent<Rigidbody>().AddForce(bulletInstance.transform.forward * bulletPower); Destroy(bulletInstance, 5f); } といった風に、「bulletPrefab」ではなく新たに生成された「bulletInstance」の方に力を加えています。ご質問者さんの場合はどうでしょうか? もっと広い範囲のコード(字数が許せばスクリプト全体でもいいかと思います)をご提示いただければ、なにか手がかりが見つかるかもしれません。
actionstudio

2021/01/30 02:01

「nomalEnemyPrefab」では、prefabそのものを指定していました。 Instantiateでクローンを作ってから、オリジナルそのものに力を加えていたからいけなかったのですね。 もし、スクリプト全体のコードを示したほうがいいのならば、おっしゃってください。 しかし、クローンに力を加えるにはどうすればいいのでしょうか。 また、 void Shot() { var bulletInstance = Instantiate<GameObject>(bulletPrefab, muzzle.position, muzzle.rotation); bulletInstance.GetComponent<Rigidbody>().AddForce(bulletInstance.transform.forward * bulletPower); Destroy(bulletInstance, 5f); } これは、クローンを一つ作って、そのオブジェクトをbulletInstanceとしているのでしょか。 その場合、クローンが複数の場合どうすればいいかわかりませんでした・・・ もし仮にクローンを一つ作った場合では、 Rigidbody nomalEnemyRigidbody = nomalEnemyPrefab.GetComponent<Rigidbody>(); はどのように変更すればいいのでしょうか。
guest

回答2

0

ベストアンサー

力を加える対象については、PinoMatchaさんのご回答のようにシーン上に生成された敵オブジェクトとする必要があるでしょう。
あとは複数のオブジェクトをどう扱うかですが、プレイヤーがその都度シーン内の敵を探すのが手軽かと思います。

C#

1using UnityEngine; 2 3public class Player : MonoBehaviour 4{ 5 [SerializeField] float blowOffStrength = 1.0f; 6 7 void Update() 8 { 9 if (Input.GetKeyDown(KeyCode.Space)) 10 { 11 ExplodeEnemies(); 12 } 13 } 14 15 void ExplodeEnemies() 16 { 17 // 敵プレハブにはあらかじめ何らかのタグ(さしあたり「Enemy」とした)を付けておく 18 // すると、クローンも同じタグが付いた状態で生成されるはずなので、FindGameObjectsWithTagで 19 // すべての敵クローンを探し出すことができるはず 20 foreach (GameObject enemy in GameObject.FindGameObjectsWithTag("Enemy")) 21 { 22 Rigidbody enemyRigidbody = enemy.GetComponent<Rigidbody>(); 23 Vector3 enemyAwayFromPlayer = enemy.transform.position - transform.position; 24 enemyRigidbody.AddForce(enemyAwayFromPlayer * blowOffStrength, ForceMode.Impulse); 25 } 26 } 27}

ご質問者さんもFindObjectsOfTypeを試されたようですが、なにがダメだったんでしょうかね。プレイヤーも敵もそれ以外も含めたあらゆるRigidbodyが取得されてしまい、全部吹っ飛んだ...とかでしょうか?

別案としては、こちらは敵クローン生成役のスクリプトにも手を加えることになりますが、クローンを生成したときに敵生成役がオブジェクトの参照を保持しておき、プレイヤースクリプトは敵生成役からクローンへの参照を得る手が考えられるでしょう。

C#

1using System.Collections; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5 6public class EnemyManager : MonoBehaviour 7{ 8 // ここに敵プレハブをセットしておく 9 [SerializeField] GameObject enemyPrefab; 10 11 // 敵クローンを生成するたび、このリストにそれを追加していくことにする 12 readonly List<GameObject> enemies = new List<GameObject>(); 13 14 void SpawnAt(Vector3 worldPosition) 15 { 16 // 生成した敵はenemiesリストに追加する 17 enemies.Add(Instantiate(enemyPrefab, worldPosition, Quaternion.identity)); 18 } 19 20 // 他のスクリプト(Playerなど)で敵クローンを列挙するためのプロパティを用意する 21 // ゲームの進行に伴い敵クローンが破壊されていく可能性があるが、enemiesリスト上には 22 // 死んだクローンの残骸もそのまま残ることになるため、それらはWhereで除外した 23 public IEnumerable<GameObject> Enemies => enemies.Where(enemy => enemy != null); 24 25 IEnumerator Start() 26 { 27 // さしあたり1秒ごとに地上10m、半径10mの円内のどこかに敵を生成することにした 28 YieldInstruction wait = new WaitForSeconds(1.0f); 29 while (true) 30 { 31 yield return wait; 32 33 Vector2 randomPosition = Random.insideUnitCircle * 10.0f; 34 SpawnAt(new Vector3(randomPosition.x, 10.0f, randomPosition.y)); 35 } 36 } 37}

C#

1using UnityEngine; 2 3public class Player : MonoBehaviour 4{ 5 [SerializeField] float blowOffStrength = 1.0f; 6 7 // ここに上述のEnemyManagerをアタッチしたオブジェクトをセットしておく 8 [SerializeField] EnemyManager enemyManager; 9 10 void Update() 11 { 12 if (Input.GetKeyDown(KeyCode.Space)) 13 { 14 ExplodeEnemies(); 15 } 16 } 17 18 void ExplodeEnemies() 19 { 20 // enemyManagerのEnemiesプロパティを使って敵クローンを列挙する 21 // こちらの場合は敵クローンのタグは何でもかまわない 22 foreach (GameObject enemy in enemyManager.Enemies) 23 { 24 Rigidbody enemyRigidbody = enemy.GetComponent<Rigidbody>(); 25 Vector3 enemyAwayFromPlayer = enemy.transform.position - transform.position; 26 enemyRigidbody.AddForce(enemyAwayFromPlayer * blowOffStrength, ForceMode.Impulse); 27 } 28 } 29}

こちらの方式の場合、敵生成役が保持する参照はGameObjectでなくともかまいません。

C#

1using System.Collections; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5 6public class EnemyManager : MonoBehaviour 7{ 8 [SerializeField] GameObject enemyPrefab; 9 10 // Rigidbodyを保持しておいてもよい 11 readonly List<Rigidbody> enemyRigidbodies = new List<Rigidbody>(); 12 13 void SpawnAt(Vector3 worldPosition) 14 { 15 // 敵を生成するとともに、生成された敵からRigidbodyを取得し、enemyRigidbodiesリストに追加する 16 enemyRigidbodies.Add(Instantiate(enemyPrefab, worldPosition, Quaternion.identity).GetComponent<Rigidbody>()); 17 } 18 19 public IEnumerable<Rigidbody> EnemyRigidbodies => enemyRigidbodies.Where(enemyRigidbody => enemyRigidbody != null); 20 21 IEnumerator Start() 22 { 23 YieldInstruction wait = new WaitForSeconds(1.0f); 24 while (true) 25 { 26 yield return wait; 27 28 Vector2 randomPosition = Random.insideUnitCircle * 10.0f; 29 SpawnAt(new Vector3(randomPosition.x, 10.0f, randomPosition.y)); 30 } 31 } 32}

C#

1using UnityEngine; 2 3public class Player : MonoBehaviour 4{ 5 [SerializeField] float blowOffStrength = 1.0f; 6 [SerializeField] EnemyManager enemyManager; 7 8 void Update() 9 { 10 if (Input.GetKeyDown(KeyCode.Space)) 11 { 12 ExplodeEnemies(); 13 } 14 } 15 16 void ExplodeEnemies() 17 { 18 foreach (Rigidbody enemyRigidbody in enemyManager.EnemyRigidbodies) 19 { 20 Vector3 enemyAwayFromPlayer = enemyRigidbody.position - transform.position; 21 enemyRigidbody.AddForce(enemyAwayFromPlayer * blowOffStrength, ForceMode.Impulse); 22 } 23 } 24}

あるオブジェクトに力を加える処理をプレイヤー側、敵側のどちらに書くべきか...ということについては、小規模なゲームでしたらどちらでもかまわないんじゃないでしょうかね?
意味付けの観点からは「オブジェクトに力を加える」という行為の主体はプレイヤー側でしょうから、プレイヤー側に記述するのが自然かもしれません。ですが「プレイヤーは敵に『吹っ飛べ』と命令を出し、命令を受けた敵は自分自身に力を加えて吹っ飛ぶ」ととらえれば敵側に処理を記述してもいいように見えてきます。

ある程度複雑なゲームの場合は、この辺もきっちり役割分担を検討した方がいいでしょうね。ある敵は爆発が効かなかったり、別の敵は爆発攻撃に反応してプレイヤーに反撃したり...などと複雑化してくると、それらの処理を全部プレイヤーの責務としてプレイヤースクリプトに記述してしまえば、大量の条件分岐がある混沌としたスクリプトになってしまいそうです。
AddForceみたいな具体的な処理は、プレイヤーでも敵でもなく第3の「シーン内オブジェクトの相互作用処理役」を用意して、そこに実装するという手もあるかもしれませんね。プレイヤーや敵は「○○を狙って攻撃力××の実弾攻撃を行う」とか「地点△△を中心に攻撃力□□の爆発攻撃を行う」みたいな抽象的なイベントを発生させ、実処理役がそれらに呼応してキャラクターを吹っ飛ばしたり体力を減らしたり、みたいな感じで...

投稿2021/01/30 11:05

編集2021/01/30 11:09
Bongo

総合スコア10811

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

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

actionstudio

2021/01/30 23:31

様々なやり方があり驚きました。すべて理解しきれなかったですが、とても参考になりました。 頑張って作ってみようと思います。
guest

0

prefabから出現させたクローンに、力を加えて

とのことですが、プレファブのRigidbodyを参照しても意味はありません。
クローンの方に力を加えてください。

以下、参考に

C#

1void Start () { 2 // プレファブからインスタンス作成 3 var clone = Instantiate(/*省略*/); 4 var cloneRb = clone.GetComponent<Rigidbody>(); 5 6 // addforce 7 cloeRb.AddForce(/*省略*/); 8}

投稿2021/01/30 03:34

PinoMatcha

総合スコア368

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

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

actionstudio

2021/01/30 23:29

やはりプレハブを参照しても意味がなかったのですね。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問