今回はキャラクターが乗ったらシーソーする床を作成してみます。
CharacterControllerコンポーネントでキャラクターを操作している場合はそのままでは物理的な影響を受けない代わりに影響を与える事も出来ません。
また相手方でOnTriggerEnterやOnCollisionEnter等でキャラクターを検知する事も出来ません(IsTriggerにチェックが入っている場合OnTriggerEnterは使えます)。
しかし、CharacterControllerでは他のコライダと接触している時にOnControllerColliderHitというメソッドが呼ばれるのでそれを使って他のコライダに力を加える事が出来ます。
今回はOnControllerColliderHitを使い床を検知して床に力を加え、床がシーソーするようにしていきます。
シーソーする床を作成する
まずはシーソーする床を作成します。
床は
で作った物とほぼ同じですが、物理的な影響を与える為Rigidbodyを追加しています。
ヒエラルキーで右クリック→3D Object→Cubeを選択、作成し、名前をFrictionCube1とします。
↑のようにAdd Component→Physic→Rigidbodyを追加し、ConstraintsのFreeze RotationZ以外をすべてチェックします。
これでゲームオブジェクトは位置が変わらずZ軸を基点に回転するだけになります。
ゲームオブジェクトの向きによってFreeze Rotationのチェックする位置が変わりますので、ご自分の環境に合わせて変更してください。
Use Gravityのチェックはしてもしなくても構いません(Freeze Positionにチェックを入れている為位置は変わらない)。
床には力を加えるのでIs Kinematicのチェックは外しておきます。
また床がシーソーした後に回転の空気抵抗を与える為にAngular Dragに1を設定しています。
この値を大きくすると抵抗が強くなる為に回転が早く止まるようになります。
あまり大きくしすぎると力がかかっていないように見えます。
FrictionCube1にはBlockタグ、Blockレイヤーを設定してください。
Blockタグ、レイヤーがない場合は作成し設定するようにしてください。
↑のような感じでシーソーする床が出来上がりました。
キャラクターが床に乗った時に下向きに力を加える
後はキャラクターがこの床に乗った時に下向きに力を加えればいい事になります。
キャラクターが床に力を加えるスクリプトSeeSawCharaスクリプトを作成します。
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 | using UnityEngine; using System.Collections; public class SeeSawChara : MonoBehaviour { private CharacterController characterController; private Animator animator; private Vector3 velocity = Vector3.zero; [SerializeField] private float walkSpeed = 1.5f; [SerializeField] private float jumpPower = 5f; // 床に与える力 [SerializeField] private float power = 20f; // Use this for initialization void Start () { characterController = GetComponent <CharacterController> (); animator = GetComponent <Animator> (); } // Update is called once per frame void Update () { if (characterController.isGrounded) { velocity = Vector3.zero; var input = new Vector3 (Input.GetAxis ("Horizontal"), 0f, Input.GetAxis ("Vertical")); if (input.magnitude > 0f) { animator.SetFloat ("Speed", input.magnitude); transform.LookAt (transform.position + input); velocity = transform.forward * walkSpeed; } else { animator.SetFloat ("Speed", 0f); } if(Input.GetButtonDown ("Jump") && !animator.GetCurrentAnimatorStateInfo (0).IsName ("Jump") && !animator.IsInTransition (0) ) { animator.SetBool ("Jump", true); velocity.y += jumpPower; } } velocity.y += Physics.gravity.y * Time.deltaTime; characterController.Move (velocity * Time.deltaTime); } // 他のコライダと接触した時 void OnControllerColliderHit(ControllerColliderHit col) { // 確認の為レイを視覚的に見えるようにする Debug.DrawLine(transform.position + Vector3.up * 0.1f, transform.position + Vector3.up * 0.1f + Vector3.down * 0.2f, Color.red); // rayPositionから下にレイを飛ばし、Blockレイヤーに当たっていたら力を加える if(Physics.Linecast(transform.position + Vector3.up * 0.1f, transform.position + Vector3.up * 0.1f + Vector3.down * 0.2f, LayerMask.GetMask("Block"))) { col.gameObject.GetComponent <Rigidbody>().AddForceAtPosition (Vector3.down * power, transform.position, ForceMode.Force); } } } |
少しづつ見ていきます。
1 2 3 4 5 | // 床に与える力 [SerializeField] private float power = 20f; |
powerはキャラクターがシーソーに乗った時に主人公の位置から下に加える力です。
1 2 3 4 5 6 7 8 9 10 11 12 | // 他のコライダと接触した時 void OnControllerColliderHit(ControllerColliderHit col) { // 確認の為レイを視覚的に見えるようにする Debug.DrawLine(transform.position + Vector3.up * 0.1f, transform.position + Vector3.up * 0.1f + Vector3.down * 0.2f, Color.red); // rayPositionから下にレイを飛ばし、Blockレイヤーに当たっていたら力を加える if(Physics.Linecast(transform.position + Vector3.up * 0.1f, transform.position + Vector3.up * 0.1f + Vector3.down * 0.2f, LayerMask.GetMask("Block"))) { col.gameObject.GetComponent <Rigidbody>().AddForceAtPosition (Vector3.down * power, transform.position, ForceMode.Force); } } |
キャラクターが床に乗っているのではなくただ接触している時(シーソーの横に接触している時)は力を加えないようにする為、
キャラクターの位置の少し上から下向きにレイを飛ばしてBlockレイヤーが設定されたゲームオブジェクトがあるかどうかを判定します。
1 2 3 | col.gameObject.GetComponent <Rigidbody>().AddForceAtPosition (Vector3.down * power, transform.position, ForceMode.Force); |
シーソーする床のゲームオブジェクトに設定しているRigidbodyを取得し、AddForceAtPositionでキャラクターの位置から下向きに力を加えています。
AddForceはゲームオブジェクト自体に力を加える事が出来ますが、今回の場合ゲームオブジェクトのある一点に力を加える必要があります。
AddForceはゲームオブジェクト全体、AddForceAtPositionはゲームオブジェクトの一定の位置に力を加えます。
その為AddForceAtPositionを使い、キャラクターがいる位置から下に力を加えることによって床がシーソーするようにします。
これでスクリプトが完成しました。
床がシーソーするか確認する
キャラクターにSeeSawCharaスクリプトを取りつけて、
それではUnityの実行ボタンを押して確認してみましょう。
↑のようにキャラクターがシーソー床に乗った時にその位置から下に力が働くようになりました。
動画を見るとわかりますが、CharacterControllerを使用している為シーソー床の下からジャンプしても床を突き抜け床の上に飛び乗る事が出来てしまいます。
これが嫌な方はRigidbody+コライダで移動するキャラクターを使った方がいいかもしれませんね。
これでUnityでキャラクターが乗ったらシーソーする床の作成が出来ました。
床がシーソーするステージを飛んで移動するようなアクションゲームとか面白そうですね!
最近段々とRigidbody+コライダで動かすキャラクターの方がいいんじゃないかと思えてきました・・・(^_^;)
Rigidbody+Capsule Colliderを使ったキャラクターの移動方法は
を参照してください。