當你想要在CSO LUA中建立更多元的UI物件時,官方僅提供了UI.Box和UI.Text兩個選項。但是,如果你希望有更多自定義的UI物件,你可以透過手刻Class物件來實現。這樣一來,你就能夠根據自己的需求來客製化UI物件了!

Lua 中的物件導向

Lua 是一種輕量級的語言,沒有內建的 class 概念,但可以通過其他方式模擬類似的行為,例如使用表(table)和元表(metatable)來實現對象導向的編程。如果對此不太熟悉,可以參考一些線上資源,比如這個網站

文字陰影 UI 物件

假設我們要創建一個自定義的文字陰影 UI 物件。首先,讓我們看一下如果不使用 class 的話,程式碼會是怎麼樣的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TextShadow = UI.Text.Create()
TextShadow:Set({
text = "哈囉", font = "small", align = "left",
x = 2, --<< 偏移2點
y = 2, --<< 偏移2點
width = 100,
height = 30,
r = 255, g = 255, b = 255
})

Text = UI.Text.Create()
Text:Set({
text = "哈囉", font = "small", align = "left",
x = 0,
y = 0,
width = 100,
height = 30,
r = 255, g = 255, b = 255
})

這樣的程式碼看起來相當冗長且不易維護。現在,讓我們看看如何使用 class 來實現同樣的功能。

定義 TextShadow Class

  1. TextShadow = {}:這一行創建了一個名為 TextShadow 的空表,用於存儲自定義物件的方法和屬性。
  2. function TextShadow:Create():這一行定義了一個叫做 Create 的方法,該方法用於創建新的 TextShadow 物件。使用 : 語法定義的方法隱式地將物件自身作為第一個參數(類似於其他語言中的 this 或 self)。
  3. Create 方法中:
  • 首先,創建了一個名為 newObject 的新表,用於存儲 TextShadow 物件的屬性和方法。
  • newObject 表中,設置了一個叫做 SetArg 的表,其中包含了一系列的屬性,用於設置陰影效果的參數。這些參數包括了文本內容 (text)、字體 (font)、對齊方式 (align),,位置(x 和 y),大小 (width 和 height),顏色 (r、g、b 和 a) 以及偏移量 (offset)。
  • 接著,創建了一個 UI 表,其中包含了兩個名為 backfront 的屬性,這些屬性分別表示陰影的背景和前景,並且使用了 UI.Text.Create() 方法來創建相應的文本 UI 物件。
  • 最後,設置了一個名為 visible 的屬性,表示該陰影是否可見,並將其設置為預設值 true

總的來說,這段程式碼創建了一個具有自定義屬性和方法的 TextShadow 物件,用於表示文本的陰影效果。通過這種方式,可以方便地創建。

來自 ChatGPT 說明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- 定義物件
TextShadow = {}

function TextShadow:Create()
-- 自訂義物件內容並給預設值,內容怎樣都行。
local newObject = {
SetArg = {
text = "",
font = "small",
align = "left",
x = 0,
y = 0,
width = 0,
height = 0,
r = 255, g = 255, b = 255, a = 255,
offset = 2
},
UI = {
back = UI.Text.Create(),
front = UI.Text.Create()
},
visible = true
}

return setmetatable(newObject, {__index = TextShadow})
end

上述程式碼定義了一個 TextShadow Class,其中包含了一個 Create 方法用於創建新的 TextShadow 物件。該物件包含了一個 SetArg 表,用於存儲設定參數,一個 UI 表用於存儲 UI 元件,以及一個 visible 屬性用於表示陰影是否可見。

更新 UI

接下來我們在定義一個Update函式,來更新我們的UI要怎麼設定。

  1. function TextShadow:Update():這一行定義了一個叫做 Update 的方法,該方法用於更新 TextShadow 物件的 UI。
  2. local arg = self.SetArg:這一行將 self.SetArg 表示的陰影設置參數儲存在本地變數 arg 中,以便於後續使用。
  3. local setting = {...}:這一行創建了一個名為 setting 的表,其中包含了陰影效果的設定。對於每個 UI 元素(back 和 front),設置了相應的位置(x 和 y)、顏色(r、g、b 和 a)等參數。
  4. for k,v in pairs(self.UI) do:這一行使用 pairs 函數遍歷 self.UI 表中的所有元素,其中 k 是鍵(back 或 front),而 v 則是相應的值(UI.Text 物件)。
  5. 在迴圈中,創建了一個名為 temp 的表,用於存儲更新後的 UI 參數。這些參數包括了位置 (x 和 y),大小 (width 和 height),顏色 (r、g、b 和 a),以及文本相關的屬性(text、font、align)。
  6. v:Set(temp):這一行調用了 UI.Text 物件的 Set 方法,並將更新後的參數 temp 傳遞給該方法,從而更新了 UI 的屬性。

總的來說,這段程式碼是用來更新 TextShadow 物件的 UI,並根據設置的參數來更新相應的屬性,例如位置、大小、顏色等。這樣一來,可以在程式執行過程中動態地改變陰影效果的外觀。

來自 ChatGPT 說明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- 更新UI
function TextShadow:Update()
local arg = self.SetArg
local setting = {
back = {x = arg.offset, y = arg.offset, r = 0, g = 0, b = 0, a = arg.a},
front = {x = 0, y = 0, r = arg.r, g = arg.g, b = arg.b, a = arg.a}
}

for k,v in pairs(self.UI) do
local temp = {
text = arg.text,
font = arg.font,
align = arg.align,

x = arg.x + setting[k].x,
y = arg.y + setting[k].y,
width = arg.width,
height = arg.height,

r = setting[k].r,
g = setting[k].g,
b = setting[k].b,
a = setting[k].a
}
v:Set(temp)
end
end

上述程式碼定義了一個 Update 方法,用於更新 TextShadow 物件的 UI。該方法根據設定參數更新 UI 的各個屬性,包括位置、大小、顏色等。

其他必需的函式

  1. function TextShadow:Set(args):這一行定義了一個名為 Set 的方法,該方法用於設置陰影效果的屬性。首先,它檢查傳入的參數是否為一個表,如果是的話,則調用 setArgs 函數將該表中的值設置到 self.SetArg 中。最後,它調用了 self:Update() 方法來更新 UI。
  2. function TextShadow:Get():這一行定義了一個名為 Get 的方法,該方法用於取得陰影效果目前的設置值。它調用了 clone 函數來複製 self.SetArg 表,以防止直接返回引用。
  3. function TextShadow:Show():這一行定義了一個名為 Show 的方法,該方法用於顯示陰影效果的 UI。它調用了 deepCall 函數來遞迴地調用 UI 表中每個元素的 Show 方法,以顯示相應的 UI。最後,將 self.visible 設置為 true,表示陰影效果已經顯示。
  4. function TextShadow:Hide():這一行定義了一個名為 Hide 的方法,該方法用於隱藏陰影效果的 UI。它同樣調用了 deepCall 函數來遞迴地調用 UI 表中每個元素的 Hide 方法,以隱藏相應的 UI。最後,將 self.visible 設置為 false,表示陰影效果已經隱藏。
  5. function TextShadow:IsVisible():這一行定義了一個名為 IsVisible 的方法,該方法用於返回陰影效果是否可見的狀態。它簡單地返回 self.visible 的值,以表示陰影效果目前是否處於顯示狀態。

總的來說,這些方法為 TextShadow 物件提供了設置、取得、顯示和隱藏陰影效果的功能,並提供了一個方法來查詢陰影效果目前是否可見。

來自 ChatGPT 說明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
-- 設置
function TextShadow:Set(args)
if type(args) == "table" then
setArgs(self.SetArg, args)
end
self:Update()
end

-- 取得設定值
function TextShadow:Get()
return clone(self.SetArg)
end

-- 顯示
function TextShadow:Show()
deepCall(self.UI, "Show")
self.visible = true
end

-- 隱藏
function TextShadow:Hide()
deepCall(self.UI, "Hide")
self.visible = false
end

-- 返回顯示狀態
function TextShadow:IsVisible()
return self.visible
end

上述程式碼定義了一些必需的函式,包括設置、取得設定值、顯示、隱藏和返回顯示狀態等功能。這些函式使得 TextShadow 物件更加易用和靈活。

輔助函式

  1. local function setArgs(data, args):這是一個局部函數,用於更新表中的值。它接受兩個參數,data 表示待更新的表,args 表示包含新值的表。該函數通過遍歷 data 表中的每個鍵,檢查是否存在相應的 args 表中的值,如果是的話,則將 data 表中的值更新為 args 表中的對應值。如果鍵對應的值是一個表,則遞迴調用 setArgs 函數以處理嵌套的表。
  2. local function deepCall(table, funcName, args):這是一個局部函數,用於在表中深層遞迴地調用指定的函式。它接受三個參數,table 表示待遍歷的表,funcName 表示要調用的函式名稱,args 表示要傳遞給該函式的參數。該函數遍歷 table 表中的每個元素,如果元素是一個表,則遞迴調用 deepCall 函數以處理嵌套的表;如果元素是一個 userdata,則調用該 userdata 對象的指定函式,並傳遞參數 args
  3. local function clone(table):這是一個局部函數,用於深層複製表。它接受一個表作為參數,並返回該表的深層複製。該函數遍歷原始表中的每個鍵值對,如果值是一個表,則遞迴調用自身以處理嵌套的表;否則,將鍵值對直接複製到新的表中。

這些輔助函數提供了對表的操作,使得程式碼更加模組化和易於理解。通過這些函數,可以更方便地處理複雜的數據結構和執行深層遞迴操作。

來自 ChatGPT 說明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
-- 更新設定值
local function setArgs(data, args)
for k in pairs(data) do
if type(data[k]) == type(args[k]) then
if type(data[k]) == "table" then
setArgs(data[k], args[k])
else
data[k] = args[k]
end
end
end
end

-- 深層調用,調用指定函式
local function deepCall(table, funcName, args)
for _,v in pairs(table) do
if type(v) == "table" then
deepCall(v, funcName, args)
elseif type(v) == "userdata" then
v[funcName](v, args)
end
end
end

-- 複製表(table)
local function clone(table)
local temp = {}
for k,v in pairs(table) do
if type(v) == "table" then
temp[k] = clone(v)
else
temp[k] = v
end
end
return temp
end

上述程式碼定義了三個輔助函式,分別是更新設定值的 setArgs、深層調用的 deepCall 和複製表的 clone。這些函式用於處理表的操作,使得程式碼更加模組化和易於理解。

完整代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
-- 更新設定值
local function setArgs(data, args)
for k in pairs(data) do
if type(data[k]) == type(args[k]) then
if type(data[k]) == "table" then
setArgs(data[k], args[k])
else
data[k] = args[k]
end
end
end
end

-- 深層調用,調用指定函式
local function deepCall(table, funcName, args)
for _,v in pairs(table) do
if type(v) == "table" then
deepCall(v, funcName, args)
elseif type(v) == "userdata" then
v[funcName](v, args)
end
end
end

-- 複製表(table)
local function clone(table)
local temp = {}
for k,v in pairs(table) do
if type(v) == "table" then
temp[k] = clone(v)
else
temp[k] = v
end
end
return temp
end

-- 定義物件
TextShadow = {}

function TextShadow:Create()
-- 自訂義物件內容並給預設值,內容怎樣都行。
local newObject = {
SetArg = {
text = "",
font = "small",
align = "left",
x = 0,
y = 0,
width = 0,
height = 0,
r = 255, g = 255, b = 255, a = 255,
offset = 2
},
UI = {
back = UI.Text.Create(),
front = UI.Text.Create()
},
visible = true
}

return setmetatable(newObject, {__index = TextShadow})
end


-- 更新UI
function TextShadow:Update()
local arg = self.SetArg
local setting = {
back = {x = arg.offset, y = arg.offset, r = 0, g = 0, b = 0, a = arg.a},
front = {x = 0, y = 0, r = arg.r, g = arg.g, b = arg.b, a = arg.a}
}

for k,v in pairs(self.UI) do
local temp = {
text = arg.text,
font = arg.font,
align = arg.align,

x = arg.x + setting[k].x,
y = arg.y + setting[k].y,
width = arg.width,
height = arg.height,

r = setting[k].r,
g = setting[k].g,
b = setting[k].b,
a = setting[k].a
}
v:Set(temp)
end
end

-- 設置
function TextShadow:Set(args)
if type(args) == "table" then
setArgs(self.SetArg, args)
end
self:Update()
end

-- 取得設定值
function TextShadow:Get()
return clone(self.SetArg)
end

-- 顯示
function TextShadow:Show()
deepCall(self.UI, "Show")
self.visible = true
end

-- 隱藏
function TextShadow:Hide()
deepCall(self.UI, "Hide")
self.visible = false
end

-- 返回顯示狀態
function TextShadow:IsVisible()
return self.visible
end


-- 測試
local screen = UI.ScreenSize()
local center = {x = screen.width / 2, y = screen.height / 2}

text = TextShadow:Create()
text:Set({
text = "哈囉 你好~",
font = "medium",
align = "center",
x = 0,
y = center.y,
width = screen.width,
height = 50,
r = 0, g = 128, b = 255,
offset = 5
})

上述是完整的程式碼範例,展示了如何使用 Class 物件來建立自定義的文字陰影 UI 物件。這樣的設計使得程式碼更加模組化和易於理解,同時也提供了更好的可擴展性和重用性。