Related Posts Plugin for WordPress, Blogger...

7-6 Creating A Simple 2D Game For Reinforcement Learning (2)

本章要繼續來建構我們的2D遊戲場景啦!接下來,請先到Sunnlyland/artwork/Environment資料夾底下,找到tileset-sliced檔案,這是一個已經切割好的場景圖檔。


選擇圖片以後,在Inspector選擇Sprite Editor。

接著會開啟編輯視窗,大家可以看到這邊已經切割好每一個小元件了。假設大家自己的素材是沒有切割好的話,就請先切割吧。

然後在tileset-sliced旁有一顆小箭頭,按下去後會展開所有小元件。然後我們將第一個小元件拉進場景吧。

拉進場景以後,再進行複製,可以使用下圖的方式進行排列。另一個更好的選擇,是使用Unity提供的TileMap,這是一個免費提供的工具,但因為我使用的Unity版本2018.1.0的TileMap無法正常使用,所以我才使用比較原始的方式佈置場景。

排列好以後,就會長得如下圖。

接著我又進行了更多的複製與排列,這結構看起來略為複雜。

最後,請在結構最上層的tileset-sliced_0新增一個Box Collider 2D。

player-idle-1新增Box Collider 2 D,以及Rigidbody2D。

然後請自己調整Box Collider 2 D的大小。

場景的Box Collider 2 D也是如此設置。

接著,在Animator中新增一個名為Jump的Boolean參數。

並將Animator如下佈置。

然後記得在Jump新增補間動畫,Samples設為6。如不會操作Animator與Animation的話,可以參考上一篇文章:
7-5 Creating A Simple 2D Game For Reinforcement Learning (1)
https://3dactionrpg.blogspot.com/2018/07/7-5-creating-simple-2d-game-for.html


然後我在Animator中的每一個Transition,都關掉了Has Exit Time,並將Transition Duration(s)設為0。這樣就會快速切換不同的動畫,由於2D動畫的影格變化很急速,跳起來就應該要立即換成跳躍的圖片,並不會像3D動畫那樣需要切換時間。

然後player-idle-1的Rigidbody2D的Constraints要設定Freeze Rotation Z,這樣角色跳躍的時候,才不會因為撞到牆壁的邊邊角角,導致角色倒下來。

接著來撰寫PlayerMovement的程式吧,以下提供程式碼和註解,只要你有依照上面的教學做好前置步驟的話,下面的腳本就可以直接拿去用啦:

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    [SerializeField] Rigidbody2D myRigidbody2D;
    [SerializeField] Animator animator;
    [SerializeField] float speed = 30;
    [SerializeField] float jumpHeight = 2;

    bool isGround = false;

    const int MOVE_STOP = 0;
    const int MOVE_RIGHT = 1;
    const int MOVE_LEFT = -1;
    const int RIGHT_DIRECTION = 0;
    const int LEFT_DIRECTION = 1;

    void Update()
    {
        // 按下方向鍵左鍵,或右鍵時進行移動,開啟Run動畫
        if (Input.GetKey(KeyCode.RightArrow))
        {
            Move(MOVE_RIGHT);
            ChangeDirection(RIGHT_DIRECTION);
            SetRunAnimator(true);
        }
        else if (Input.GetKey(KeyCode.LeftArrow))
        {
            Move(MOVE_LEFT);
            ChangeDirection(LEFT_DIRECTION);
            SetRunAnimator(true);
        }
        // 放開方向鍵左鍵或右鍵時關閉Run動畫
        else if (Input.GetKeyUp(KeyCode.RightArrow) || Input.GetKeyUp(KeyCode.LeftArrow))
        {
            Move(MOVE_STOP);
            SetRunAnimator(false);
        }
        // 按下Z鍵呼叫Jump方法,開啟Jump動畫
        if (Input.GetKey(KeyCode.Z))
        {
            Jump();
            SetJumpAnimator(true);
        }
        // 當Player回到地面時,關閉Jump動畫
        if (isGround)
        {
            SetJumpAnimator(false);
        }
    }

    void Jump()
    {
        // 當Player不在地面時,不要再設定Velocity
        if (!isGround)
        {
            return;
        }
        // 設定Player的Velocity的Y值,即可讓Player跳起
        Vector2 velocity = myRigidbody2D.velocity;
        velocity.y = jumpHeight;
        myRigidbody2D.velocity = velocity;
    }

    void Move(int i)
    {
        // 設定Player的Velocity的X值,即可讓Player移動
        Vector2 velocity = myRigidbody2D.velocity;
        velocity.x = i * speed * Time.deltaTime;
        myRigidbody2D.velocity = velocity;
    }

    void ChangeDirection(int i)
    {
        // 若i為1則會將Y軸轉向180度,若i為0則會轉回原方向
        // 藉此控制角色的轉向
        transform.eulerAngles = new Vector3(0, 180 * i, 0);
    }

    void SetRunAnimator(bool isMove)
    {
        animator.SetBool("Run", isMove);
    }

    void SetJumpAnimator(bool isJump)
    {
        animator.SetBool("Jump", isJump);
    }

    private void OnCollisionStay2D(Collision2D collision)
    {
        //若接觸點的法線向量不為上的話,代表並非撞到地板
        if (collision.contacts[0].normal != Vector2.up)
            return;
        isGround = true;
    }

    private void OnCollisionExit2D(Collision2D collision)
    {
        isGround = false;
    }
}


將PlayerMovement.cs加入player-idle-1,並拉入Rigidbody2D與Animator,然後Speed設為30,Jump Height設為3.5。這個數值是我測試後,覺得還滿意的數值,大家可以依自己的需求修改唷。

最後,執行遊戲看看吧,下面就是執行後的動畫圖啦!

留言