1. 程式人生 > >Unity/UI —— 使用字元圖片自定義字型(Custom Font)

Unity/UI —— 使用字元圖片自定義字型(Custom Font)

前言

在Unity的UI設計中,我們經常會遇到需要自定義字型的情況。畢竟Unity自帶的字型只有Arial一種,根本無法滿足人民群眾對於美的嚮往。當然,全能的Unity支援我們匯入或建立字型,並可以在GUI Text和Text Mesh中使用。雖然可匯入字型給我們提供了更多選擇的餘地,但也可能遇到選擇的字型和遊戲整體不搭或者僅需少量特定字元的情況。這種時候Custom Font就為我們自定義字型提供了方便,而設計這樣一套字型其實只需要 一張 期望的圖片即可做到。

素材準備

和匯入的字型不同,Custom Font並不是通用的 .ttf/.otf 檔案,而是由使用者指定的包含特定字元的圖片生成的。以數字字型為例,我們的原始素材可以是下面這樣的一張圖片:

digit1

這裡字元圖片的選取還是有一定講究的,理想狀態下的字元圖應該滿足以下幾個條件:

  1. 圖片格式為PNG格式(這樣可以保證得到的圖片背景為透明,方便在Unity中進行處理)
  2. 圖片中字元顏色為白色(可選條件,如果沒有 改變字型顏色 的需求該條件可以忽略)
  3. 每個字元以透明背景分割,並且以整齊的間距排列(方便識別每個具體字元的位置)
  4. 每個字元的大小一致(保證得到的字型整齊並且方便初始化配置)

當然,上述四個條件均為可選條件,但儘量做到上述幾點可以讓你之後的工作節省大量的時間。如果找到的素材不理想,建議先通過Photoshop進行一些簡單的處理。

建立字型材質

當你經過第一步的處理獲得理想的素材之後,下一步就是使用該素材建立一個字型材質。之前也說過Custom Font和匯入字型的不同之處就在於它是由字元圖片生成的。而字型材質就是一種特殊的材質(Material),你可以把它看做是連結Custom Font和字元圖的紐帶。 它接受一張字元圖的紋理並可以被賦予給一個Custom Font,這也是我們之前強調字元圖只能有一張的原因。建立一個字型材質的過程非常簡單,在Project檢視中右鍵單擊 Create - Material

,然後將其使用的著色器改為 “GUI/Text Shader”即可。正常情況下Inspector視窗下你可以看到下面的樣子:

TextMaterial

直接將字元圖片拖拽到Texture位置即可獲得一個字型材質。我們同樣可以在Project檢視中右鍵單擊 Create - Custom Font 來建立一個自定義字型,然後將之前得到的字型材質拖到Custom Font屬性欄中的Material上就得到了一個Custom Font的雛形。顯示效果如下圖(根據Unity版本不同可能屬性會有些許改變):

digitFont

進行字元對映

當然,經過上述步驟你得到的Custom Font還沒有任何用處,因為它還沒有進行最重要也是最麻煩的一個步驟,那就是將ASCII碼與我們自定義的圖片對應起來。

ASCII碼,即America Standard Code for Information Interchange, 主要用於顯示現代英語和其他西歐語言。屬於Unity中Custom Font的預設編碼集。我們使用Custom Font自定義字型的原理不過是簡單地為我們需要的ASCII碼指定一張圖片,當使用該字型時,被指定了圖片的字元可以正常顯示,而未指定的字元或者不在ASCII編碼集中的字元則無法顯示,所以使用該方法定義數字或英文字母效果拔群,定義漢字字元貌似是不大行了。。。

首先選擇我們之前匯入的字元圖片,將它的Texture Type 改為 Sprite(2D and UI),Sprite Mode改為 Multiple,點選Apply儲存後我們就可以開啟 Sprite Editor 對字元圖進行編輯了。

Sprite Setting

關於紋理匯入(Texture Importer)詳細的相關配置問題,請參考Unity官方文件 Texture Importer

在Sprite Editor視窗下,點選左上角的Slice按鈕就可以對當前圖片進行切分了,Unity會自動根據透明的背景識別每個字圖片,即單個字元的圖片。當然,我們這裡的目的並不是使用這些被切分出來的字圖片,而是使用每個字圖片對應的引數來設定 Custom Font 中的 Character Rects 引數。

Sprite_Arguement

如上圖所示, 被圈出來的Position和 Border資訊對於我們之後指定該圖片每個字元的位置具有重要的作用。此時開啟我們之前建立的Custom Font 檔案,我們可以在引數一欄中找到 Character Rects 這一選項,這也是Custom Font識別每個字元的重要配置資訊。作為示範,我們可以先設定Character Rects 的Size為1,表示該字符集只包含一個字元(雖然一般不會有這種用法)。然而Unity並沒有我們想象的那麼高階,可以自動從圖片中找出我們想要的字元圖再對映到具體的ASCII碼上,所以我們可以看到Unity希望我們為這唯一一個字元(即Element0)設定的引數列表,而我們必須每個引數都認真地設定才能看到效果。

Element0_Setting

不過不用慌,通過下面這張表你就可以基本掌握它們的意思並且快速地設定完成

引數名 換算公式 引數含義
Index 當前字元的索引, 用於確認該字元圖對應的ASCII碼,換算關係為 Ascii Start Offset + Index = Ascii實際值
Uv 該字元對應於圖片中的哪個區域,四個引數取值範圍均為[0,1],表示相對範圍
Uv_X Position_X/Sprite_Width 字元圖的起始x座標
Uv_Y Postiion_Y/Sprite_Height 字元圖的起始y座標
Uv_W Position_W/Sprite_Width 字元圖的相對寬度
Uv_H Position_H/Sprite_Height 字元圖的相對高度
Vert 該字元對應於圖片中的哪個區域,引數取值為實際畫素值
Vert_X 一般為0 字元圖在相對位置(即Uv_X基礎上)的偏移, 以畫素為單位
Vert_Y 一般為0 字元圖在相對位置(即Uv_Y基礎上)的偏移, 以畫素為單位
Vert_W Position_W 字元圖的實際寬度, 以畫素為單位
Vert_H -Position_H 字元圖的實際高度, 以畫素為單位
Advanced(或Width) Position_W 字元圖的寬度

對照表格完成設定之後,在使用對應ASCII碼的字元時,Unity就可以幫助我們自動替換為圖片。以該圖片為例,我先在Sprite Editor中查詢字元圖“1”對應的位置資訊,然後將計算的結果填入Custom Font中的Element0中。因為數字“1”對應於ASCII碼中的49,所以我們可以直接設定index為49,並保持Ascii Start Offset為0;或者設定Ascii Start Offset為48,再將index設定為1。如果只設置數字的話,後一種方法顯然更加方便。

Vert_H必須設定為實際畫素的負值,這是因為Unity中圖片是從左上角繪製的,所以高度實際上是向下生長。

digit1_setting

正常情況下數字“1”的顯示效果如圖中所示:

digit1_display

Custom Font的缺點和不足

Custom Font雖然給了使用者自定義字型的能力,但比起常規的Dynamic Font還是有很多缺點的,例如:

  1. 無法定義中文字型。這點是由於Custom Font使用Ascii字符集導致的,Ascii字符集並不包含漢字。
  2. 無法通過Size改變字型大小。 就像上一節的演示圖一樣,數字“1”顯然比Text文字框的範圍還要高,這是因為Custom Font本身無法改變字元大小,不過依然可以通過Scale來變相調節
  3. 無法得到理想的字型顏色。 當改變Color,會在原圖片的基礎上變化,所以為了得到最好的顯示效果,最好保證 字型顏色是白色,背景為透明
    4. 無法換行。關於為何無法換行。。。這個問題我也不清楚,哪位大哥能夠解決這個問題請告訴我。可選的解決方案是使用多個文字框。

有熱心的程式猿同僚私信告訴我可以通過調節Line Spacing實現換行功能,特別感謝這位陌生的朋友能指正我的錯誤~~

下面是對第四點的補充,其實是可以通過修改Custom Font中的 Line Spacing 一項來解決該問題。親測有效,測試過程中有以下幾點需要注意:
1. 直接修改Custom Font中的 Line Spacing 是不會導致Text重繪的,所以在調節的時候無法觀察到Text發生變化,想要檢視修改效果必須對Text元件進行修改(例如修改文字內容)。
2. UGUI內部Text元件是使用屬性[ExecuteInEditMode]修飾的,使用該屬性(attribute)會導致即使遊戲未處於“播放”狀態指令碼也會執行,所以我們修改Text元件時,看到的內容也會實時更新。
3. 修改 Custom Font 的 Line Spacing 後,即使修改Scale也可以得到正常的效果。除此之外,還可以通過修改Text元件上的 Line Spacing 再次調整行間距。Text 元件上 Line Spacing 的計算單位就是Custom 中指定的 Line Spacing