国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

這篇具有很好參考價(jià)值的文章主要介紹了【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、前言

嗨,大家好,我是新發(fā)。
有同學(xué)私信我,問我能不能寫一篇Unity手游第一人稱視角控制的教程,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
那么,今天就來做個(gè)Demo吧~

注:Demo工程源碼見文章末尾

最終效果如下:
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

二、實(shí)現(xiàn)方案

1、無主之地,第一人稱視角

第一人稱視角的游戲大家應(yīng)該不陌生,比如《無主之地》,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
不過它是PC平臺(tái)的,使用WASD控制移動(dòng),使用鼠標(biāo)來控制鏡頭角度,單擊鼠標(biāo)左鍵開槍。注:你也可以接手柄來操作~

那么,如果我們想做移動(dòng)端(手機(jī)端)的第一人稱視角,如何做角色控制呢?

2、我之前做的搖桿控制

手機(jī)端比較常見的就是搖桿控制了,我之前在幾篇博客中都有做過搖桿控制,
《【游戲開發(fā)創(chuàng)新】用Unity等比例制作廣州地鐵,廣州加油,早日戰(zhàn)勝疫情(Unity | 地鐵地圖 | 第三人稱視角)》
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
《【游戲開發(fā)創(chuàng)新】上班通勤時(shí)間太長,做一個(gè)任意門,告別地鐵與塞車(Unity | 建模 | ShaderGraph | 搖桿 | 角色控制)》
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
《【游戲開發(fā)實(shí)戰(zhàn)】新發(fā)教你做游戲(六):教你2個(gè)步驟實(shí)現(xiàn)搖桿功能》
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

3、第一人稱視角 + 搖桿控制

我上面做的都是第三人稱視角的搖桿控制,我們改成第一人稱視角即可,也就是第一人稱視角+搖桿控制,像這樣子,(圖片說明:下圖是我在《無主之地》游戲截圖中P了搖桿的UI
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

三、開始實(shí)戰(zhàn)

1、資源獲?。篣nity AssetStore

我沒有《無主之地》的資源,沒關(guān)系,我們?nèi)?code>Unity的AssetStore上找一下FPS射擊游戲的資源,

注:Unity AssetStore地址:https://assetstore.unity.com/
關(guān)于資源的搜索,我之前寫過一篇文章:《Unity游戲開發(fā)——新發(fā)教你做游戲(二):60個(gè)Unity免費(fèi)資源獲取網(wǎng)站》

搜索關(guān)鍵字FPS Pack,馬上就搜到了一個(gè)免費(fèi)的資源Low Poly FPS Pack

【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
我們點(diǎn)擊添加至我的資源(注意需要先登錄你的Unity賬號(hào)),
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
然后回到Unity編輯器中,點(diǎn)擊菜單Windows / Package Manager,打開PackageManager窗口,就可以看到我們剛剛在AssetStore中添加的資源啦,我們把資源包下載并導(dǎo)入我們的工程即可。
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

注:你得先創(chuàng)建一個(gè)空工程,然后再導(dǎo)入資源包。我之前寫過《學(xué)Unity的貓》系列教程,其中第三章有講創(chuàng)建工程的步驟,
《【學(xué)Unity的貓】——第三章:第一個(gè)Unity工程,你好喵星人》)

2、Low Poly FPS Pack資源運(yùn)行效果

Low Poly FPS Pack資源包中已經(jīng)幫我們做好了一個(gè)簡單的第一人稱FPS游戲Demo,我們打開Assault_Rifle_01_Demo場景,如下
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
運(yùn)行,測試效果如下
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
如你所見,經(jīng)典的PC平臺(tái)FPS射擊游戲玩法,使用WASD控制移動(dòng),使用鼠標(biāo)來控制鏡頭角度,單擊鼠標(biāo)左鍵開槍。
接下來,我們要給它做下手術(shù),改成 搖桿按鈕 控制。

3、制作UI界面
3.1、UI素材獲取

搖桿圖片簡單處理,用一個(gè)圓就可以了,然后我們還需要一些按鈕圖標(biāo),比如開槍、丟手雷、跳躍、裝子彈等,這里推薦我平時(shí)經(jīng)常用的一個(gè)查找圖標(biāo)資源的網(wǎng)站,阿里圖標(biāo)庫:https://www.iconfont.cn/
比如我搜關(guān)鍵字:槍,就可以看到槍的圖標(biāo)啦~
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
可以直接免費(fèi)下載,而且還可以事先修改圖片顏色,建議改成白色,這樣方便在Unity中設(shè)置其他顏色,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
根據(jù)你自身的需要下載一些圖標(biāo)資源,我下載的圖標(biāo)如下,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
注意,因?yàn)槲覀円?code>UGUI中顯示這些圖標(biāo),需要將它們的Texture Type設(shè)置為Sprite (2D and UI),如下
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

3.2、創(chuàng)建UI攝像機(jī):UICamera

建議UI的顯示使用一個(gè)單獨(dú)的攝像機(jī)來渲染,我們?cè)趫鼍爸袆?chuàng)建一個(gè)Camera,重命名為UICamera,

注:創(chuàng)建攝像機(jī)的操作步驟:在Hierarchy視圖中鼠標(biāo)右鍵,然后點(diǎn)擊菜單Camera即可。

【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
設(shè)置攝像機(jī)的Clear FlagsDepth only,設(shè)置Culling Mask只渲染UI層,設(shè)置ProjectionOrthographic(正交模式),設(shè)置Depth1(確保UI攝像機(jī)的比3D攝像機(jī)后渲染),
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

3.3、創(chuàng)建UI畫布:Canvas

接下來,我們?cè)?code>Hierarchy視圖中鼠標(biāo)右鍵,點(diǎn)擊菜單UI / Canvas,創(chuàng)建一個(gè)Canvas,【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
設(shè)置一下參數(shù),如下,目的是讓UICamera來渲染Canvas的內(nèi)容,并設(shè)置分辨率適配規(guī)則,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

3.4、創(chuàng)建Panel:GamePanel

我們?cè)?code>Canvas子節(jié)點(diǎn)下創(chuàng)建一個(gè)Panel,重命名為GamePanel,并把Image組件禁用,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
下面我們?cè)僭?code>GamePanel下去創(chuàng)建UI對(duì)象。

3.5、制作搖桿

我們先做移動(dòng)控制的搖桿,在GamePanel子節(jié)點(diǎn)下創(chuàng)建一個(gè)Image,重命名為moveJointedArm,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
設(shè)置左下角對(duì)齊,并調(diào)整坐標(biāo)和尺寸,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
像這樣,它就是我們搖桿的檢測區(qū)域,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

我們把它的Image組件的顏色的Alpha通道設(shè)置為0,這樣我們就看不見它了,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
我們?cè)?code>moveJointedArm子節(jié)點(diǎn)下再創(chuàng)建兩個(gè)Image,分別命名為bgcenter
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
分別設(shè)置一下尺寸,圖片,顏色,如下
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
效果
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

同理,做一下右搖桿,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
效果
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

3.6、制作操作按鈕

除了移動(dòng)和旋轉(zhuǎn),我們還有開槍、丟手雷、跳躍、裝子彈的操作,配套需要制作對(duì)應(yīng)的按鈕。安排上,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
效果
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
到這里,我們的UI界面就基本做好啦,下面就是寫代碼的環(huán)節(jié)了~

4、搖桿控制腳本:JointedArm.cs

搖桿的邏輯實(shí)現(xiàn),我之前寫過一篇文章講過原理:《Unity使用ScrollRect制作搖桿(UGUI)》,這里我就不過對(duì)贅述,直接說下操作流程。

4.1、JointedArm.cs腳本代碼

創(chuàng)建一個(gè)C#腳本,重命名為JointedArm.cs,代碼如下:

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System;

// 搖桿邏輯
public class JointedArm : ScrollRect, IPointerDownHandler
{
    public Action<Vector2> onDragCb;
    public Action onStopCb;

    protected float mRadius = 0f;
    
    private Transform trans;
    private RectTransform bgTrans;
    private Camera uiCam;
    private Vector3 originalPos;

    protected override void Awake()
    {
        base.Awake();
        trans = transform;
        bgTrans = trans.Find("bg") as RectTransform;
        uiCam = GameObject.Find("UICamera").GetComponent<Camera>();
        originalPos = trans.localPosition;
    }

    void Update()
    {
        if (Input.GetMouseButtonUp(0))
        {
            //松手時(shí),搖桿復(fù)位
            trans.localPosition = originalPos;
            this.content.localPosition = Vector3.zero;
        }
    }

    protected override void Start()
    {
        base.Start();
        //計(jì)算搖桿塊的半徑
        mRadius = bgTrans.sizeDelta.x * 0.5f;
    }

    public override void OnDrag(PointerEventData eventData)
    {
        base.OnDrag(eventData);
        var contentPostion = this.content.anchoredPosition;
        if (contentPostion.magnitude > mRadius)
        {
            contentPostion = contentPostion.normalized * mRadius;
            SetContentAnchoredPosition(contentPostion);
        }
        //Debug.Log("搖桿滑動(dòng),方向:" + contentPostion);

        if(null != onDragCb)
            onDragCb(contentPostion);
    }

    public override void OnEndDrag(PointerEventData eventData)
    {
        base.OnEndDrag(eventData);
        //Debug.Log("搖桿拖動(dòng)結(jié)束");
        if (null != onStopCb)
            onStopCb();
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        //點(diǎn)擊到搖桿的區(qū)域,搖桿移動(dòng)到點(diǎn)擊的位置
        trans.position = uiCam.ScreenToWorldPoint(eventData.position);
        trans.localPosition = new Vector3(trans.localPosition.x, trans.localPosition.y, 0);
    }
}
4.2、掛搖桿腳本,設(shè)置成員對(duì)象

moveJointedArm節(jié)點(diǎn)掛JointedArm腳本,并設(shè)置Contentcenter節(jié)點(diǎn),如下,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
同理設(shè)置右搖桿rotateJointedArm。到此,我們的搖桿就有交互效果了,如下
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

5、關(guān)聯(lián)UI交互事件
5.1、定義UI成員:GamePanel.cs

我們創(chuàng)建一個(gè)GamePanel.cs腳本,聲明UI對(duì)象,如下

using UnityEngine;

public class GamePanel : MonoBehaviour
{
 	/// <summary>
    /// 移動(dòng)搖桿
    /// </summary>
    public JointedArm moveJointedArm;
    /// <summary>
    /// 旋轉(zhuǎn)搖桿
    /// </summary>
    public JointedArm rotateJointedArm;
    /// <summary>
    /// 開槍按鈕
    /// </summary>
    public GameObject fireBtn;
    /// <summary>
    /// 丟手雷按鈕
    /// </summary>
    public GameObject bombBtn;
    /// <summary>
    /// 跳躍按鈕
    /// </summary>
    public GameObject jumpBtn;
    /// <summary>
    /// 裝子彈按鈕
    /// </summary>
    public GameObject bulletBtn;
	
	void Start()
	{
		// TODO 關(guān)聯(lián)UI交互事件
	}
}
5.2、設(shè)置UI對(duì)象

把它掛到GamePanel節(jié)點(diǎn)上,并設(shè)置變量對(duì)象,如下
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

5.3、設(shè)置搖桿委托

Start函數(shù)中添加搖桿的委托,如下

// GamePanel.cs

void Start()
{
   // 移動(dòng)控制搖桿
    moveJointedArm.onDragCb = (direction) =>
    {
        // TODO 拋出事件
    };
    moveJointedArm.onStopCb = () =>
    {
        // TODO 拋出事件
    };
    
    // 旋轉(zhuǎn)控制搖桿
    rotateJointedArm.onDragCb = (direction) =>
    {
        // TODO 拋出事件
    };
    rotateJointedArm.onStopCb = () =>
    {
        // TODO 拋出事件
    };

	// ...
}

我們要拋出一些事件,這里要封裝一個(gè)事件管理器。

6、事件管理:訂閱、注銷、拋出
6.1、封裝事件管理器:EventDispatcher.cs

我在之前的多篇文章中都有到和用到事件管理器,歡迎閱讀我之前寫的這些文章,里面都有用到事件管理器,
《【游戲開發(fā)框架】自制Unity通用游戲框架UnityXFramework,詳細(xì)教程(Unity3D技能樹 | tolua | 框架 | 熱更新)》
《【游戲開發(fā)創(chuàng)新】用Unity等比例制作廣州地鐵,廣州加油,早日戰(zhàn)勝疫情(Unity | 地鐵地圖 | 第三人稱視角)》
《【游戲開發(fā)實(shí)戰(zhàn)】使用Unity 2019制作仿微信小游戲飛機(jī)大戰(zhàn)(二):搭建基礎(chǔ)游戲框架》
《【游戲開發(fā)實(shí)戰(zhàn)】使用Unity制作水果消消樂游戲教程(三):水果拖動(dòng)與交換邏輯》
《【游戲開發(fā)實(shí)戰(zhàn)】使用Unity制作像天天酷跑一樣的跑酷游戲——第七篇:游戲界面的基礎(chǔ)UI》
《【學(xué)Unity的貓】第十二章:使用Unity制作背包,皮皮的夢(mèng)想背包》
EventDispatcher腳本代碼:

using UnityEngine;
using System.Collections.Generic;

public delegate void MyEventHandler(params object[] objs);

/// <summary>
/// 游戲事件管理器
/// </summary>
public class EventDispatcher
{
    /// <summary>
    /// 注冊(cè)事件
    /// </summary>
    /// <param name="evt">事件名</param>
    /// <param name="handler">響應(yīng)函數(shù)</param>
    public void Regist(string evt, MyEventHandler handler)
    {
        if (handler == null)
            return;

        if (listeners.ContainsKey(evt))
        {
            //這里涉及到Dispath過程中反注冊(cè)問題,必須使用listeners[type]+=..
            listeners[evt] += handler;
        }
        else
        {
            listeners.Add(evt, handler);
        }
    }

    /// <summary>
    /// 注銷事件
    /// </summary>
    /// <param name="evt">事件名</param>
    /// <param name="handler">響應(yīng)函數(shù)</param>
    public void UnRegist(string evt, MyEventHandler handler)
    {
        if (handler == null)
            return;

        if (listeners.ContainsKey(evt))
        {
            //這里涉及到Dispath過程中反注冊(cè)問題,必須使用listeners[type]-=..
            listeners[evt] -= handler;
            if (listeners[evt] == null)
            {
                //已經(jīng)沒有監(jiān)聽者了,移除.
                listeners.Remove(evt);
            }
        }
    }

    /// <summary>
    /// 拋出事件
    /// </summary>
    /// <param name="evt">事件名</param>
    /// <param name="objs">參數(shù)</param>
    public void DispatchEvent(string evt, params object[] objs)
    {
        try
        {
            if (listeners.ContainsKey(evt))
            {
                MyEventHandler handler = listeners[evt];
                if (handler != null)
                    handler(objs);
            }
        }
        catch (System.Exception ex)
        {
            Debug.LogErrorFormat(szErrorMessage, evt, ex.Message, ex.StackTrace);
        }
    }


    public void ClearEvents(string key)
    {
        if (listeners.ContainsKey(key))
        {
            listeners.Remove(key);
        }
    }

    private Dictionary<string, MyEventHandler> listeners = new Dictionary<string, MyEventHandler>();
    private readonly string szErrorMessage = "DispatchEvent Error, Event:{0}, Error:{1}, {2}";

    private static EventDispatcher s_instance;
    public static EventDispatcher instance
    {
        get
        {
            if (null == s_instance)
                s_instance = new EventDispatcher();
            return s_instance;
        }
    }
}
6.2、定義事件名:EventNameDef.cs

我們?cè)賱?chuàng)建一個(gè)EventNameDef.cs腳本,用于定義事件名,如下

/// <summary>
/// 事件名定義
/// </summary>
public class EventNameDef 
{
    /// <summary>
    /// 移動(dòng)
    /// </summary>
    public const string MOVE = "MOVE";
    /// <summary>
    /// 旋轉(zhuǎn)
    /// </summary>
    public const string ROTATE = "ROTATE";
    /// <summary>
    /// 開槍
    /// </summary>
    public const string FIRE = "FIRE";
    /// <summary>
    /// 丟手榴彈
    /// </summary>
    public const string BOMB = "BOMB";
    /// <summary>
    /// 跳躍
    /// </summary>
    public const string JUMP = "JUMP";
    /// <summary>
    /// 裝子彈
    /// </summary>
    public const string BULLET = "BULLET";
}
6.3、拋出事件

我們回到GamePanel.cs腳本,在搖桿的委托中拋出事件,

// GamePanel.cs

void Start()
{
     // 移動(dòng)控制搖桿
     moveJointedArm.onDragCb = (direction) =>
     {
         EventDispatcher.instance.DispatchEvent(EventNameDef.MOVE, new Vector3(direction.x, 0, direction.y).normalized, true);
     };
     moveJointedArm.onStopCb = () =>
     {
         EventDispatcher.instance.DispatchEvent(EventNameDef.MOVE, Vector3.zero, false);
     };
     // 旋轉(zhuǎn)控制搖桿
     rotateJointedArm.onDragCb = (direction) =>
     {
         EventDispatcher.instance.DispatchEvent(EventNameDef.ROTATE, new Vector3(direction.x, 0, direction.y).normalized);
     };
     rotateJointedArm.onStopCb = () =>
     {
         EventDispatcher.instance.DispatchEvent(EventNameDef.ROTATE, Vector3.zero);
     };
     
     // ...
}
6.4、訂閱事件和注銷事件

搖桿拋出的事件,最終的響應(yīng)邏輯就是角色移動(dòng)和旋轉(zhuǎn),那么我們就要在原來控制角色移動(dòng)和旋轉(zhuǎn)的腳本中添加事件訂閱。
邏輯在哪里呢?邏輯在FPSControllerLPFP.cs腳本和AutomaticGunScriptLPFP.cs腳本中。
畫個(gè)圖,方便大家理解,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

我們分別在FPSControllerLPFP.cs腳本和AutomaticGunScriptLPFP.cs腳本中添加事件訂閱和注銷,如下

// FPSControllerLPFP.cs

private void Start()
{
	// ...
	// 訂閱事件
	EventDispatcher.instance.Regist(EventNameDef.MOVE, OnEventMove);
    EventDispatcher.instance.Regist(EventNameDef.ROTATE, OnEventRotate);
    // ...
}

private void OnDestroy()
{
	// 注銷事件
    EventDispatcher.instance.UnRegist(EventNameDef.MOVE, OnEventMove);
    EventDispatcher.instance.UnRegist(EventNameDef.ROTATE, OnEventRotate);
    // ...
}
// AutomaticGunScriptLPFP.cs

private void Start()
{
	// ...
	// 訂閱事件
    EventDispatcher.instance.Regist(EventNameDef.MOVE, OnEventMove);
	// ...
}

private void OnDestroy()
{
	// 注銷事件
    EventDispatcher.instance.UnRegist(EventNameDef.MOVE, OnEventMove);
	// ...
}
7、移動(dòng)控制
7.1、流程

流程如下,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

7.2、代碼實(shí)現(xiàn)

搖桿通過MOVE事件傳遞了移動(dòng)方向過來,我們?cè)?code>FPSControllerLPFP.cs腳本中把它緩存到m_moveDirection變量中,如下

// FPSControllerLPFP.cs

Vector3 _moveDirection;
private void OnEventMove(params object[] args)
{
   	_moveDirection = (Vector3)args[0];
}

FixedUpdate函數(shù)中執(zhí)行MoveCharacter方法,在MoveCharacter方法中根據(jù)m_moveDirection去計(jì)算移動(dòng),邏輯如下,(部分函數(shù)此處沒有列出,可下載工程源碼進(jìn)行查看)

// FPSControllerLPFP.cs 

/// <summary>
/// 移動(dòng)角色
/// </summary>
private void MoveCharacter()
{
    // 轉(zhuǎn)為世界坐標(biāo)系下的方向
    var worldDirection = transform.TransformDirection(_moveDirection);
    // 移動(dòng)速度
    var velocity = worldDirection * (input.Run ? runningSpeed : walkingSpeed);
    // 檢查碰撞,以便角色在跳墻時(shí)不會(huì)卡住
    var intersectsWall = CheckCollisionsWithWalls(velocity);
    if (intersectsWall)
    {
        _velocityX.Current = _velocityZ.Current = 0f;
        return;
    }
    // 平滑運(yùn)算
    var smoothX = _velocityX.Update(velocity.x, movementSmoothness);
    var smoothZ = _velocityZ.Update(velocity.z, movementSmoothness);
    // 獲取當(dāng)前剛體速度
    var rigidbodyVelocity = _rigidbody.velocity;
    // 計(jì)算速度差
    var force = new Vector3(smoothX - rigidbodyVelocity.x, 0f, smoothZ - rigidbodyVelocity.z);
    // 給剛體施加一個(gè)力
    _rigidbody.AddForce(force, ForceMode.VelocityChange);
}

移動(dòng)的同時(shí),還需要播放走路動(dòng)畫,邏輯在AutomaticGunScriptLPFP.cs腳本中,

// AutomaticGunScriptLPFP.cs

private Animator anim;
private bool isWalking;

private void OnEventMove(params object[] args)
{
    isWalking = (bool)args[1];
}

private void Update()
{
	// ...
	if (isWalking && !isRunning)
	{
	   anim.SetBool("Walk", true);
	}
	else
	{
	   anim.SetBool("Walk", false);
	}
	// ...
}
7.3、運(yùn)行效果

此時(shí)效果
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

8、旋轉(zhuǎn)控制
8.1、流程

同理,旋轉(zhuǎn)控制也是通過事件的響應(yīng)函數(shù)來觸發(fā),流程如下,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

8.2、代碼實(shí)現(xiàn)
// FpsControllerLPFP.cs

/// <summary>
/// 旋轉(zhuǎn)角色
/// </summary>
private void RotateCameraAndCharacter()
{
    // 平滑運(yùn)算
    var rotationX = _rotationX.Update(RotationXRaw, rotationSmoothness);
    var rotationY = _rotationY.Update(RotationYRaw, rotationSmoothness);
    // 限制豎直方向的旋轉(zhuǎn)角度:
    var clampedY = RestrictVerticalRotation(rotationY);
    _rotationY.Current = clampedY;
    // 將世界坐標(biāo)系下的up方向轉(zhuǎn)為相對(duì)手臂的局部坐標(biāo)系下的方向
    var worldUp = arms.InverseTransformDirection(Vector3.up);
    // 計(jì)算最終角度(四元數(shù))
    var rotation = arms.rotation *
                   Quaternion.AngleAxis(rotationX, worldUp) *
                   Quaternion.AngleAxis(clampedY, Vector3.left);
    // 父節(jié)點(diǎn)只沿著y軸旋轉(zhuǎn),容易漏掉此步,如果沒有此步,計(jì)算移動(dòng)的時(shí)候會(huì)出問題
    transform.eulerAngles = new Vector3(0f, rotation.eulerAngles.y, 0f);
    // 手臂自由旋轉(zhuǎn)
    arms.rotation = rotation;
}
8.3、運(yùn)行效果

此時(shí)效果
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

9、開槍控制
9.1、流程

【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

9.2、封裝EventTrigger,監(jiān)聽長按事件

因?yàn)殚_槍是一個(gè)連續(xù)過程,我們要檢測是否長按了開槍按鈕,而UGUIButtononClick只能監(jiān)聽點(diǎn)擊事件,所以我們需要另外實(shí)現(xiàn)長按事件的監(jiān)聽。
UnityEngine.EventSystems命名空間下有個(gè)EventTrigger類,它基本提供了所有UI事件,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
我們封裝一個(gè)EventTriggerListener.cs,繼承EventTrigger,如下,

using UnityEngine;
using UnityEngine.EventSystems;

/// <summary>
/// UI事件觸發(fā)器
/// </summary>
public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger
{
    public delegate void VoidDelegate(GameObject go);
    public delegate void BoolDelegate(GameObject go, bool state);
    public delegate void FloatDelegate(GameObject go, float delta);
    public delegate void VectorDelegate(GameObject go, Vector2 delta);
    public delegate void ObjectDelegate(GameObject go, GameObject obj);
    public delegate void KeyCodeDelegate(GameObject go, KeyCode key);

    public VoidDelegate onClick;
    public VoidDelegate onDown;
    public VoidDelegate onEnter;
    public VoidDelegate onExit;
    public VoidDelegate onUp;
    public VoidDelegate onSelect;
    public VoidDelegate onUpdateSelect;

    static public EventTriggerListener Get(GameObject go)
    {
        EventTriggerListener listener = go.GetComponent<EventTriggerListener>();
        if (listener == null) listener = go.AddComponent<EventTriggerListener>();
        return listener;
    }

    static public EventTriggerListener Get(Transform transform)
    {
        EventTriggerListener listener = transform.GetComponent<EventTriggerListener>();
        if (listener == null) listener = transform.gameObject.AddComponent<EventTriggerListener>();
        return listener;
    }
    public override void OnPointerClick(PointerEventData eventData)
    {
        if (onClick != null) onClick(gameObject);
    }
    public override void OnPointerDown(PointerEventData eventData)
    {
        if (onDown != null) onDown(gameObject);
    }
    public override void OnPointerEnter(PointerEventData eventData)
    {
        if (onEnter != null) onEnter(gameObject);
    }
    public override void OnPointerExit(PointerEventData eventData)
    {
        if (onExit != null) onExit(gameObject);
    }
    public override void OnPointerUp(PointerEventData eventData)
    {
        if (onUp != null) onUp(gameObject);
    }
    public override void OnSelect(BaseEventData eventData)
    {
        if (onSelect != null) onSelect(gameObject);
    }
    public override void OnUpdateSelected(BaseEventData eventData)
    {
        if (onUpdateSelect != null) onUpdateSelect(gameObject);
    }
}
9.3、開槍按鈕,長按與抬起事件

GamePanel.cs中添加按鈕長按onDown和按鈕抬起onUp的監(jiān)聽并拋出FIRE事件,如下

// GamePanel.cs

// 開炮
void Start()
{
	// ...
    EventTriggerListener.Get(fireBtn).onDown += (btn) =>
    {
        EventDispatcher.instance.DispatchEvent(EventNameDef.FIRE, true);
    };
    EventTriggerListener.Get(fireBtn).onUp += (btn) =>
    {
        EventDispatcher.instance.DispatchEvent(EventNameDef.FIRE, false);
    };
    // ...
}
9.4、響應(yīng)FIRE事件

開槍的邏輯在AutomaticGunScriptLPFP.cs腳本中,流程如下

// AutomaticGunScriptLPFP.cs

bool _fire;
private void OnEventFire(params object[] args)
{
    _fire = (bool)args[0];
}

private void Update()
{
	// ...
	if (_fire && !outOfAmmo && !isReloading && !isInspecting && !isRunning)
    {
        if (Time.time - lastFired > 1 / fireRate)
        {
            lastFired = Time.time;
            // 執(zhí)行開槍
            DoFire();
        }
    }
	// ...
}

void DoFire()
{
	// 以下具體代碼見工程代碼,此處不展開了
	
	// 播放開槍音效
	// 播放開炮動(dòng)畫
	// 播放槍口粒子
	// 實(shí)例化子彈并給子彈一個(gè)力
	// 實(shí)例化彈殼
}
9.5、運(yùn)行效果

此時(shí)效果,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

10、丟手雷、跳躍、裝子彈

同理,通過事件訂閱觸發(fā)丟手雷、跳躍、裝子彈等邏輯。

10.1、丟手雷

【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

10.2、跳躍

【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

10.3、裝子彈

【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

11、加個(gè)彩蛋,同學(xué)你上電視了

給這位提問的同學(xué)一次上電視的機(jī)會(huì),我把他貼到墻上,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
初始的時(shí)候圖片半透明,角色靠近的時(shí)候圖片完全不透明,用到的是觸發(fā)器,
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)
關(guān)于觸發(fā)器的教程,我之前寫過一些文章,《【學(xué)Unity的貓】第十章:Unity的物理碰撞,流浪喵星計(jì)劃》
這里的檢測邏輯如下,

using UnityEngine;
using UnityEngine.UI;

public class TipsBoard : MonoBehaviour
{
    public Image board;

    private void Start() {
         board.color = new Color(1, 1, 1, 0.3f);
    }

    private void OnTriggerEnter(Collider other)
    {
        if ("Player" != other.tag) return;
        board.color = new Color(1, 1, 1, 1);
    }

    private void OnTriggerExit(Collider other)
    {
        if ("Player" != other.tag) return;
        board.color = new Color(1, 1, 1, 0.3f);
    }
}

四、工程源碼

本文工程源碼我已上傳到CODE CHINA,感興趣的同學(xué)可自行下載學(xué)習(xí),
地址:https://codechina.csdn.net/linxinfa/FirstPersonGame
注:我使用的Unity版本是2021.1.7f1c1,如果你使用的版本與我的不同,可能會(huì)有一些兼容問題。
【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)

五、完畢

好啦,就到這里吧~
我是林新發(fā):https://blog.csdn.net/linxinfa
原創(chuàng)不易,若轉(zhuǎn)載請(qǐng)注明出處,感謝大家~
喜歡我的可以點(diǎn)贊、關(guān)注、收藏,如果有什么技術(shù)上的疑問,歡迎留言或私信~文章來源地址http://www.zghlxwxcb.cn/news/detail-404460.html

到了這里,關(guān)于【游戲開發(fā)實(shí)戰(zhàn)】Unity手游第一人稱視角,雙搖桿控制,F(xiàn)PS射擊游戲Demo(教程 | 含Demo工程源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Unity 第一人稱視角控制移動(dòng)、旋轉(zhuǎn)

    Unity 第一人稱視角控制移動(dòng)、旋轉(zhuǎn)

    第一人稱視角操作 此功能主要是借鑒YouTube上一個(gè)博主的教程,寫的蠻好我就搬運(yùn)過來讓大家也試試。 其原理是:左右旋轉(zhuǎn)是控制父物體的歐拉角的Y軸 上下點(diǎn)頭是子物體相機(jī)的歐拉角Z軸 水平方向 跳躍: 移動(dòng)

    2024年04月27日
    瀏覽(27)
  • Unity使用NaveMesh實(shí)現(xiàn)第一人稱視角移動(dòng)

    Unity使用NaveMesh實(shí)現(xiàn)第一人稱視角移動(dòng)

    Navemesh尋路系列文章 文章目錄 目錄 系列文章目錄 文章目錄 前言 一、NavMeshPath是什么? 二、使用步驟 1.引入庫 2.讀入數(shù)據(jù) 總結(jié) navemesh已經(jīng)大量使用到游戲中,但大部分尋路都是使用SetDestination函數(shù),給予一個(gè)目標(biāo)點(diǎn)移動(dòng),第一人稱直接操控移動(dòng)的文章很少。 為了解決這個(gè)問

    2024年02月03日
    瀏覽(22)
  • Unity例子——第一人稱視角的角色控制器

    Unity例子——第一人稱視角的角色控制器

    本文是為了前文Unity四元組的舉例示范,為了讓讀者更好地理解。 效果是實(shí)現(xiàn)一個(gè)可以由鼠標(biāo)進(jìn)行方向操作,鍵盤進(jìn)行移動(dòng)操作的任務(wù)。 此為效果視頻: 1687597097844 下面進(jìn)行教學(xué): 新建一個(gè)場景,放置一個(gè)plane作為地板,尺寸自定 創(chuàng)建一個(gè)新的material掛在plane上 再地板上放置

    2024年02月10日
    瀏覽(31)
  • Unity3D中實(shí)現(xiàn)人物的第一人稱視角

    Unity3D中實(shí)現(xiàn)人物的第一人稱視角

    打開unity創(chuàng)建一個(gè)場景地圖可以添加一個(gè)Plane作為地面 在Hierarchy視圖中右鍵創(chuàng)建一個(gè)膠囊體(Capsule)作為Player,添加好后重置膠囊體的位置,并且調(diào)整膠囊體在一個(gè)合適的位置。 將Main Camera拖拽到到player內(nèi)作為子對(duì)象,重置一下Main Camera的transform,并且再調(diào)整一下它在player中

    2024年02月11日
    瀏覽(93)
  • Unity3D中實(shí)現(xiàn)Player的第一人稱視角

    Unity3D中實(shí)現(xiàn)Player的第一人稱視角

    效果,上面為Scene場景,下面為Game場景 0創(chuàng)建地形,當(dāng)然可以先簡單的創(chuàng)建一個(gè)空白的Terrain。這里我已經(jīng)對(duì)地形進(jìn)行了初步的編輯和渲染。 1.在Hierarchy視圖中右鍵創(chuàng)建一個(gè)膠囊體(Capsule)作為Player,添加好后重置膠囊體的位置,并且調(diào)整膠囊體在一個(gè)合適的位置。 ?2.將Main

    2023年04月08日
    瀏覽(30)
  • 【0到1學(xué)習(xí)Unity腳本編程】第一人稱視角的角色控制器

    【0到1學(xué)習(xí)Unity腳本編程】第一人稱視角的角色控制器

    ?????個(gè)人主頁 :@元宇宙-秩沅 ????? hallo 歡迎 點(diǎn)贊?? 收藏? 留言?? 加關(guān)注?! ????? 本文由 秩沅 原創(chuàng) ????? 收錄于專欄 :【0到1】Unity腳本游戲開發(fā)寶典 將攝像機(jī)變?yōu)槟z囊體的子物體,按住 ctrl +shift +F 調(diào)整視野。讓他變成膠囊體的眼睛 判斷要前進(jìn)時(shí)按照哪個(gè)

    2024年02月05日
    瀏覽(24)
  • Unity3D實(shí)現(xiàn)第一人稱移動(dòng),隨鼠標(biāo)轉(zhuǎn)動(dòng)視角+上樓梯(C#)

    Unity3D實(shí)現(xiàn)第一人稱移動(dòng),隨鼠標(biāo)轉(zhuǎn)動(dòng)視角+上樓梯(C#)

    第一人稱移動(dòng): 1、在層級(jí)面板創(chuàng)建一個(gè)Capsule,命名為Player,將層級(jí)面板中的相機(jī)拖到Player下方 2、重置Player和攝像機(jī)的Transform數(shù)值(方便調(diào)整攝像機(jī)在Player上的位置),然后調(diào)整攝像機(jī)在Player上的位置 大概將攝像機(jī)放到Player眼睛的位置即可。 3、創(chuàng)建一個(gè)腳本,命名為Came

    2024年02月13日
    瀏覽(60)
  • Unity游戲源碼分享-Unity手游射擊橫版游戲

    Unity游戲源碼分享-Unity手游射擊橫版游戲

    Unity游戲源碼分享-Unity手游射擊橫版游戲 ? 戰(zhàn)斗場景 項(xiàng)目地址: https://download.csdn.net/download/Highning0007/88050256

    2024年02月16日
    瀏覽(29)
  • Unity-第一人稱射箭游戲

    Unity-第一人稱射箭游戲

    歡迎來到我們開發(fā)的第一人稱射箭游戲!本游戲的設(shè)計(jì)目標(biāo)是提供一種真實(shí)而又有趣的射箭體驗(yàn)。玩家可以在美麗的自然場景中自由移動(dòng),嘗試不同的射箭技巧,挑戰(zhàn)靜態(tài)和動(dòng)態(tài)的靶標(biāo),以獲取高分。我們靈感來源于對(duì)射箭運(yùn)動(dòng)的熱愛,希望通過這個(gè)游戲,讓玩家感受到駑弓

    2024年02月03日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包