❤❤Fungus新課程即將發布,快寫問卷拿優惠❤❤

2017年5月9日 星期二

Unity 教學 2D 遊戲角色移動 程式篇





影片中的專案下載(台幣約30元)
https://gumroad.com/l/iLyXq

Unity 2D遊戲角色移動控制 程式篇
用淺顯易懂的方式解說如何實作2D角色移動的控制 包含走路與跳躍
而且能用 Physics2D.Linecast 判定是否在地板上,是的話才能跳躍(也就是不能在空中連跳)
並且附上2D platform Effector 的簡易說明

延伸閱讀:
Unity 5.5 2D Effectors 力場教學:2D平台, 橫向捲軸, 風吹, 瀑布, 漂浮, 黑洞, 爆炸, 輸送帶
http://www.morningfungame.com/2017/01/unity-55-2d-effectors-2d.html

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    Rigidbody2D playerRigidbody2D;

    [Header("目前的水平速度")]
    public float speedX;

    [Header("目前的水平方向")]
    public float horizontalDirection;//數值會在 -1~1之間

    const string HORIZONTAL = "Horizontal";

    [Header("水平推力")]
    [Range(0, 150)]
    public float xForce;

    //目前垂直速度
    float speedY;

    [Header("最大水平速度")]
    public float maxSpeedX;

    [Header("垂直向上推力")]
    public float yForce;

    [Header("感應地板的距離")]
    [Range(0, 0.5f)]
    public float distance;

    [Header("偵測地板的射線起點")]
    public Transform groundCheck;

    [Header("地面圖層")]
    public LayerMask groundLayer;

    public bool grounded;

    public void ControlSpeed()
    {
        speedX = playerRigidbody2D.velocity.x;
        speedY = playerRigidbody2D.velocity.y;
        float newSpeedX = Mathf.Clamp(speedX, -maxSpeedX, maxSpeedX);
        playerRigidbody2D.velocity = new Vector2(newSpeedX, speedY);
    }

    public bool JumpKey
    {
        get
        {
            return Input.GetKeyDown(KeyCode.Space);
        }
    }

    void TryJump()
    {
        if (IsGround && JumpKey)
        {
            playerRigidbody2D.AddForce(Vector2.up * yForce);
        }
    }

    //在玩家的底部射一條很短的射線 如果射線有打到地板圖層的話 代表正在踩著地板
    bool IsGround
    {
        get
        {
            Vector2 start = groundCheck.position;
            Vector2 end = new Vector2(start.x, start.y - distance);

            Debug.DrawLine(start, end, Color.blue);
            grounded = Physics2D.Linecast(start, end, groundLayer);
            return grounded;
        }
    }

    void Start()
    {
        playerRigidbody2D = GetComponent<Rigidbody2D>();
    }

    /// <summary>水平移動</summary>
    void MovementX()
    {
        horizontalDirection = Input.GetAxis(HORIZONTAL);
        playerRigidbody2D.AddForce(new Vector2(xForce * horizontalDirection, 0));
    }

    void Update()
    {
        MovementX();
        ControlSpeed();
        TryJump();
        //speedX = playerRigidbody2D.velocity.x;
    }
}

22 則留言:

  1. 作者已經移除這則留言。

    回覆刪除
    回覆
    1. 你是說輸入rig的時候無法跳出Rigibody2D讓你選嗎?這個功能叫做自動完成,這樣的話要關掉visual studio以後再重開。visual studio正在啟動的時候別執行任何操作,不然有時候自動完成的功能會失效

      刪除
    2. 不好意思~我也遇到一樣的狀況,我有照著做關掉Visual Studio以後重開,可是Rigidbody2D還是不會跳出讓我選,而且Rigidbody2D的顏色是白色不是綠色,請問要怎麼做才好呢?謝謝您~

      刪除
    3. 我找到問題了謝謝你~

      刪除
  2. 您好:
    看完您的教學後我想讓角色落地後會減速至0
    但慣性太大了,往往衝過頭
    改用Translate卻產生抖動
    該怎麼讓移動看起來更順暢
    更自然呢

    回覆刪除
    回覆
    1. 你說的衝過頭是指穿透地板嗎? 試試看把地板的Collider加厚吧

      刪除
    2. 我指的是左右移動的速度
      我想要在放開按鍵後不再移動,變成靜止狀態
      可是如果用addforce他就會有個慣性繼續移動
      後來我用Translate有達到我要的效果了
      不過在移動時撞到牆壁,持續按著移動按鍵會抖動
      有辦法改善嗎?

      原因是否為Translate運算改變player位置後發現撞牆,所以又改變一次位置
      所以變成一直來回來回的抖動?

      還有我是想做連線的2D遊戲
      能問你相關的問題嗎?

      刪除
    3. 那你可以試試在移動的程式碼裡加上判定條件,按下移動相關的按鍵同時"沒有"碰到牆壁的時候才能AddForce
      你講的原因應該沒錯,就是撞牆後回來又被往前推,結果就是一直抖動...

      連線遊戲的話我就沒概念了,建議去臉書社團 Unity應用領域 問問 那邊很多高手喔~

      刪除
    4. 了解!
      非常感謝

      刪除
  3. 不好意思,請問一下,角色在加上LineCast判斷後就無法跳躍了,已確定圖層設定正常,是否有遺漏了什麼判斷條件?

    回覆刪除
    回覆
    1. 你可以把程式碼PO出來嗎 這樣比較好幫你判斷

      刪除
    2. 還有 distance 會不會設定太短?太短的話LineCast打不到地板,就會被判定為在空中喔

      刪除
    3. public bool grounded;

      [Header("射線起點")]
      public Transform groundCheck;

      [Header("地板")]
      public LayerMask Layer;

      int distance;

      public bool JumpKey
      {
      get
      {
      return Input.GetKey(KeyCode.UpArrow);
      }
      }

      void Jump()
      {
      if (JumpKey && Ground)
      {
      player.AddForce(Vector2.up * 100f);
      }
      }

      public bool Ground
      {
      get{
      Vector2 start = groundCheck.position;
      Vector2 end = new Vector2(start.x, start.y - distance);
      Debug.DrawLine(start, end, Color.blue);
      grounded = Physics.Linecast(start, end, Layer);
      return grounded;
      }
      }

      void Update () {
      Jump();
      }

      void Start () {
      distance = 1;
      }

      刪除
    4. 不好意思...排版跑掉了...

      刪除
    5. 你找一下這兩行 照著修改:

      player.AddForce(Vector2.up * 800f); //力道改大一點,我這邊的玩家質量(重量)設比較大,要大力點才能推動

      grounded = Physics2D.Linecast(start, end, Layer);//你少寫一個2D

      以後可以上網找一下 程式碼分享 的網站,貼程式碼的時候會有自動上色的效果
      然後當你覺得程式碼"看起來"跟範例裡一模一樣,卻又找不出那裡出錯的話,找一下 文字比對 的軟體
      就可以發現其實你打的程式碼跟範例的不一樣

      我也是用文字比對軟體才知道說你少打了個2D

      刪除
    6. 目前的問題依然是Linecast偵測不到LayerMask(程式碼已修改)

      刪除
    7. 謝謝!以解決問題。
      主要好像是因為&&判斷條件先後的問題,而導致無法起跳。

      刪除
  4. 你好
    請問如果要讓玩家方向和移動方向一致的話,程式部分應該要怎麼寫呢?

    目前情況是
    當玩家向右移動的時候,看起來像是倒退那樣

    回覆刪除
  5. 這個要配合Animator動畫器來製作,人物座標向右移動時播放向右的Animation動畫,向左移動時播放向左的動畫Animation。
    關鍵字:unity 2d移動動畫

    回覆刪除
  6. 我嘗試用不一樣的方法來控制角色:按下按鈕的時候對player施力,之後放開按鈕則再施一個反向的力,讓其停止,目的是讓player可以用一個固定的速度來行進。但是測試的時候常常偵測不到,有時候只有偵測到按下,有時候只有偵測到放開,請問是哪個地方出了問題呢?

    有測試了我的鍵盤確認沒有故障
    附上程式碼


    private void FixedUpdate()
    {
    Movement();
    }


    //在這邊管理所有的行動
    void Movement()
    {
    Walk();
    Jump();
    }

    void Walk()
    {

    if (Input.GetKeyDown(KeyCode.RightArrow))
    {

    playerRigidbody2D.AddForce(Vector2.right * walkForce);
    Debug.Log("Right key down");
    }

    if (Input.GetKeyUp(KeyCode.RightArrow))
    {
    playerRigidbody2D.AddForce(Vector2.left * walkForce);
    Debug.Log("Right key up");
    }

    if (Input.GetKeyDown(KeyCode.LeftArrow))
    {
    playerRigidbody2D.AddForce(Vector2.left * walkForce);
    Debug.Log("Left key down");
    }
    if (Input.GetKeyUp(KeyCode.LeftArrow))
    {
    playerRigidbody2D.AddForce(Vector2.right * walkForce);
    Debug.Log("Left key up");
    }

    }

    void Jump()
    {

    if (Input.GetKeyDown(KeyCode.Z))
    {
    playerRigidbody2D.AddForce(new Vector2(0f, jumpForce));
    }
    }

    回覆刪除
  7. 你好 請問我角色底下放一個物件(子物件)當作射擊口,用一個物件的位置當作子彈製造點。請問要怎麼寫才能讓發射器跟著人物轉向

    回覆刪除
    回覆
    1. 字面上來看,把發射器設成人物的子物件就可以了,然後生成子彈的時候,子彈套用發射器的角度,但我擔心誤解你的問題,可以的話還是加LINE傳程式碼跟截圖比較清楚

      Line帳號連結
      http://line.me/ti/p/pTX9Io9AKW

      刪除

留言給作者加油打氣