Fix signal, mount, types, store bugs. Adding tutorials
This commit is contained in:
parent
52bc94cef2
commit
3e38345dfb
20 changed files with 400 additions and 29 deletions
|
|
@ -13,6 +13,6 @@
|
|||
|
||||
## 목차
|
||||
|
||||
[1. 설치하기](kr/tutorial/1_install)
|
||||
[1. 설치하기](kr/tutorial/1_importRobloxClass)
|
||||
[2. 시작하기](kr/tutorial/2_starting)
|
||||
|
||||
|
|
|
|||
0
docs/kr/tutorial/11_signal.md
Normal file
0
docs/kr/tutorial/11_signal.md
Normal file
46
docs/kr/tutorial/1_importRobloxClass.md
Normal file
46
docs/kr/tutorial/1_importRobloxClass.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
# 로블록스 오브젝트 불러오기
|
||||
|
||||
Frame 과 같은 UI 오브젝트를 만들고 싶은 경우 먼저 import 를 이용해주어야 합니다.
|
||||
다음과 같이 입력해보세요!
|
||||
|
||||
```lua
|
||||
local Quad = require(path.to.module).Init()
|
||||
local Class = Quad.Class
|
||||
|
||||
local Frame = Class "Frame"
|
||||
|
||||
print(
|
||||
Frame {
|
||||
Name = "Wow!";
|
||||
-- 다음과 같이 자식을 추가할 수 있습니다
|
||||
Frame {
|
||||
Name = "Child";
|
||||
};
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
나중에 자신만의 UI 오브젝트를 생성할 수 있지만, 일반적인 로블록스가 지원하는 오브젝트의 경우 `Class(ClassName:string)` 으로 불러올 수 있습니다
|
||||
|
||||
불러온 Class 에 기본값을 설정할 수도 있습니다
|
||||
|
||||
```lua
|
||||
local Quad = require(path.to.module).Init()
|
||||
local Class = Quad.Class
|
||||
|
||||
local FrameWithoutBorder = Class "Frame"
|
||||
FrameWithoutBorder.BorderSizePixel = 0
|
||||
|
||||
local FrameWithBorder = Class "Frame"
|
||||
FrameWithBorder.BorderSizePixel = 1
|
||||
|
||||
local frame1 = FrameWithoutBorder {}
|
||||
local frame2 = FrameWithBorder {}
|
||||
print(frame1.FrameWithBorder)
|
||||
print(frame2.FrameWithBorder)
|
||||
```
|
||||
|
||||
이제 그려낸 프레임을 화면에 그려보고 싶나요? 다음 튜토리얼 Mount 를 확인해보세요!
|
||||
|
||||
[다음 튜토리얼](./2_mount)
|
||||
84
docs/kr/tutorial/2_mount.md
Normal file
84
docs/kr/tutorial/2_mount.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
# 트리를 연결하고 화면에 UI 를 표시하기
|
||||
|
||||
일반적으로 *Quad* 모듈에서 모든 Parent 처리는 `Mount` 를 이용합니다. `Mount(to:any,...item:any)->mounts` 함수를 이용하면 다루는 오브젝트가 로블록스 Instance 인지, Quad 확장 클래스인지 상관없이 알아서 Parent 를 처리해 줍니다.
|
||||
|
||||
```lua
|
||||
--- StarterGui 안에 ScreenGui 를 넣고 로컬스크립트로 입력해보세요
|
||||
local ScreenGUI = script.Parent
|
||||
local Quad = require(path.to.module).Init()
|
||||
local Class,Mount = Quad.Class,Quad.Mount
|
||||
|
||||
local Frame = Class "Frame"
|
||||
|
||||
Mount(ScreenGui,
|
||||
Frame {
|
||||
Name = "Wow!";
|
||||
}
|
||||
--[[
|
||||
, Frame {} , Frame {}
|
||||
더많은 오브젝트를 다같이 Mount 할 수 있습니다
|
||||
]]
|
||||
)
|
||||
```
|
||||
|
||||
편의를 위해서 Mount 함수는 mounts 라는 객체를 반환합니다. 이것을 이용하면 필요에 따라서 Mount 상태를 해제할 수 있습니다.
|
||||
|
||||
```lua
|
||||
local ScreenGUI = script.Parent
|
||||
local Quad = require(path.to.module).Init()
|
||||
local Class,Mount = Quad.Class,Quad.Mount
|
||||
|
||||
local Frame = Class "Frame"
|
||||
|
||||
local mainFrame = Frame {}
|
||||
Mount(ScreenGui,mainFrame)
|
||||
|
||||
local childFrame = Frame {}
|
||||
local childFrameMount = Mount(mainFrame,childFrame)
|
||||
childFrameMount:Unmount()
|
||||
-- childFrame 은 단순히 .Parent 되는 것을 넘어 메모리에서 사라집니다
|
||||
-- 즉, Destroy() 가 호출됩니다
|
||||
```
|
||||
|
||||
이 동작은 리스트를 만들 때 유용할 수 있습니다. **다시로드 동작시 직접 제거가 필요하지 않습니다**
|
||||
|
||||
```lua
|
||||
local ScreenGUI = script.Parent
|
||||
local Quad = require(path.to.module).Init()
|
||||
local Class,Mount = Quad.Class,Quad.Mount
|
||||
|
||||
local Frame = Class "Frame"
|
||||
|
||||
local mainFrame = Frame {}
|
||||
Mount(ScreenGui,mainFrame)
|
||||
|
||||
local lastListMount
|
||||
local function refreshList()
|
||||
if lastListMount then -- 이전 children 을 알아서 제거합니다
|
||||
lastListMount:Unmount()
|
||||
end
|
||||
|
||||
local children = {}
|
||||
for i = 1,10 do
|
||||
table.insert(children,Frame { Name = tostring(i) })
|
||||
end
|
||||
|
||||
lastListMount = Mount(mainFrame,unpack(children))
|
||||
end
|
||||
|
||||
task.spawn(function()
|
||||
while true do
|
||||
refreshList()
|
||||
task.wait(2)
|
||||
end
|
||||
end)
|
||||
```
|
||||
|
||||
다음과 같이 이전 children 을 간접적으로 제거합니다. 단 ScrollFrame 의 경우 CanvasPosition 이 초기화 되어버리므로 자식들을 `:Unmount()` 하기 전에 위치를 저장하고 `Mount()` 후 불러와야 합니다
|
||||
<br>
|
||||
|
||||
아직 생성한 오브젝트를 변수에 넣어야하는것이 귀찮아 보이는가요? 이제 `Store.GetObject(id:string)` 에 대해 알아봅시다.
|
||||
<br>
|
||||
|
||||
[다음 튜토리얼](./3_storeGetObject)
|
||||
138
docs/kr/tutorial/3_storeGetObject.md
Normal file
138
docs/kr/tutorial/3_storeGetObject.md
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
# 오브젝트에 아이디 부여하기, 그리고 사용하기
|
||||
|
||||
**변수에 만들어진 오브젝트를 하나하나 저장해???** 그게 편할리가 없죠. 오브젝트에 아이디를 넣고 사용해봅시다.
|
||||
|
||||
```lua
|
||||
local ScreenGUI = script.Parent
|
||||
local Quad = require(path.to.module).Init()
|
||||
local Class,Mount,Store = Quad.Class,Quad.Mount,Quad.Store
|
||||
|
||||
local Frame = Class "Frame"
|
||||
|
||||
Frame "mainFrame" {
|
||||
Size = UDim2.fromScale(1,1);
|
||||
}
|
||||
|
||||
Mount(ScreenGUI,Store.GetObject("mainFrame"))
|
||||
```
|
||||
|
||||
아이디에 허용되는 글자는 변수명과 같습니다. 일반적으로 대소문자, 숫자, 언더바(_) 를 허용합니다.
|
||||
오브젝트 생성시 `Frame "mainFrame" {}` 와 같이 id 값을 지정해 준다면 생성된 오브젝트는 그 아이디를 가지게 됩니다.
|
||||
`Store.GetObject(id:string)->Object` 는 생성된 객체중 가장 첫번째의 id 가 일치하는 오브젝트를 반환해 줍니다. 만약 원한다면
|
||||
|
||||
```lua
|
||||
local index = 1
|
||||
Frame ("mainFrame" .. index) {}
|
||||
print(Store.GetObject("mainFrame" .. index))
|
||||
```
|
||||
|
||||
처럼 생성이나 가져오기에서 식을 만들어 넣을 수도 있습니다.
|
||||
|
||||
## 다량의 오브젝트를 다루기
|
||||
|
||||
또한, Quad 는 다량의 오브젝트를 다루기 편하도록 `Store.GetObjects(id:string)->objectList` 라는 함수를 가지고 있습니다.
|
||||
|
||||
> 주의 : *GetObjects 의 반환값인 objectList 는 캐시해서는 안됩니다. objectList 를 local 에 넣고 계속해서 유지시키지 마십시오, 반환값은 자동으로 업데이트 되지 않습니다. 반환값을 바로바로 사용하는 것이 이상적입니다.*
|
||||
|
||||
```lua
|
||||
local ScreenGUI = script.Parent
|
||||
local Quad = require(path.to.module).Init()
|
||||
local Class,Mount,Store = Quad.Class,Quad.Mount,Quad.Store
|
||||
|
||||
local Frame = Class "Frame"
|
||||
|
||||
Frame "mainFrame" {
|
||||
Size = UDim2.fromScale(1,1);
|
||||
Frame "Child" {
|
||||
Size = UDim2.fromOffset(20,20);
|
||||
};
|
||||
Frame "Child" {
|
||||
Size = UDim2.fromOffset(20,20);
|
||||
Position = UDim2.fromOffset(30,0);
|
||||
};
|
||||
Frame "Child" {
|
||||
Size = UDim2.fromOffset(20,20);
|
||||
Position = UDim2.fromOffset(60,0);
|
||||
};
|
||||
Frame "Child" {
|
||||
Size = UDim2.fromOffset(20,20);
|
||||
Position = UDim2.fromOffset(90,0);
|
||||
};
|
||||
}
|
||||
|
||||
Mount(ScreenGUI,Store.GetObject("mainFrame"))
|
||||
|
||||
-- 값을 설정할 수 있습니다. 그러니 값을 읽거나 :Connect 할 수는 없습니다
|
||||
Store.GetObjects("Child").Size = UDim2.fromOffset(30,30)
|
||||
|
||||
-- 필요에 따라 Store.GetObjects("Child") 를 pairs 에 넣어 for 문을 사용하거나
|
||||
-- :Each , :EachAsync , :IsEmpty 함수를 이용할 수 있습니다
|
||||
task.spawn(function()
|
||||
while true do
|
||||
Store.GetObjects("Child"):Each(function (item,index)
|
||||
item.BackgroundColor3 = Color3.fromRGB(
|
||||
math.random(0,255),
|
||||
math.random(0,255),
|
||||
math.random(0,255)
|
||||
)
|
||||
end)
|
||||
task.wait(1)
|
||||
end)
|
||||
end
|
||||
```
|
||||
|
||||
`Store.GetObjects()` 의 반환 `objectList` 의 메소드들은 다음과 같습니다.
|
||||
|
||||
:Each((item:any,index:number)->())
|
||||
> 일반적인 반복입니다. for 를 사용하는것과 효과가 같으나 함수를 이용합니다
|
||||
|
||||
:EachAsync((item:any,index:number)->())
|
||||
> 일반적으로 반환을 기다리지 않고 바로바로 다음 아이템으로 넘어갑니다.
|
||||
> 코루틴이 이용됩니다 `wrap()`
|
||||
|
||||
:IsEmpty()
|
||||
> 이 ObjectList 가 비어있는지 여부를 반환합니다.
|
||||
|
||||
:Remove(indexOrItem:number|any)
|
||||
> objectList 에서 해당하는 오브젝트를 제거합니다.
|
||||
> , & 를 사용한 고급 검색에서는 작동하지 않습니다
|
||||
|
||||
## 고급 ID 사용하기
|
||||
|
||||
id 기능을 조금더 고급적인 방법으로 사용할 수도 있습니다.
|
||||
|
||||
```lua
|
||||
--다음과 같이 a 와 b 모두 가진 프레임을 생성할 수도 있습니다.
|
||||
Frame "a,b" {
|
||||
Name = "main";
|
||||
Frame "a" {
|
||||
Name = "Child1";
|
||||
};
|
||||
Frame "b" {
|
||||
Name = "Child2";
|
||||
};
|
||||
}
|
||||
|
||||
-- 다음과 같이 a 와 b 둘다 선택할 수 있습니다
|
||||
Store.GetObjects("a,b"):Each(function(item,index)
|
||||
print(item.Name)
|
||||
end)
|
||||
print("----")
|
||||
|
||||
-- 다음과 같이 a 와 b 를 동시에 가진 것을 선택할 수 있습니다
|
||||
Store.GetObjects("a&b"):Each(function(item,index)
|
||||
print(item.Name)
|
||||
end)
|
||||
print("----")
|
||||
|
||||
-- 다음과 같이 a와b 를 동시에 가진것과, b 를 가진것을 선택
|
||||
-- 할 수 있습니다
|
||||
Store.GetObjects("a&b,b"):Each(function(item,index)
|
||||
print(item.Name)
|
||||
end)
|
||||
```
|
||||
|
||||
또는(or) 연산 `,` 와 그리고(and) 연산 `&` 연산을 GetObjects 에 사용할 수 있고, 생성시에는 `,` 로 여러 아이디를 부여해줄 수 있습니다. *띄어쓰기는 무시됩니다*
|
||||
|
||||
> 주의 : *고급 ID 사용시 :Remove 연산자는 사용할 수 없습니다*
|
||||
0
docs/kr/tutorial/4_style.md
Normal file
0
docs/kr/tutorial/4_style.md
Normal file
0
docs/kr/tutorial/5_events.md
Normal file
0
docs/kr/tutorial/5_events.md
Normal file
0
docs/kr/tutorial/6_tween.md
Normal file
0
docs/kr/tutorial/6_tween.md
Normal file
0
docs/kr/tutorial/7_register.md
Normal file
0
docs/kr/tutorial/7_register.md
Normal file
4
docs/kr/tutorial/8_lang.md
Normal file
4
docs/kr/tutorial/8_lang.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
# 언어관리
|
||||
|
||||
Quad 에는 귀찮은 언어관리를 자동으로 해주는 모듈이 내장되어 있습니다.
|
||||
0
docs/kr/tutorial/9_quadProperty.md
Normal file
0
docs/kr/tutorial/9_quadProperty.md
Normal file
|
|
@ -274,7 +274,9 @@ function module.init(shared)
|
|||
local lastName = prop
|
||||
return function (nprop,...)
|
||||
nprop = nprop or {}
|
||||
if not nprop.Name then
|
||||
nprop.Name = gsub(gsub(match(lastName,"[^,]+")," +$",""),"^ +","")
|
||||
end
|
||||
for styleName,styleObj in pairs(styleList) do
|
||||
if match(prop,styleName) then
|
||||
insert(nprop,styleObj)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,15 @@ local insert = table.insert
|
|||
local find = table.find
|
||||
local floor = math.floor
|
||||
|
||||
if not find then
|
||||
find = function (table,item)
|
||||
for i,v in pairs(table) do
|
||||
if v == item then return i end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local script = script
|
||||
local EasingFunctions = require(script and script.EasingFunctions or "EasingFunctions")
|
||||
local Stepped = require(script and script.Stepped or "Stepped")
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ function module.init(shared)
|
|||
mountsClass.__index = mountsClass
|
||||
function mountsClass:Unmount()
|
||||
for _,v in ipairs(self) do
|
||||
v:unmount()
|
||||
v:Unmount()
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ function module.init(shared)
|
|||
local connection = {}
|
||||
connection.__index = connection
|
||||
function connection.New(signal,func)
|
||||
return {signal = signal,func = func}
|
||||
return setmetatable({signal = signal,func = func},connection)
|
||||
end
|
||||
function connection:Disconnect(slient)
|
||||
local signal = self.signal
|
||||
|
|
@ -69,7 +69,7 @@ function module.init(shared)
|
|||
end
|
||||
for i,v in pairs(onceConnection) do
|
||||
if v.connection == self then
|
||||
remove(connection,i)
|
||||
remove(onceConnection,i)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,6 +11,16 @@ local remove = table.remove
|
|||
local gmatch = string.gmatch
|
||||
local gsub = string.gsub
|
||||
local match = string.match
|
||||
local find = table.find
|
||||
|
||||
if not find then
|
||||
find = function (table,item)
|
||||
for i,v in pairs(table) do
|
||||
if v == item then return i end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function catch(...)
|
||||
local passed,err = pcall(...)
|
||||
|
|
@ -32,17 +42,17 @@ function module.init(shared)
|
|||
|
||||
-- id space (array of object)
|
||||
local objectListClass = {__type = "quad_objectlist"}
|
||||
function objectListClass:Each(func)
|
||||
function objectListClass:EachAsync(func)
|
||||
local index = 1
|
||||
for i,v in pairs(self) do
|
||||
wrap(catch)(func,index,v)
|
||||
wrap(catch)(func,v,index)
|
||||
index = index + 1
|
||||
end
|
||||
end
|
||||
function objectListClass:EachSync(func)
|
||||
function objectListClass:Each(func)
|
||||
local index = 1
|
||||
for _,v in pairs(self) do
|
||||
local ret = func(index,v)
|
||||
local ret = func(v,index)
|
||||
index = index + 1
|
||||
if ret then
|
||||
break
|
||||
|
|
@ -50,6 +60,9 @@ function module.init(shared)
|
|||
end
|
||||
end
|
||||
function objectListClass:Remove(indexOrItem)
|
||||
if self.__locked then
|
||||
error("This objectList is locked, maybe used Store.GetObjects('a,b')? AdvancedObjectQuery does not support :Remove")
|
||||
end
|
||||
local thisType = type(indexOrItem)
|
||||
if thisType == "number" then
|
||||
return remove(self,indexOrItem),indexOrItem
|
||||
|
|
@ -78,24 +91,65 @@ function module.init(shared)
|
|||
|
||||
-- get object array with id (objSpace)
|
||||
function new.GetObjects(ids)
|
||||
if match(ids,",") then
|
||||
if match(ids,"[,&]") then
|
||||
local list = objectListClass.__new()
|
||||
objectListClass.__locked = true
|
||||
local checked = {}
|
||||
for query in gmatch(ids,"[^,]+") do -- split by ,
|
||||
if match(query,"&") then
|
||||
-- multi ids (and)
|
||||
|
||||
-- make list of combined ids
|
||||
local queryIds = {}
|
||||
for id in gmatch(query,"[^&]+") do
|
||||
id = gsub(gsub(id,"^ +","")," +$","")
|
||||
insert(queryIds,id)
|
||||
end
|
||||
|
||||
-- loop as first list
|
||||
local targetList = queryIds[1] and items[remove(queryIds,1)]
|
||||
if targetList then
|
||||
for _,item in pairs(targetList) do
|
||||
if not checked[item] then
|
||||
-- check item has all of ids from queryIds
|
||||
local ok = true
|
||||
for _,id in ipairs(queryIds) do
|
||||
local checkList = items[id]
|
||||
if (not checkList) or (not find(checkList,item)) then
|
||||
ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- insert in return list
|
||||
if ok then
|
||||
insert(list,item)
|
||||
-- prevent multi insert
|
||||
checked[item] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
query = gsub(gsub(query,"^ +","")," +$","")
|
||||
local idItem = items[query]
|
||||
if idItem then
|
||||
for _,item in pairs(idItem) do
|
||||
if not checked[item] then
|
||||
insert(list,item)
|
||||
checked[item] = true -- prevent multi insert
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return list
|
||||
else
|
||||
local list = items[ids]
|
||||
if list then return list end
|
||||
list = objectListClass.__new()
|
||||
items[ids] = list
|
||||
return list
|
||||
else
|
||||
local list = objectListClass.__new()
|
||||
for id in gmatch(ids,"[^,]+") do -- split by ,
|
||||
id = gsub(gsub(id,"^ +","")," +$","")
|
||||
local idItem = items[id]
|
||||
if idItem then
|
||||
for _,item in pairs(idItem) do
|
||||
insert(list,item)
|
||||
end
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
end
|
||||
-- get first object with id (not array)
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ export type register = {
|
|||
}
|
||||
export type store = {}
|
||||
export type objectList = {
|
||||
Each: (self:objectList,(item:DOM,index:number)->())->();
|
||||
EachSync: (self:objectList,(item:DOM,index:number)->())->();
|
||||
Each: (self:objectList,(item:DOM|any,index:number)->())->();
|
||||
EachSync: (self:objectList,(item:DOM|any,index:number)->())->();
|
||||
Remove: (self:objectList,index:number|DOM)->(DOM?,number?);
|
||||
IsEmpty: (self:objectList)->boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,9 +54,7 @@ function module.init()
|
|||
|
||||
local Global = Store.GetStore "global"
|
||||
local TweenTest = Class(script.tween)
|
||||
local LangTest = Class(script.lang)
|
||||
|
||||
-- Signal.
|
||||
-- local LangTest = Class(script.lang)
|
||||
|
||||
SetTheme(Global)
|
||||
|
||||
|
|
@ -65,8 +63,8 @@ function module.init()
|
|||
Size = UDim2.fromOffset(400,640);
|
||||
Position = UDim2.fromScale(0.5,0.5);
|
||||
AnchorPoint = Vector2.new(0.5,0.5);
|
||||
-- TweenTest{};
|
||||
LangTest{};
|
||||
TweenTest{};
|
||||
-- LangTest{};
|
||||
}
|
||||
}
|
||||
Mount(game.StarterGui,Store.GetObject "MainGui")
|
||||
|
|
|
|||
36
testing/signal
Normal file
36
testing/signal
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
local mySignal = Signal.Bindable.New()
|
||||
|
||||
local connection = mySignal:Connect(function(v)
|
||||
print(v)
|
||||
end)
|
||||
mySignal:Fire("우왕")
|
||||
connection:Disconnect()
|
||||
mySignal:Fire("이거뜨면안된다")
|
||||
|
||||
task.spawn(function()
|
||||
task.wait(5)
|
||||
mySignal:Fire("우와왕")
|
||||
end)
|
||||
print(mySignal:Wait())
|
||||
|
||||
mySignal:Once(function(v)
|
||||
print(v)
|
||||
end)
|
||||
mySignal:Fire("우와와왕")
|
||||
mySignal:Fire("이것도 뜨면안된다")
|
||||
|
||||
mySignal:Once(function(v)
|
||||
print(v)
|
||||
end):Disconnect()
|
||||
mySignal:Fire("이것도 뜨면안된다*2")
|
||||
|
||||
local myClass = Class.Extend()
|
||||
function myClass:Render(props)
|
||||
return Class "TextBox" {
|
||||
[Event.Prop "Text"] = function(this,value)
|
||||
self:EmitPropertyChangedSignal("Text",value)
|
||||
end;
|
||||
Size = UDim2.new()
|
||||
}
|
||||
end
|
||||
Loading…
Reference in a new issue