7.Creating Destructible Walls
壊れる壁を作ります。ダメージを受けている状態のスプライトをpublicで設定可能にして、それに置き換える、という動作を指定ます。
8.Player Animator Controller
Mecanimというアニメーションコントロールの仕組みのキモとなる、Animator Controllerの設定方法について解説しています。
まず、playrHit/Chopに遷移するためのきっかけを、Triggerとして作成します。(Triggerはboolean)
そして、PlayerIdleからPlayerHit,PlayerChopにTransitionを繋ぎます。
IdleからHit/Chopにはすぐ変更されてほしいので、Has Exit Timeをfalseに、Dulationを0にします。
帰りはHit/Chopのアニメーションが1回終わってからIdleに戻って欲しいので、Has Exit Timeをtureにして、Exit Timeを1、Drationを0にしておきます。
TransitionのConditionとして、先ほど作成したTriggerを設定します。
AnimatorウインドウをGameウインドウを同時に表示できるようにしておくと、Animation ControllerのTriggerの値をマウスでリアルタイムに変更してプレビューを行うことができます。
9.Writing the Player Script
Playerの動きを作っていきます。Player.csは、前回作ったMovingObject.csを継承しています。
private void Update () { //If it's not the player's turn, exit the function. if(!GameManager.instance.playersTurn) return; int horizontal = 0; //Used to store the horizontal move direction. int vertical = 0; //Used to store the vertical move direction. //Get input from the input manager, round it to an integer and store in horizontal to set x axis move direction horizontal = (int) (Input.GetAxisRaw ("Horizontal")); //Get input from the input manager, round it to an integer and store in vertical to set y axis move direction vertical = (int) (Input.GetAxisRaw ("Vertical")); //Check if moving horizontally, if so set vertical to zero. if(horizontal != 0) { vertical = 0; } //Check if we have a non-zero value for horizontal or vertical if(horizontal != 0 || vertical != 0) { //Call AttemptMove passing in the generic parameter Wall, since that is what Player may interact with if they encounter one (by attacking it) //Pass in horizontal and vertical as parameters to specify the direction to move Player in. AttemptMove<wall> (horizontal, vertical); } }
まず、左右のキーと上下のキーがが同時押しされたら、上下のキーは無視するようにします。(左右が優先)
そして、AttemptMoveを使用して移動します。 引数の<Wall>は、Wall型に対して当たり判定が発生するかどうかを確認しています。もしWallに当っていたら、Wallに対してダメージを与えたことになります。(Enemyを指定しないのは、このゲームではEnemyにダメージを与えることはできないからです)
//AttemptMove overrides the AttemptMove function in the base class MovingObject //AttemptMove takes a generic parameter T which for Player will be of the type Wall, it also takes integers for x and y direction to move in. protected override void AttemptMove <t> (int xDir, int yDir) { //Every time player moves, subtract from food points total. food--; //Call the AttemptMove method of the base class, passing in the component T (in this case Wall) and x and y direction to move. base.AttemptMove <t> (xDir, yDir); //Hit allows us to reference the result of the Linecast done in Move. RaycastHit2D hit; //If Move returns true, meaning Player was able to move into an empty space. if (Move (xDir, yDir, out hit)) { //Call RandomizeSfx of SoundManager to play the move sound, passing in two audio clips to choose from. } //Since the player has moved and lost food points, check if the game has ended. CheckIfGameOver (); //Set the playersTurn boolean of GameManager to false now that players turn is over. GameManager.instance.playersTurn = false; }
AttemptMoveをoverrideしています。foodを減らし、ベースクラスのAttemptMoveを実行します。
次にまたMoveを実行していますが、これを実行すると2回移動する気がするのですが・・(ビデオ内では現時点ではこのMoveはありません)。ちょっと謎です。
//OnCantMove overrides the abstract function OnCantMove in MovingObject. //It takes a generic parameter T which in the case of Player is a Wall which the player can attack and destroy. protected override void OnCantMove <t> (T component) { //Set hitWall to equal the component passed in as a parameter. Wall hitWall = component as Wall; //Call the DamageWall function of the Wall we are hitting. hitWall.DamageWall (wallDamage); //Set the attack trigger of the player's animation controller in order to play the player's attack animation. animator.SetTrigger ("playerChop"); }
OnCantMoveはベースクラスのAttemptMoveで、移動できない時に呼び出されるメソッドです。Wallに対して当たり判定があった、という判断になるので、Wallにダメージを与えて、アニメーションを変更します。Mecanimでアニメーションを書くと、制御がとても簡単になりますね。
//OnTriggerEnter2D is sent when another object enters a trigger collider attached to this object (2D physics only). private void OnTriggerEnter2D (Collider2D other) { //Check if the tag of the trigger collided with is Exit. if(other.tag == "Exit") { //Invoke the Restart function to start the next level with a delay of restartLevelDelay (default 1 second). Invoke ("Restart", restartLevelDelay); //Disable the player object since level is over. enabled = false; } //Check if the tag of the trigger collided with is Food. else if(other.tag == "Food") { //Add pointsPerFood to the players current food total. food += pointsPerFood; //Disable the food object the player collided with. other.gameObject.SetActive (false); } //Check if the tag of the trigger collided with is Soda. else if(other.tag == "Soda") { //Add pointsPerSoda to players food points total food += pointsPerSoda; //Disable the soda object the player collided with. other.gameObject.SetActive (false); } }
当たり判定のあるオブジェクトに当たった場合は、tagにより対象を判別して処理を分岐します。