[Unity Script] 偵測滑鼠是否碰觸遊戲畫面邊緣 Detect If Mouse on Edge of Screen

[Unity Script] 偵測滑鼠是否碰觸遊戲畫面邊緣 Detect If Mouse on Edge of Screen

此腳本是使用傳統 Input Manager 實作,可以取得滑鼠於螢幕邊緣的狀態,可回傳上、下、左、右、上左、上右、下左與下右,如果滑鼠於非邊緣而在畫面中則回傳未知狀態 (Unknown)。

The script was created with legacy Input Manager. It can simply get your mouse state when it is on edge of the screen. The “GetMouseEdgeState” method can return Top, Down, Left, Right, Top Left, Top Right, Down Left, and Down Right state. It also returns an unknown state when the mouse is over the game window.

public enum MouseEdgeState
{
    Unknown,
    Left, Right, Top, Down,
    TopLeft, TopRight,
    DownLeft, DownRight
}
private MouseEdgeState GetMouseEdgeState()
{
    var mouseX = Mathf.RoundToInt(Input.mousePosition.x);
    var mouseY = Mathf.RoundToInt(Input.mousePosition.y);
    if (mouseX >= Screen.width)
    {
        if (mouseY >= Screen.height)
        {
            return MouseEdgeState.TopRight;
        }
        else if (mouseY <= 0)
        {
            return MouseEdgeState.DownRight;
        }
        else
        {
            return MouseEdgeState.Right;
        }
    }
    else if (mouseX <= 0)
    {
        if (mouseY >= Screen.height)
        {
            return MouseEdgeState.TopLeft;
        }
        else if (mouseY <= 0)
        {
            return MouseEdgeState.DownLeft;
        }
        else
        {
            return MouseEdgeState.Left;
        }
    }
    else
    {
        if (mouseY >= Screen.height)
        {
            return MouseEdgeState.Top;
        }
        else if (mouseY <= 0)
        {
            return MouseEdgeState.Down;
        }
        else
        {
            return MouseEdgeState.Unknown;
        }
    }
}

Unity 骨架控制器「Animation Rigging」手部骨架基礎操作

想要在 Unity 裡控制 3D 模型的骨架,除了最知名的「Final IK」付費套件可以用外,如果你的 Unity 引擎版本在 2020 版以上,也可以來嘗試看看官方支援的「Animation Rigging」。

在這篇內容中我僅能介紹基礎的用法,因為我對於 3D 模型相關的知識目前處於入門等級,尚在學習中。


前情提要

  • 模型必須先綁好骨架並蒙皮。
  • 建議先在主流 3D 建模軟體中完成動畫設計,再由 Animation Rigging 進行動態控制。

套件資訊


套件安裝

Animation Rigging 已經是正式版套件,可以直接透過 Package Manager 進行安裝。


模型配置

一、匯入模型,我在 Mixamo 中找了一個動畫附帶模型作為操作範例,此模型已帶有骨架與動畫。

二、將模型拉入場景,為物件新增 Animator 組件和 Animator Controller,並將模型自帶的動畫拉入控制器中並設為預設。

三、顯示骨架,先選中場景上的人物模型,從頂部選單執行 Bone Renderer Setup。

四、模型將會被新增一個 Bone Renderer 組件以渲染人物骨架,可透過調整 Bone Size 與 Color 來使骨架清楚顯示。


建立手部控制器

一、先選中人物模型,只不過這次要執行的是 Rig Setup,這將會新增 Rig Builder 組件與一個子物件 Rig1。

二、在 Rig1 下建立一個空物件,先給他新增一個「Two Bone IK Constraint」,再將模型骨架中的手部物件拖入 Tip 欄位,最後在組件的標題上滑鼠右鍵選單執行 Auto Setup from Tip Transform,其他的組件欄位將會自動設置完畢,也會多出 target 和 hint 兩個子物件。

三、這邊產生的 LeftHand_target 物件就是我們的手部骨架控制器,但現在他的座標還是在 (0, 0, 0),需要進行對齊。請按著鍵盤 Ctrl,先選 LeftHand_target 後再選手部骨架,再透過頂部選單進行 Align Transform 對齊。

四、現在的 LeftHand_target 已經與手部骨架對齊,接下來選中他,並點選場景中 Animation Rigging 浮動視窗中的 + 按鈕以建立可視的控制器。

五、可調整 Shape、Size、Rotation 等屬性以使控制器符合模型現況。

六、接下來讓 LeftHand_hint 也做一樣的對齊、加 Effector 動作,但是這個物件放置的座標要注意一下,因為人的手肘是往後彎曲的,要將他放在手的後面。

LeftHand_hint 是拿來讓 Unity 判斷控制器移動時骨架要彎曲的方向,這個物件是可選的,當然我們也可刪掉 LeftHand_hint,讓 Unity 自行判斷。

LeftHand_hint 物件位置對於彎曲行為的影響:

https://tedliou.com/wp-content/uploads/2022/03/2022-03-25-23-58-11-1.mp4

完成。

https://tedliou.com/wp-content/uploads/2022/03/2022-03-26-00-00-30-1.mp4

Unity 假彈道製作「二次方貝茲曲線」原理與語法

想要在 Unity 中讓物體進行拋物線運動,平常的我可能會直接用 Rigidbody 來施加力,讓系統自己去運算物理的大小事。但有時候我只是要做個「看起來」是拋物線運動的效果,沒有必要弄到非常真實,就可以套個曲線公式來施作。

原理

我們最常看到的貝茲曲線是只有一個原點、一個終點與一個控制點的「二次方貝茲曲線」,你可以透過移動控制點來修改曲線。在推導「二次方貝茲曲線」前,必須先了解「線性貝茲曲線」,它等同於我們常用的線性插值。

線性貝茲曲線

線性貝茲曲線等同線性差值,我們現在已知 A 與 B 的座標位置,也假定總共移動所需的時間 t 為 1,t 介於 0~1,可以直接想像成此次移動的完成百分比 (0~100%)。

t 代表時間,A 和 B 分別代表原點與終點,C 就是結果。

先以簡單的一維空間來解釋…

假設 A = 0、B = 10,求 t = 0.2 時 C 點的位置。這時就可以用 A~B 的距離乘 t 來表示 C 的位置:

但是這個假設是建立在原點 = 0 的情況,所以正確的式子是:

用分配律整理一下,這就是「線性貝茲曲線」的公式:

接下來帶入剛才假設的數值,得 C = 2:

二次方貝茲曲線

進入主題,二次方貝茲曲線是由三條線性貝茲曲線組合出來的產物,以下方影片為例,我們將使用到

  1. 先定義由左到右的座標分別為 A、B、C 點。
  2. 分別計算 A~B 與 B~C 上的點於指定 t 的時候所在的座標,可得出的 D、E 兩個座標點。
  3. 將 D 與 E 帶入公式最後得出我們要的 F 座標:

https://tedliou.com/wp-content/uploads/2022/03/movie_002.mp4

能用三個線性貝茲曲線算出座標後,是時候將他整理成一個公式…

首先是剛才計算 AB、 BC 線段上的 D、E 座標式子:

還有最終的 F 座標式子:

將 D 和 E 帶入 F 座標的式子:

整理後可得以下公式,t 介於 0~1 之間:


二次方貝茲曲線公式


語法

Unity 中的次方可使用 Mathf.Pow 來實現,最後的 Bt 座標就是指定時間點 t 的貝茲曲線座標。

public Transform P0, P1, P2, Bt;

private void Start()
{
    var t = 0.5f;
    var p0 = P0.position;
    var p1 = P1.position;
    var p2 = P2.position;
    Bt.position = Mathf.Pow(1 - t, 2) * p0 + 2 * t * (1 - t) * p1 + Mathf.Pow(t, 2) * p2;
}

也可以放到 Update 中並給予時間與線段特效,以下影片為例:

https://tedliou.com/wp-content/uploads/2022/03/movie_003-1.mp4

完整腳本:

using UnityEngine;

public class BezierCalculator : MonoBehaviour
{
    public int Duration = 5;
    public Transform P0, P1, P2, Bt;

    private float _time;
    private float _duration;

    private void Update()
    {
        if (_duration > Duration)
        {
            _duration = 0;
        }

        var t = _duration / Duration;
        Bt.position =
            Mathf.Pow(1 - t, 2) * P0.position +
            2 * t * (1 - t) * P1.position +
            Mathf.Pow(t, 2) * P2.position;

        _duration += Time.deltaTime;
    }
}

Unity 以任意角度取圓周上座標之原理與語法

因為要在 Unity 上做一個能在圓周上隨機生成物件的功能,回去研究了一下關於圓與角度的數學。

原理

一、我們會先定義好圓心和半徑,這邊的圓心為 (0, 0)、C = 半徑、θ 為角度,可繪製出以下圖形:

(B, A) 就是我們要求的座標。

二、帶入三角函數公式,其實這就是邊的比例。


先取 座標,我們已知 C = 半徑,為了拿到 B 值,要用 C 乘

已知 等於 ,所以等同

去分母後就是 B 值。


座標同理,只不過改成 C 乘

一樣去分母…


語法

知道為什麼需要乘 後,接下來就是用腳本來實現他。

一、定義圓心與半徑。

var center = new Vector3(0, 0, 0);
var radius = 3;

二、計算弧度,因為 Unity 自帶的 Mathf.Cos 和 Mathf.Sin 只能輸入弧度並非角度,所以需要事先進行換算。( = 弧度、 = 角度)

以 20 度為例:

var rad = 20 * Mathf.PI / 180;

三、計算 XY 座標,如圓心不在 (0, 0) 時需要加上圓心座標。

var x = center.x + radius * Mathf.Cos(rad);
var y = center.y + radius * Mathf.Sin(rad);

四、最後加入物件生成後會像這樣,指定於角度 20 度座標位置生成一個 Ball 物件:

public GameObject Ball;

private void Start()
{
    var center = new Vector3(0, 0, 0);
    var radius = 3;
    var rad = 20 * Mathf.PI / 180;
    var x = center.x + radius * Mathf.Cos(rad);
    var y = center.y + radius * Mathf.Sin(rad);
    Ball.transform.position = new Vector3(x, y, center.z);
    Instantiate(Ball);
}

Unity 預覽,紅點為圓心,白點為生成的 Ball。

五、實際運用方面,我們可以用迴圈達成「在圓周上每 20 度生成一個物件」的目的。

public GameObject Ball;

private void Start()
{
    var center = new Vector3(0, 0, 0);
    var radius = 3;
    for (int i = 0; i < 360; i += 20)
    {
        var rad = i * Mathf.PI / 180;
        var x = center.x + radius * Mathf.Cos(rad);
        var y = center.y + radius * Mathf.Sin(rad);
        Ball.transform.position = new Vector3(x, y, center.z);
        Instantiate(Ball);
    }
}

輸出結果

Unity 免 Build 多人連線測試套件「ParrelSync」安裝與使用

「ParrelSync」套件可快速達成 Unity 專案同步雙開的目的,以快速進行多人遊戲連線測試作業。


套件資訊


安裝與使用

一、從 套件 Github 中取得 Unitypackage 後直接開啟匯入。

二、從上方工具列開啟 Clones Manager (ParrelSync/Clones Manager)。

三、點擊 Create new clone 並等待專案複製完成。

四、點擊 Open in New Editor 啟動剛才複製的專案。

五、等待複製的專案啟動完成後,兩邊的專案內容將完全一致,且當你變更原專案的內容時,複製的專案將會自動完成同步,在多人遊戲開發中即可進行快速測試。

可以從 Clones Manager 中點擊 View Folder 來開啟複製的專案資料夾,你會發現其中 Assets 與 ProjectSettings 目錄是一個類似捷徑的東西。

舉例說明,當原專案場景變更時,滑鼠點開複製的專案時就會要求進行場景 Reload,重載後即完成同步。

另外 ParrelSync 有加入防呆機制,你不可以直接變更複製的專案的內容,在嘗試存檔時會自動阻擋,請一律在原專案中進行內容修改。

[Unity] 開啟 Enter Play Mode Options,減少進入播放模式等待時間

Unity 編輯器預設會在你按下 Play 按鈕後,將場景與腳本進行重新載入,以確保所有物件與屬性資料皆為預設值,例如執行時間定義的靜態變數。

而這個重新載入的時間會因為場景與腳本的複雜度影響而延長,長久下來會占了很大一部份的開發時間,我想大多數開發者應該都有遇過卡在 Application.EnterPlayMode 很長一段時間的經驗。

這個 Enter Play Mode Options 設定就是為了解決這個問題而存在,當你勾選後,之後按下播放時,編輯器就不會重載場景和腳本,而是直接執行無需等待。但出現的副作用就是前一次執行時定義的靜態變數 (包含事件) 都不會被撤銷,所以要記得在 Start 或 Awake 時將這些變數全部設定回預設值


Enter Play Mode Options 選項開關實測影片:


Enter Play Mode Options 設定位置在 Edit > Project Settings 的 Editor 中,其中還有 Reload Domain 與 Reload Scene 兩個設定可選,分別是開啟重載腳本與場景,可視目前專案開發情況進行選擇。


參考資料

解決 Dissonance 於 Quest 2 平台麥克風無作動問題

Dissonance (全名:Dissonance Voice Chat) 是一個運作於 Unity Engine 的線上多人語音系統插件,他本身沒有多人連線功能,而是依附於常見的 UNET、Photon、Mirror、Steamworks.NET 或最新的 Netcode 多人連線架構,讓多人遊戲可同時擁有語音聊天功能。這支插件原價 75 美金,如非急需的話可在特殊節日或黑五等特價日以 35 美元或更低的價格購入。


插件資訊


Dissonance 配置完成後,在 PC 端啟動後可以直接運作,但在 Quest 2 上卻沒有任何反應 (可聽不可說),因為 Quest 2 的作業系統是 Android。現在的 Android 為保障安全性,對於「權限」的使用鎖得很緊,何況是能作為監聽使用的麥克風。

照理說 Unity Engine 應該要在編譯時偵測到 Dissonance 有使用到麥克風時,自動在 APK 中加入麥克風權限的需求。但目前的狀況是,在用 Quest 2 啟動程式時,並不會有任何的權限同意視窗供你選擇,導致此硬體不會有任何作動。

為解決此問題,我們就需要在遊戲啟動時 (可放在 Splash 或登入場景) 讓他執行一個腳本來請求權限,可使用 Unity Engine 的 Application.HasUserAuthorization 與 Application.RequestUserAuthorization 來實作。

using System.Collections;
using System.Linq;
using UnityEngine;

public class DissonanceMicrophoneChecker : MonoBehaviour
{
    private IEnumerator Start()
    {
        // 檢查是否有麥克風權限,否則提出權限請求
        if (!Application.HasUserAuthorization(UserAuthorization.Microphone))
        {
            yield return Application.RequestUserAuthorization(UserAuthorization.Microphone);
        }

        // 再次檢查,如仍然無權限則將遊戲關閉
        if (Application.HasUserAuthorization(UserAuthorization.Microphone))
        {
            Debug.Log("Device: " + Microphone.devices.Select(x => x.ToString()));
        }
        else
        {
            Application.Quit();
        }
    }
}

把這支腳本掛在遊戲啟動後的第一個場景中,在執行程式時就可以看到允許權限的視窗,點選允許後 Dissonance 的語音系統將能正常作動。

[Unity] 於 Runtime 中重建 RectTransform,解決 ContentSizeFitter 尺寸計算錯誤問題

Unity 有一個 UI 組件稱為「ContentSizeFitter」,他可以自動偵測子容器的文字、圖片等元素尺寸,並自動調整成與之相符的大小。但他有個問題,當我們以巢狀的方式或搭配 Layout Group 來使用時,他常會發生大小計算錯誤問題。

如下圖,左圖為原始問題,右圖為解決後。

前面說的巢狀 ContentSizeFitter 就是下圖,容易造成計算錯誤問題。

重點來了,這個問題的解法是利用 LayoutRebuilder.ForceRebuildLayoutImmediate 這支方法,他能強制系統重新計算目標 RectTransform 的大小。但畢竟是強制重繪,他鐵定吃效能的,所以請慎用 🤔

如果你是少量介面要重繪的話,請不用猶豫直接用這個方法,趕快解決掉。只有那種數萬筆資料的要謹慎考慮作法,但一般遊戲應該不太會有這種問題就是了。

此範例以透過父物件以迴圈查找的方式來做更新:

if (_contentSizeFitter == null) _contentSizeFitter = GetComponentsInChildren<ContentSizeFitter>();
foreach (var e in _contentSizeFitter)
{
    LayoutRebuilder.ForceRebuildLayoutImmediate(e.GetComponent<RectTransform>());
}

參考資料

[Unity] Addressable v1.16.19 常用語法整理

沒意外 Addressable 將會成為開發 Unity 遊戲的必備技能,尤其是有在做手機 APP 開發的程式人。為了防止自己忘記寫法,只要有空檔就會來更新這篇 Addressable 語法筆記。

基本觀念

命名空間

using UnityEngine.AddressableAssets;

工作流程

1. 下載資源

在使用資源前,必定要先用 LoadAsset(s)Async 系列的語法來讓他進行下載。這個工作是非同步進行的,後面會有範例程式碼。

2. 調用資源

完成下載後即可直接調用,如果沒有先下載的話系統會出錯。

資源 Key

在載入資源時都會用到 Key,這個東西其實就是 Addressable Name 和 Label。而因為 Key 可以重複指定 (用於一次下載大量資料),所以在包資源時要注意名稱不要有衝突。

LoadAssetAsync

沒有 s 的是下載單筆資源,寫法有用協程 (Coroutine)、 Async 和 Event 三種:

Coroutine

private IEnumerator LoadCubeAsset () {
    var cube = Addressables.LoadAssetAsync<GameObject>("Cube");
    yield return cube;
    Instantiate(cube.Result);
}

Async

private async void LoadCubeAssetAsync () {
    var cube = Addressables.LoadAssetAsync<GameObject>("Cube");
    await cube.Task;
    Instantiate(cube.Result);
}

Event

private void LoadCubeAssetEvent () {
    Addressables.LoadAssetAsync<GameObject>("Cube").Completed += x => Instantiate(x.Result);
}

LoadAssetsAsync

下載多筆資源。第二個參數是一個 Action<T>,在下載完成一筆資料時會調用,但不保證順序。

Addressables.LoadAssetsAsync<GameObject>("Cube", cubes.Add);

也可給他多筆 Key:

Addressables.LoadAssetsAsync<GameObject>(new string[] { "Cube", "Profile" }, cubes.Add);

範例 (Async 寫法):

var cubes = new List<GameObject>();
var asyncWork = Addressables.LoadAssetsAsync<GameObject>("Cube", cubes.Add);
await asyncWork.Task;

foreach (var e in cubes)
{
    Debug.Log(e.name);
}

LoadSceneAsync

場景也可以放到 Addressable 中,如果場景中存在已包好的物件,會自動全部下載,一樣要用非同步載入。

await Addressables.LoadSceneAsync("Combat", LoadSceneMode.Additive).Task;

AssetReference

AssetReference 要在 Inspector 中指派,預設是沒有限定型別,但他有 AssetReferenceGameObject、AssetReferenceTexture 等變種,通常會用 AssetReferenceT<T> 來自己設定。

public AssetReference allType;
public AssetReferenceGameObject gameObj;
public AssetReferenceTexture texture;
public AssetReferenceT<TextAsset> textAsset;

範例 (Async 寫法):

await gameObj.LoadAssetAsync<GameObject>().Task;
gameObj.InstantiateAsync().Completed += x => {
    x.Result.AddComponent<BoxCollider>();
};

[Unity] Facebook v11.0 手機登入與伺服器端驗證實作教學

在設計會員制的手機遊戲時,弄一個社群登入是一個能方便玩家快速進入遊戲核心的一個方法,可以省下註冊 Key 資料的時間。

今天我要帶給各位的是 Facebook 最新的 v11 SDK 手機會員登入與伺服器端驗證的實作教學,如果你沒有伺服器需求的話可以只做完手機會員登入,那其他人就跟著我一步一步來完成它。

事前安裝

待會我們要開始將 Facebook SDK 匯入專案,匯入後他要建立一串 Key Hash 給 API 用,而因為這東西會動到 OpenSSL,所以我們必須先將它安裝好。

安裝後我們要手動設定環境變數,設定好變數後必須重開電腦,就是這原因我才會把這段寫在最前面。

OpenSSL For Windows:https://slproweb.com/products/Win32OpenSSL.html

這個版本的 OpenSSL 套件有分為 32/64 位元與 普通/Light 版本,對於一般用途,選用 64 位元 Light 版本就夠用,也就是下載安裝「Win64 OpenSSL v1.1.1L Light」。

開新專案

啟動 Unity HUB,開一個新專案。因為在這裡我們只會動到 UI,所以使用 2020.3.15 的 2D 樣板。

專案建立完成後,開啟 Build Settings,將 Platform 切換為 Android。切換完成後點擊左下角的 Player Settings… 開啟設定視窗。

展開 Other Settings,勾選 Override Default Package Name 後將 Package Name 改成你要的名稱。這步驟先做好,後面匯入 SDK 時就只要等待一次系統配置的時間。

匯入 Facebook SDK

到 Facebook 開發者文件中下載給 Unity 用的 Package,下載解壓縮後能得到一支名為 facebook-unity-sdk-11.0.0.unitypackage 的檔案。

Facebook SDK for Unity:https://developers.facebook.com/docs/unity

直接將 SDK 全部匯入 Unity。

如果有跳出 API Update Required 提示,選擇 I Made a Backup, Go Ahead!。

SDK 成功匯入後,Editor 將自動啟動 Resolving Android Dependencies 工作,等他跑完且顯示 Library processing complete 即可關掉它。

前面先改好 Package Name 就是為了讓他別再多跑一次這個工作,時間寶貴。

設定 Facebook 串接資料

從頂部選單的 Facebook > Edit Settings 開啟 Facebook Settings 內容。

現在我們應該要看到的狀況應該是:

  1. 有 Invalid App Id 錯誤警告。
  2. Android Build Facebook Settings 中無任何錯誤訊息。

如有其他狀況則需要一些手段來解決,有人遇到再來補充。

接下來要開始進行 Facebook 那邊的設定,現在請啟動你慣用網頁瀏覽器。

建立應用程式

前往 Facebook 所有應用程式網頁,點擊新增應用程式按鈕,開始進行設定。

Facebook 所有應用程式:https://developers.facebook.com/apps/

應用程式類型選擇「遊戲」。

輸入應用程式名稱後完成建立流程。

切換為上線模式

應用程式建立後預設模式為「調整中」,如需要切換成「上線」則要完成 隱私政策網址用戶資料刪除子類別 欄位的填入。

設定的位置在左側的 設定 > 基本資料。

儲存後,點擊應用程式類型旁的「調整中」,將它切換為上線模式。

填入 Facebook App Id

剛才設定基本資料的網頁中有個「應用程式編號」,將它複製貼上到前面打開的 Facebook Settings 的 Facebook App Id 欄位。

Invalid App Id 錯誤警告將消失。另外我們馬上要使用到 Android Build Facebook Settings 中的 Package Name、Class Name 與 Debug Android Key Hash 資料。

新增平台串接資訊

回到剛才的基本設定網頁,滑到最下面點擊「+ 新增平台」按鈕。

平台選擇「Android」。

Android Store 選擇「Google Play」。

最後你會得到一個新的空表單,這時請依序填入前面提到的 Package Name、Class Name 與 Debug Android Key Hash 三筆資料。

在填入套件名稱時會顯示 There was a problem verifying this package name. Please check and try again. 錯誤訊息,這是 BUG,全部填完後直接存檔就好,不用理他。

感動吧!基礎設定都完成了,接下來將要開始寫程式。

建立 SDK 控制腳本

我們先完成客戶端的 Facebook 登入功能後再來管伺服器資料驗證,基本上多為 Copy & Past 的作業。

首先建立一個名為 FacebookController 的腳本,再將 Facebook 官方提供的初始化腳本複製貼上。就是填入下面附的這個連結中的 Initialize the SDK 的 Code。

Unity SDK Example:https://developers.facebook.com/docs/unity/examples

最後看起來會長這樣,直接複製貼上我的也行:

建立登入按鈕功能

這邊一樣是 Copy & Past 的工作。首先在 FacebookController 類別下新增一個公開方法,可取名為 OnLoginBtnClick,再將官方範例中的 Facebook Login 段落的前兩行 Code 放進去。

這邊再貼一次文檔連結:

Unity SDK Example:https://developers.facebook.com/docs/unity/examples

完成按鈕的方法後,再將官方範例剩下的 Code 貼在 OnLoginBtnClick 下面。

到這裡,客戶端登入的程式碼就撰寫完成,我們先來弄個簡單的登入按鈕。

在場景中新增一個 Canvas 與 Button,將 FacebookController 拉進去後設定點擊事件觸發 OnLoginBtnClick。這邊的是很基礎的操作,就不細講。

設定完後來做個客戶端登入的測試。

測試客戶端登入功能

在 Editor 播放,並按下登入按鈕後他會彈出這個模擬登入的介面。這東西是讓你能在 Editor 中快速測試的功能,免得每次都要等待編譯 APK 的時間。

他的用法很簡單,流程如下:

  1. 點擊 Find Access Token 開啟網頁,登入帳號並取得 Token。
  2. 將 Token 複製貼上至 User Access Token 欄位。
  3. 按下 Send Success 按鈕後成功登入。

第一次來要 Token 時,User Token 欄位會有個「需要提供權限」的連結,點開後他會帶你到圖形 API 測試工具網頁。

先確認一下「Facebook 應用程式」與「用戶或粉絲專頁」的值是否與下圖類似,是的話就放心點擊 Generate Access Token 按鈕。

完成資料授權。

將取得的 Token 複製下來。

最後將 Token 貼上到 Unity 後按下 Send Success,就可以完成帳號登入並在 Console 中找到你的使用者 ID。

剛才的存取權杖工具在完成這一次的資料授權後,以後開啟網頁後會直接顯示 Token,就不用再開啟圖形 API 測試工具。

到這裡已經完成客戶端登入的功能。如果你想,也可以在這邊就先 Build 一版到手機裡,理論上是可以正常調用 Facebook API 並成功登入。

那麼接下來即將要實作並整合現有客戶端登入的「伺服器端驗證」功能,這邊將使用 XAMPP 來建一個簡易網頁伺服器,並搭配 PHP 來進行後端處理。XAMPP 的安裝將直接略過,請自行完成安裝後再進行下一步驟。

建立伺服器端驗證程式

先啟動 XAMPP 的 Apache 伺服器,並在 C:\xampp\htdocs 下新增一個 login.php 檔案,將以下程式碼複製貼上。

簡單解釋一下,這支 PHP 會先偵測說你用 POST 傳入的 Token 是否存在,存在的話就會把他丟給 Facebook 伺服器來取得這個 Token 代表的真實帳戶 ID 和名稱。

中間的 graph.fb.gg 這串所對應的 API 可以在先前我們有用過的圖形 API 測試工具中取得,點擊「取得代碼」按鈕可以拿到幾種程式語言的語法,你可以自行嘗試各種不同的 API 用法。

圖形 API 測試工具:https://developers.facebook.com/tools/explorer/

剛才這隻 PHP Script 最終會把從 Facebook 伺服器取得的帳戶 ID 與名稱直接 Print 出來,這時伺服器就可以拿帳戶 ID 來向資料庫那邊做撈資料等作業。但這一塊現在也直接略過 (不是重點),我們就直接將 PHP Print 出來的資料顯示在 Unity 的 UI 中。

新增手機登入後發送與接收資料功能

回到 Unity,先 using 兩項命名空間:

再將以下程式碼複製貼上到 FacebookController 下:

這段程式碼就是一個基礎的發送 POST 至 login.php 的功能並顯示到 Text UI 上,基礎功能就不多做贅述。(IP 記得要改成你伺服器的)

最後完成的結果如下圖,登入成功後在 Text UI 上就會顯示「我的伺服器」從「Facebook 伺服器」上抓到的帳戶資料。

最後的完整 FacebookController.cs 長這樣,七八成都是複製貼上來著:

參考資料

Unity Recorder 擷取透明去背的 UI 畫面設定方法

最近遇到需要提供現有的 UI 畫面給美術做角色設計,必須去掉背景和部分人物,也就是要去背。

應該沒人去做螢幕擷圖後 PS 去背的傻事吧?想要在編輯器中擷圖,我們可以用 Unity Recorder 這個 Package,他能輸出完美尺寸的圖片。只不過要用他來擷取透明背景的 UI 的方法比較少人知道,所以就寫這篇來記錄一下。


首先將 Unity Recorder 安裝到你的專案裡,在 2020 版中此套件已經是正式版。

接下來從頂部選單 Window > General > Recorder > Recorder Window 啟動介面。

這邊要做一小連串的操作,我們用編號列出來:

  1. 按下左邊 + Add Recorder 新增一個 Image Sequence。
  2. 修改右側內容:
    1. 將 Source 從 Game View 改成 Targeted Camera。
    2. 將 Camera 從 Main Camera 改成 Active Camera。
    3. 勾選 Include UI。
    4. 修改 Media File Format 從 JPEG 改成 PNG。
    5. 勾選 Include Alpha。
  3. 修改頂部內容:
    1. 修改 Recording Mode 從 Manual 改成 Single Frame。
    2. 修改 Target Frame 改成你要的目標幀,一般就用 1。
  4. 按下 START RECORDING 完成擷圖。

右側欄的 Output File 有寫擷圖後輸出的位置,到目標位置取圖即可。

備註:有勾選 Include UI 後,貌似將 Camera 改回 Main Camera 一樣可以成功擷取 UI。

[Unity] 以 Interface 介面搜尋場景上所有物件

有在 Unity 用過 Interface 介面的工程師們應該都知道 GetComponent<介面名稱>; 的用法,但卻沒辦法用 FindObjectsByType<介面名稱> 來找物件。

而在 2014 年的 Unity 論壇中有人提出的 How can I find all objects that have a script that implements a certain interface? 討論串中有人以 LINQ 實作出用介面找物件的功能。

但為了要能更方便使用,我將它重寫成擴充功能,但這個目前沒研究出來能直接在 MonoBehaviour 中使用的辦法,所以就先讓它依附在 GameObject 之下。

編寫邏輯

先新開一個腳本,儲存以下程式碼:

簡單來說就是,因為我們不能直接搜尋 Interface,所以就往更上層的 MonoBehaviour 搜尋,再往下去找有指定介面的物件,感覺就超吃效能,慎用。

用法如下,它會回傳一個 List。

使用範例

IReady 是我自己寫的介面,裡面有個 Ready() 函數。上面先以 iReady 儲存它用 FindInterfacesOfType 找出來的物件 List,再透過 foreach 呼叫 Ready()。

切記,別把這個玩意兒塞在 Update 中讓它瘋狂執行,Find 與 LINQ 系列的程式碼都很吃效能的!

Exit mobile version