Unity初心者がローグライクチュートリアルに挑戦(6.Moving Object Script)

6.Moving Object Script
さて、ここから一気にスクリプトが難しくなりますw

protected IEnumerator SmoothMovement (Vector3 end)
        {
            //Calculate the remaining distance to move based on the square magnitude of the difference between current position and end parameter.
            //Square magnitude is used instead of magnitude because it's computationally cheaper.
            float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
            //While that distance is greater than a very small amount (Epsilon, almost zero):
            while(sqrRemainingDistance > float.Epsilon)
            {
                //Find a new position proportionally closer to the end, based on the moveTime
                Vector3 newPostion = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
                //Call MovePosition on attached Rigidbody2D and move it to the calculated position.
                rb2D.MovePosition (newPostion);
                //Recalculate the remaining distance after moving.
                sqrRemainingDistance = (transform.position - end).sqrMagnitude;
                //Return and loop until sqrRemainingDistance is close enough to zero to end the function
                yield return null;
            }
        }

まず、スムーズに移動を行うためのコルーチン、SmoothMovement。移動先となるendを引数にします。
現在の座標と、移動先のendのsqrMagnitudeを取得します。
sqrMagnitudeは、2つのベクトル(現在の座標と、移動先)の距離を比較するときに使われる値で、これがfloat.Epsilon(ゼロではないが十分に小さい数)よりも大きい場合に、ちょっとづつ移動を行う、というループが動きます。
「ちょっと移動する」ときの移動先は、
Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
で計算します。MoveTowards関数の3番めは、「1フレーム毎の早さ x フレーム数」となり、endにどのくらい進むか、という値を示しています。
Rididbody2DのMovePositionに移動先を指定して、再度sqrMagnitudeを計算します。

        protected bool Move (int xDir, int yDir, out RaycastHit2D hit)
        {
            //Store start position to move from, based on objects current transform position.
            Vector2 start = transform.position;
            // Calculate end position based on the direction parameters passed in when calling Move.
            Vector2 end = start + new Vector2 (xDir, yDir);
            //Disable the boxCollider so that linecast doesn't hit this object's own collider.
            boxCollider.enabled = false;
            //Cast a line from start point to end point checking collision on blockingLayer.
            hit = Physics2D.Linecast (start, end, blockingLayer);
            //Re-enable boxCollider after linecast
            boxCollider.enabled = true;
            //Check if anything was hit
            if(hit.transform == null)
            {
                //If nothing was hit, start SmoothMovement co-routine passing in the Vector2 end as destination
                StartCoroutine (SmoothMovement (end));
                //Return true to say that Move was successful
                return true;
            }
            //If something was hit, return false, Move was unsuccesful.
            return false;
        }

out引数のRaicast2Dは、移動先に障害物があるかどうかを検知するためのもので、
Physics2D.Linecast (start, end, blockingLayer);
で判定しています。blockingLayerは、publicプロパティで設定するLayerMaskになります。
(最初に、自分自身のColliderをfalseにして無視してから判定して、戻す)
障害物がない場合は、先ほどのSmoothMoveを使って移動を行います。

	//The virtual keyword means AttemptMove can be overridden by inheriting classes using the override keyword.
	//AttemptMove takes a generic parameter T to specify the type of component we expect our unit to interact with if blocked (Player for Enemies, Wall for Player).
       protected virtual void AttemptMove <t> (int xDir, int yDir)
            where T : Component
        {
            //Hit will store whatever our linecast hits when Move is called.
            RaycastHit2D hit;
            //Set canMove to true if Move was successful, false if failed.
            bool canMove = Move (xDir, yDir, out hit);
            //Check if nothing was hit by linecast
            if(hit.transform == null)
                //If nothing was hit, return and don't execute further code.
                return;
            //Get a component reference to the component of type T attached to the object that was hit
            T hitComponent = hit.transform.GetComponent <t> ();
            //If canMove is false and hitComponent is not equal to null, meaning MovingObject is blocked and has hit something it can interact with.
            if(!canMove && hitComponent != null)
                //Call the OnCantMove function and pass it hitComponent as a parameter.
                OnCantMove (hitComponent);
        }

移動を試みる、という意味のAttemptMove関数です。
<T>というのは、C#のジェネリックという記載方法で、型を明示せず、汎用的に使用できるようにする方法です。
この場合は、where : Componentで、Component型のオブジェクト、またはそれを継承したオブジェクト(=Sceneに登場する全てのGameObject)を指定することができます。
具体的には、このスクリプトを使うのがPlayerの場合はWallを、Enemyの場合はPlayerを指定できるようにしています。
(PlayerがWallに当たった時に、Wallへ与えるダメージ計算をするために使用します。なお、このゲームはEnemyを破壊することはできませんので、Wallだけの指定になります)
RaycastHit2Dの変数を用意して、先ほど作成したMove変数のoutによって値を生成します。
移動に成功した場合はreturnで抜け、失敗した場合は、ヒットしたオブジェクトをhitComponentに代入します。
そして、OnCantMoveにそれを渡して、別の処理を行います。

スポンサーリンク

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

スポンサーリンク