Skip to content

Commit

Permalink
Accept constants in Observers/animation objects
Browse files Browse the repository at this point in the history
  • Loading branch information
dphfox committed Apr 16, 2024
1 parent 9c6f4ed commit da03afa
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 52 deletions.
5 changes: 0 additions & 5 deletions docs/api-reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ For a beginner-friendly experience, [try the tutorials.](../tutorials/)

<div markdown>
### State
<a class="fusiondoc-api-index-link" href="state/types/stateobject" markdown>
<span class="fusiondoc-api-icon" markdown>:octicons-note-24:</span>
<span class="fusiondoc-api-name">StateObject</span>
<span class="fusiondoc-api-index-arrow" markdown>:octicons-chevron-right-24:</span>
</a>
<a class="fusiondoc-api-index-link" href="state/types/usedas" markdown>
<span class="fusiondoc-api-icon" markdown>:octicons-note-24:</span>
<span class="fusiondoc-api-name">UsedAs</span>
Expand Down
31 changes: 20 additions & 11 deletions src/Animation/Spring.luau
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ end
]]
function class:update(): boolean
local self = self :: InternalTypes.Spring<unknown>
local goalValue = peek(self._goalState)
local goalValue = peek(self._goal)

-- figure out if this was a goal change or a speed/damping change
if goalValue == self._goalValue then
Expand Down Expand Up @@ -191,11 +191,11 @@ end

local function Spring<T>(
scope: Types.Scope<unknown>,
goalState: Types.StateObject<T>,
goal: Types.UsedAs<T>,
speed: Types.UsedAs<number>?,
damping: Types.UsedAs<number>?
): Types.Spring<T>
if isState(scope) then
if typeof(scope) ~= "table" or isState(scope) then
logError("scopeMissing", nil, "Springs", "myScope:Spring(goalState, speed, damping)")
end
-- apply defaults for speed and damping
Expand All @@ -206,7 +206,12 @@ local function Spring<T>(
damping = 1
end

local dependencySet: {[Types.Dependency]: unknown} = {[goalState] = true}
local dependencySet: {[Types.Dependency]: unknown} = {}
local goalIsState = isState(goal)
if goalIsState then
local goal = goal :: Types.StateObject<T>
dependencySet[goal] = true
end
if isState(speed) then
local speed = speed :: Types.StateObject<number>
dependencySet[speed] = true
Expand All @@ -223,7 +228,7 @@ local function Spring<T>(
_speed = speed,
_damping = damping,

_goalState = goalState,
_goal = goal,
_goalValue = nil,

_currentType = nil,
Expand All @@ -242,14 +247,18 @@ local function Spring<T>(
local self = (self :: any) :: InternalTypes.Spring<T>

table.insert(scope, self)
if goalState.scope == nil then
logError("useAfterDestroy", nil, `The {goalState.kind} object`, `the Spring that is following it`)
elseif whichLivesLonger(scope, self, goalState.scope, goalState) == "definitely-a" then
logWarn("possiblyOutlives", `The {goalState.kind} object`, `the Spring that is following it`)

if goalIsState then
local goal = goal :: Types.StateObject<T>
if goal.scope == nil then
logError("useAfterDestroy", nil, `The {goal.kind} object`, `the Spring that is following it`)
elseif whichLivesLonger(scope, self, goal.scope, goal) == "definitely-a" then
logWarn("possiblyOutlives", `The {goal.kind} object`, `the Spring that is following it`)
end
-- add this object to the goal state's dependent set
goal.dependentSet[self] = true
end

-- add this object to the goal state's dependent set
goalState.dependentSet[self] = true
self:update()

return self
Expand Down
34 changes: 22 additions & 12 deletions src/Animation/Tween.luau
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ local CLASS_METATABLE = {__index = class}
]]
function class:update(): boolean
local self = self :: InternalTypes.Tween<unknown>
local goalValue = peek(self._goalState)
local goalValue = peek(self._goal)

-- if the goal hasn't changed, then this is a TweenInfo change.
-- in that case, if we're not currently animating, we can skip everything
Expand Down Expand Up @@ -93,20 +93,27 @@ end

local function Tween<T>(
scope: Types.Scope<unknown>,
goalState: Types.StateObject<T>,
goal: Types.UsedAs<T>,
tweenInfo: Types.UsedAs<TweenInfo>?
): Types.Tween<T>
if isState(scope) then
logError("scopeMissing", nil, "Tweens", "myScope:Tween(goalState, tweenInfo)")
end
local currentValue = peek(goalState)
local currentValue = peek(goal)

-- apply defaults for tween info
if tweenInfo == nil then
tweenInfo = TweenInfo.new()
end

local dependencySet: {[Types.Dependency]: unknown} = {[goalState] = true}
local dependencySet: {[Types.Dependency]: unknown} = {}

local goalIsState = isState(goal)
if goalIsState then
local goal = goal :: Types.StateObject<T>
dependencySet[goal] = true
end

local tweenInfoIsState = isState(tweenInfo)
if tweenInfoIsState then
local tweenInfo = tweenInfo :: Types.StateObject<TweenInfo>
Expand All @@ -123,7 +130,7 @@ local function Tween<T>(
scope = scope,
dependencySet = dependencySet,
dependentSet = {},
_goalState = goalState,
_goal = goal,
_tweenInfo = tweenInfo,
_tweenInfoIsState = tweenInfoIsState,

Expand All @@ -141,15 +148,18 @@ local function Tween<T>(
local self = (self :: any) :: InternalTypes.Tween<T>

table.insert(scope, self)
if goalState.scope == nil then
logError("useAfterDestroy", nil, `The {goalState.kind} object`, `the Tween that is following it`)
elseif whichLivesLonger(scope, self, goalState.scope, goalState) == "definitely-a" then
logWarn("possiblyOutlives", `The {goalState.kind} object`, `the Tween that is following it`)

if goalIsState then
local goal = goal :: any
if goal.scope == nil then
logError("useAfterDestroy", nil, `The {goal.kind} object`, `the Tween that is following it`)
elseif whichLivesLonger(scope, self, goal.scope, goal) == "definitely-a" then
logWarn("possiblyOutlives", `The {goal.kind} object`, `the Tween that is following it`)
end
-- add this object to the goal state's dependent set
goal.dependentSet[self] = true
end

-- add this object to the goal state's dependent set
goalState.dependentSet[self] = true

return self
end

Expand Down
4 changes: 2 additions & 2 deletions src/InternalTypes.luau
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ type ForProcessor = {

-- A state object which follows another state object using tweens.
export type Tween<T> = Types.Tween<T> & {
_goalState: Value<T>,
_goal: Types.UsedAs<T>,
_tweenInfo: TweenInfo,
_prevValue: T,
_nextValue: T,
Expand All @@ -96,7 +96,7 @@ export type Tween<T> = Types.Tween<T> & {
export type Spring<T> = Types.Spring<T> & {
_speed: Types.UsedAs<number>,
_damping: Types.UsedAs<number>,
_goalState: Value<T>,
_goal: Types.UsedAs<T>,
_goalValue: T,

_currentType: string,
Expand Down
41 changes: 22 additions & 19 deletions src/State/Observer.luau
Original file line number Diff line number Diff line change
Expand Up @@ -76,42 +76,45 @@ end

local function Observer(
scope: Types.Scope<unknown>,
watching: Types.Dependency
watching: unknown
): Types.Observer
if watching == nil then
logError("scopeMissing", nil, "Observers", "myScope:Observer(watching)")
end

local watchingState = typeof(watching) == "table" and (watching :: any).dependentSet ~= nil

local self = setmetatable({
scope = scope,
dependencySet = {[watching] = true},
dependencySet = if watchingState then {[watching] = true} else {},
dependentSet = {},
_changeListeners = {}
}, CLASS_METATABLE)
local self = (self :: any) :: InternalTypes.Observer

table.insert(scope, self)

if watching.scope == nil then
local watching: any = watching
logError(
"useAfterDestroy",
nil,
`The {watching.kind or watching.type or "watched"} object`,
`the Observer that is watching it`
)
elseif whichLivesLonger(scope, self, watching.scope, watching) == "definitely-a" then
if watchingState then
local watching: any = watching
logWarn(
"possiblyOutlives",
`The {watching.kind or watching.type or "watched"} object`,
`the Observer that is watching it`
)
if watching.scope == nil then
logError(
"useAfterDestroy",
nil,
`The {watching.kind or watching.type or "watched"} object`,
`the Observer that is watching it`
)
elseif whichLivesLonger(scope, self, watching.scope, watching) == "definitely-a" then
local watching: any = watching
logWarn(
"possiblyOutlives",
`The {watching.kind or watching.type or "watched"} object`,
`the Observer that is watching it`
)
end
-- add this object to the watched object's dependent set
watching.dependentSet[self] = true
end

-- add this object to the watched object's dependent set
watching.dependentSet[self] = true

return self
end

Expand Down
6 changes: 3 additions & 3 deletions src/Types.luau
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export type Observer = Dependent & {
}
export type ObserverConstructor = (
scope: Scope<unknown>,
watching: Dependency
watching: unknown
) -> Observer

-- A state object which follows another state object using tweens.
Expand All @@ -157,7 +157,7 @@ export type Tween<T> = StateObject<T> & Dependent & {
}
export type TweenConstructor = <T>(
scope: Scope<unknown>,
goalState: StateObject<T>,
goalState: UsedAs<T>,
tweenInfo: UsedAs<TweenInfo>?
) -> Tween<T>

Expand All @@ -170,7 +170,7 @@ export type Spring<T> = StateObject<T> & Dependent & {
}
export type SpringConstructor = <T>(
scope: Scope<unknown>,
goalState: StateObject<T>,
goalState: UsedAs<T>,
speed: UsedAs<number>?,
damping: UsedAs<number>?
) -> Spring<T>
Expand Down

0 comments on commit da03afa

Please sign in to comment.