# CSO LUA 小技巧
[toc]
## 玩家座標的使用
這可能是你的寫法,看起來沒毛病,但這會讓程式碼很攏長。
```lua=
x = {}
y = {}
z = {}
function Game.Rule:OnPlayerConnect(player)
x[player.index] = player.position.x
y[player.index] = player.position.y
z[player.index] = player.position.z
end
```
這是比較理想的寫法,一個變數直接儲存XYZ。
```lua=
playerPosition = {}
function Game.Rule:OnPlayerConnect(player)
playerPosition[player.index] = player.position
end
```
舉個例子,像是KZ的存讀點功能。
```lua=
playerPosition = {}
function Game.Rule:OnPlayerSignal(player, signal)
if signal == 1 then
-- 當玩家按下1,儲存座標
playerPosition[player.index] = player.position
elseif signal == 2 then
-- 當玩家按下2,讀取座標
player.position = playerPosition[player.index]
end
end
```
## 大量且重複性高的EntityBlock創建
這我很常用在KZ裡面的跳板,10個關卡,每一關可能有10個板子,那就要創建100個座標和函式。
```lua=
playerPosition = {}
block_1 = Game.EntityBlock.Create({x = 1, y = 1, z = 1})
function block_1:OnTouch(player)
playerPosition[player.index] = player.position
end
block_2 = Game.EntityBlock.Create({x = 2, y = 2, z = 2})
function block_2:OnTouch(player)
playerPosition[player.index] = player.position
end
block_3 = Game.EntityBlock.Create({x = 3, y = 3, z = 3})
function block_3:OnTouch(player)
playerPosition[player.index] = player.position
end
...無限循環
```
只要把座標全部都彙整進一個變數,利用迴圈來跑就不用再寫無意義的函式。
```lua=
blocks = {
{x = 1, y = 1, z = 1},
{x = 2, y = 2, z = 2},
{x = 3, y = 3, z = 3}
}
for k,v in pairs(blocks) do
local block = Game.EntityBlock.Create(v)
function block:OnTouch(player)
playerPosition[player.index] = player.position
end
end
```
## 動態玩家排名系統
直接利用Lua內建函式`table.sort`幫我們處立即可。
```lua
-- list: 欲排序的表(table)
-- comp: 自定義排序方式(function)
table.sort(list [, comp])
```
```lua=
playerRank = {
{player = player, time = 15}, -- 玩家一
{player = player, time = 17}, -- 玩家二
{player = player, time = 30}, -- 玩家三
{player = player, time = 10}, -- 玩家四
{player = player, time = 13}, -- 玩家五
}
-- comp: 自訂義排序,將表裡面的time屬性進行比較,時間快的排越前面。
function sort(a, b)
return a.time < b.time
end
-- 執行排序功能
table.sort(playerRank, sort)
--[[
結果:
playerRank = {玩家四, 玩家五, 玩家一, 玩家二, 玩家三}
]]
```
## 多個玩家的SyncValue優化
想要把Game多個玩家的資料傳送到UI,你可能會這麼做。
這也沒毛病,但如果寫到24人,實在是太攏長了。
```lua=
-- game.lua
InitialLevel = 1
sync_PlayerLevel_1 = Game.SyncValue.Create("sync_PlayerLevel.1")
sync_PlayerLevel_2 = Game.SyncValue.Create("sync_PlayerLevel.2")
sync_PlayerLevel_3 = Game.SyncValue.Create("sync_PlayerLevel.3")
function Game.Rule:OnPlayerConnect(player)
if player.index == 1 then
sync_PlayerLevel_1.value = InitialLevel
elseif player.index == 2 then
sync_PlayerLevel_2.value = InitialLevel
elseif player.index == 3 then
sync_PlayerLevel_3.value = InitialLevel
end
end
```
```lua=
-- ui.lua
sync_PlayerLevel_1 = UI.SyncValue.Create("sync_PlayerLevel.1")
function sync_PlayerLevel_1:OnSync()
-- do something
end
sync_PlayerLevel_2 = UI.SyncValue.Create("sync_PlayerLevel.2")
function sync_PlayerLevel_2:OnSync()
-- do something
end
sync_PlayerLevel_3 = UI.SyncValue.Create("sync_PlayerLevel.3")
function sync_PlayerLevel_3:OnSync()
-- do something
end
```
只要改成這樣,程式碼就會變得簡潔、易懂。
```lua=
-- game.lua
InitialLevel = 1
sync_PlayerLevel = {}
for i = 1, 24 do
sync_PlayerLevel[i] = Game.SyncValue.Create("sync_PlayerLevel." .. i)
end
function Game.Rule:OnPlayerConnect(player)
sync_PlayerLevel[player.index].value = InitialLevel
end
```
```lua=
-- ui.lua
sync_PlayerLevel = UI.SyncValue.Create("sync_PlayerLevel." .. UI.PlayerIndex())
function sync_PlayerLevel:OnSync()
-- do something
end
```
## 數字轉貨幣格式
> [來源](https://gist.github.com/Ivaar/a95d9e565bd9a0e2036179c0c8cdee58#file-currencies-lua-L18)
```lua=
function comma_value(n)
local left,num,right = string.match(n,'^([^%d]*%d)(%d*)(.-)$')
return left..(num:reverse():gsub('(%d%d%d)','%1,'):reverse())..right
end
print(comma_value(10000000)) -- 10,000,000
print(comma_value("10000000")) -- 10,000,000
print(comma_value(123456789)) -- 123,456,789
print(comma_value(1234567890)) -- 1,234,567,890
```
## 秒數轉換時間格式
這個可以轉換成: 小時:分鐘:秒 `00:00:00`
```lua=
function SecondsToTime(sec)
local hour = math.floor(sec / 3600)
local minute = math.floor(sec / 60) - (hour * 60)
local seconds = math.floor(sec % 60)
return string.format("%02d:%02d:%02d", hour, minute, seconds)
end
print(SecondsToTime(0)) -- 00:00:00
print(SecondsToTime(100)) -- 00:01:40
print(SecondsToTime(1280)) -- 00:21:20
print(SecondsToTime(3600)) -- 01:00:00
```
這個可以轉換成: 分鐘:秒.毫秒 `00:00.00`
```lua=
function SecondsToTime(sec)
local minute = math.floor(sec / 60)
local seconds = math.floor(sec % 60)
return string.format("%02d:%05.2f", minute, seconds)
end
print(SecondsToTime(0.661)) -- 00:00:00.66
print(SecondsToTime(100.185)) -- 00:01:40.19
print(SecondsToTime(1280.1698)) -- 00:21:20.17
print(SecondsToTime(3600.9541)) -- 01:00:00.95
```
## UI漸層顏色
```lua
-- colorA: (table)A顏色 {r = 255, g = 255, b = 255, a = 255}
-- colorB: (table)B顏色 {r = 255, g = 0, b = 255, a = 255}
-- boxCount: (number)產生A~B之間的漸變顏色數量
GetGradient(colorA, colorB, boxCount)
```
```lua=
function GetGradient(colorA, colorB, boxCount)
colorA.a = colorA.a or 255
colorB.a = colorB.a or 255
local temp = {}
for i = 1, boxCount do
local rAvg = colorA.r + math.floor((colorB.r - colorA.r) * i / boxCount)
local gAvg = colorA.g + math.floor((colorB.g - colorA.g) * i / boxCount)
local bAvg = colorA.b + math.floor((colorB.b - colorA.b) * i / boxCount)
local aAvg = colorA.a + math.floor((colorB.a - colorA.a) * i / boxCount)
table.insert(temp, {r = rAvg, g = gAvg, b = bAvg, a = aAvg})
end
return temp
end
print(GetGradient({r=255,g=255,b=255}, {r=255,g=0,b=255}, 6))
--[[
output
{
{r=255,g=212,b=255},{r=255,g=170,b=255},{r=255,g=127,b=255},
{r=255,g= 85,b=255},{r=255,g= 42,b=255},{r=255,g= 0,b=255}
}
]]
```