前回はプレイヤーキャラクターの作成などを行いました。
前回の記事:
今回の記事ではプレイヤーに自動追尾するキャラクターを作成していきます。
また、作成したプレハブをマップに配置するスクリプトも作成します。
追従するキャラクターのコンポーネントの作成
それでは先に必要となるスクリプトの方を作成していきます。
新しく「JoinableCharacter.cs」というスクリプトを作成してください。保存先はお好みでOKですが、記事ではAssetsフォルダーに保存しています。
「JoinableCharacter.cs」の内容は次のようにしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
// JoinableCharacter.cs JoinableCharacterコンポーネントの作成 using System.Collections; using System.Collections.Generic; using UnityEngine; class JoinableCharacter : CharacterBase { public enum State { Free, Joined, } [SerializeField] CharacterBase _followedTarget; [SerializeField] State CurrentState; [Range(0.5f, 15f)] public float FreeMoveSeconds = 3f; [Range(0.5f, 15f)] public float FreeWaitSeconds = 3f; public CharacterBase FollowedTarget { get => _followedTarget; set { if (_followedTarget == value) return; _followedTarget = value; if(value == null) { StartFree(); } else { StartJoined(); } } } public bool IsJoinable(CharacterBase other) { return other != FollowedTarget && !(other is JoinableCharacter); } Coroutine _currentCoroutine; public void StartFree() { if (_currentCoroutine != null) { StopCoroutine(_currentCoroutine); } CurrentState = State.Free; _currentCoroutine = StartCoroutine(FreeCoroutine()); } IEnumerator FreeCoroutine() { var rnd = new System.Random(gameObject.GetInstanceID() + System.DateTime.Now.Millisecond); while (true) { var t = 0f; var vec = Vector3.zero; vec.x = (float)rnd.NextDouble() * 2 - 1; vec.z = (float)rnd.NextDouble() * 2 - 1; vec.Normalize(); vec *= SpeedPerSeconds; while (t < FreeMoveSeconds) { t += Time.deltaTime; Move(vec); yield return null; } yield return new WaitForSeconds(FreeWaitSeconds); } } public void StartJoined() { if (_currentCoroutine != null) { StopCoroutine(_currentCoroutine); } CurrentState = State.Joined; _currentCoroutine = StartCoroutine(JoinedCoroutine()); } IEnumerator JoinedCoroutine() { while (true) { //TODO yield return null; } } protected override void Start() { StartFree(); } } |
再生時にマップに自動的に配置する処理の追加
次に再生時に追従するキャラクターを自動的に配置する処理を「Map」コンポーネントに追加していきます。
「Map」コンポーネントを次のように修正して下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// Map.cs 追従するキャラクターの自動配置処理の作成 //次のものを修正 void Awake() { BuildMap(); InitJoinableCharacter(); } //次のものを追加 public JoinableCharacter JoinableCharacterPrefab; [Range(0, 100)] public int InitJoinableCharacterCount = 20; public Vector3 SpawnOffset = new Vector3(0.5f, 0, 0.5f); public void InitJoinableCharacter() { var buildingGridSize = GridSize - new Vector3Int(1, 0, 1); var massSize = new Vector3( Size.x / buildingGridSize.x, 1, Size.z / buildingGridSize.z); var start = new Vector3(-Size.x / 2, 0, -Size.z / 2); var oneLoopCount = (GridSize.x * GridSize.z); for (var i=0; i< InitJoinableCharacterCount; ++i) { var obj = Object.Instantiate(JoinableCharacterPrefab, transform); var xIndex = (i % oneLoopCount) % GridSize.x; var zIndex = (i % oneLoopCount) / GridSize.x; var loopCount = i / oneLoopCount; obj.transform.localPosition = new Vector3( start.x + massSize.x * xIndex, 0, start.z + massSize.z * zIndex ) + SpawnOffset * loopCount; } } |
「InitJoinableCharacterCount」フィールドは追従するキャラクターの生成数になります。
「SpawnOffset」フィールドは同じ場所に追従するキャラクターを生成すると物理エンジンによって弾かれるのを防ぐためのものです。
「InitJoinableCharacterCount」フィールドが極端に大きい場合は建物の中に被ってしまうなどの問題が出てくるので注意して下さい。
追従するキャラクターのプレハブの作成
ここまででスクリプトができたので次はGameObjectの方を作成してきます。
次の手順を行って追従するキャラクター用のプレハブを作成して下さい。
- メニューのGameObject > 空のGameObjectをクリックし新しいGameObjectを作成してください。
- 作成したGameObjectの名前は「JoinableCharacter」に変更してください。
- 「JoinableCharacter」の子GameObjectとしてメニューのGameObject > 3DObject > SphereをクリックしGameObjectを作成してください。
- 作成したGameObjectの名前は「Model」にしてください。
「JoinableCharacter」のGameObject階層は次のようになっています。
- JoinableCharacter : 空のGameObject
- – Model : 3DObject > Sphere
これらの設定内容は次のようにしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// JoinableCharacterの設定内容 ## JoinableCharacter : 空のGameObject - Transformコンポーネント Position : 0, 0, 0 Rotation : 0, 0, 0 Scale : 1, 1, 1 - JoinableCharacterコンポーネント <- 追加 SpeedPerSeconds : 3 - Rigidbodyコンポーネント <- 追加 Mass : 1 // 調節すると他のオブジェクトからの押しやすさを調節できます。 UseGravity : true IsKinematic : false Constraints FreezePosition: x=false y=false z=false Constraints FreezeRotation: x=true y=true z=true - BoxColliderコンポーネント <- 追加 IsTrigger : false Center : 0, 0.5, 0 Size: 1, 1, 1 ## JoinableCharacter > Model : 3DObject > Cube - Transformコンポーネント Position : 0, 0.5, 0 Rotation : 0, 0, 0 Scale : 1, 1, 1 - SphereColliderコンポーネント <- 削除 |
設定が終わりましたら「JoinableCharacter」をプレハブ化して下さい。その後にシーンにあるものは削除して下さい。
次にその他の設定が必要なものを設定していきます。
1 2 3 4 5 6 |
// シーン上のGameObjectに追加の設定 ## Map - Mapコンポーネント JoinableCharacterPrefab: 「JoinableCharacter」プレハブ InitJoinableCharacter : 25 SpawnOffset : 0.5, 0, 0.5 |
設定できましたら、実際に再生してみて動作を確認してみて下さい。
まとめ
今回の記事では追従するキャラクターを作成し、マップ上に自動的に配置するようにしていきました。
かなり規則正しい移動を行うので改良するなら、乱数を使って指定した時間に振れ幅を持たせたりするといいでしょう!
また、マップ際で無理やり移動する状況になるとたまにマップから落ちてしまいますが、物理エンジンまわりの問題になります。
今回はこの辺の対処は読者の方にお任せします。(当たり判定用のGameObjectを追加するか、位置修正処理を追加するかになります)
まとめますと以下のようになります。
- 追従するキャラクター用のコンポーネントの作成
- 再生時にマップにランダムに配置するようにした
それでは次の記事に行ってみましょう!
コメント