是否可以扩展插值器?
Is it possible to extend an Interpolator?
我正在尝试扩展 Vector2DFieldInterpolator
以便在给定三个点(起点、终点和中间点)的情况下制作平滑的弧形动画。
我通过在常规 Vector2DFieldInterpolator
上设置 key
和 keyValue
字段来让它工作,但现在我想把它全部放在一个组件中,这样它就可以很容易重复使用。
这是我现在拥有的最小可行示例:
Example.xml:
<?xml version="1.0" encoding="utf-8" ?>
<component name="ArcInterpolatorExample" extends="Scene" >
<script type="text/brightscript" uri="pkg:/components/Example.brs"/>
<children>
<Rectangle id = "animateMe" height = "20" width = "20" color="#ffff00ff"
translation="[250,250]"/>
<Label id="labelA" text="A" translation="[250,250]"/>
<Label id="labelB" text="B" translation="[125,250]"/>
<Label id="labelC" text="C" translation="[75,180]"/>
<Animation
id="animate"
easeFunction="linear"
duration="10">
<ArcInterpolator
id="arcInterpol"
start="[250,250]"
middle="[125,250]"
end="[75,180]"
fieldToInterp="animateMe.translation"
/>
</Animation>
</children>
</component>
Example.brs:
sub init()
m.arcAnimator = m.top.findNode("animate")
m.arcAnimator.control = "start"
end sub
ArcInterpolator.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name="ArcInterpolator" extends="Vector2DFieldInterpolator">
<interface>
<field id="start" type="vector2d" onChange="onCoordinateSet"/>
<field id="middle" type="vector2d" onChange="onCoordinateSet"/>
<field id="end" type="vector2d" onChange="onCoordinateSet"/>
</interface>
<script type="text/brightscript" uri="pkg:/components/ArcInterpolator.brs"/>
</component>
ArcInterpolator.brs
sub init()
m.pi = 3.1415927
end sub
sub onCoordinateSet()
' check that no two points are the same
if (m.top.start[0] = m.top.middle[0] and m.top.start[1] = m.top.middle[1]) or (m.top.start[0] = m.top.end[0] and m.top.start[1] = m.top.end[1]) or (m.top.middle[0] = m.top.end[0] and m.top.middle[1] = m.top.end[1]) then
return
else
setValues()
end if
end sub
sub setValues()
startpoint = m.top.start
midpoint = m.top.middle
endpoint = m.top.end
numOfPoints = 11
dim keys[numOfPoints-1]
dim values[numOfPoints-1]
keys[0] = 0.0
keys[numOfPoints-1] = 1.0
values[0] = startpoint
values[numOfPoints-1] = endpoint
' a bunch of calculation is done here and keys and values are set
m.top.key = keys
m.top.keyValue = values
end sub
事实证明是的,可以扩展一个插值器,但我的做法是错误的。插值器上有一个名为 fraction
的字段,它会在动画过程中更新。还有一个名为 fieldToInterp
的字段,它描述了要更改的节点和字段。
为了编写自己的插值器,您需要找到fieldToInterp
描述的节点和字段并将其存储在m
中,然后观察fraction
并更新该节点的字段根据分数是多少。这是最终的样子:
ArcInterpolator.brs:
sub init()
m.pi = 3.1415927
m.top.observeField("fraction", "calculateValue")
m.top.observeField("fieldToInterp", "findNodeToMove")
end sub
sub findNodeToMove(event as object)
nodeAndField = event.getData()
if right(nodeAndField, 12) <> ".translation" then return
length = len(nodeAndField)
nodeName = left(nodeAndField, length - 12)
currentNode = m.top
while currentNode.getParent() <> invalid
currentNode = currentNode.getParent()
node = currentNode.findNode(nodeName)
if node <> invalid
m.nodeToMove = node
exit while
end if
end while
end sub
sub onCoordinateSet()
' check that no two points are the same
if (m.top.start[0] = m.top.middle[0] and m.top.start[1] = m.top.middle[1]) or (m.top.start[0] = m.top.end[0] and m.top.start[1] = m.top.end[1]) or (m.top.middle[0] = m.top.end[0] and m.top.middle[1] = m.top.end[1]) then
return
else
setValues()
end if
end sub
sub setValues()
' do some math to set the center of the circle, total angle, start angle etc.
end sub
sub calculateValue(event as object)
fraction = event.getData()
angle = fraction * m.totalAngle + m.startAngle
dim position[1]
position[0] = m.center[0] + m.radius * cos(angle)
position[1] = m.center[1] + m.radius * sin(angle)
m.nodeToMove.translation = position
end sub
我正在尝试扩展 Vector2DFieldInterpolator
以便在给定三个点(起点、终点和中间点)的情况下制作平滑的弧形动画。
我通过在常规 Vector2DFieldInterpolator
上设置 key
和 keyValue
字段来让它工作,但现在我想把它全部放在一个组件中,这样它就可以很容易重复使用。
这是我现在拥有的最小可行示例:
Example.xml:
<?xml version="1.0" encoding="utf-8" ?>
<component name="ArcInterpolatorExample" extends="Scene" >
<script type="text/brightscript" uri="pkg:/components/Example.brs"/>
<children>
<Rectangle id = "animateMe" height = "20" width = "20" color="#ffff00ff"
translation="[250,250]"/>
<Label id="labelA" text="A" translation="[250,250]"/>
<Label id="labelB" text="B" translation="[125,250]"/>
<Label id="labelC" text="C" translation="[75,180]"/>
<Animation
id="animate"
easeFunction="linear"
duration="10">
<ArcInterpolator
id="arcInterpol"
start="[250,250]"
middle="[125,250]"
end="[75,180]"
fieldToInterp="animateMe.translation"
/>
</Animation>
</children>
</component>
Example.brs:
sub init()
m.arcAnimator = m.top.findNode("animate")
m.arcAnimator.control = "start"
end sub
ArcInterpolator.xml
<?xml version="1.0" encoding="utf-8" ?>
<component name="ArcInterpolator" extends="Vector2DFieldInterpolator">
<interface>
<field id="start" type="vector2d" onChange="onCoordinateSet"/>
<field id="middle" type="vector2d" onChange="onCoordinateSet"/>
<field id="end" type="vector2d" onChange="onCoordinateSet"/>
</interface>
<script type="text/brightscript" uri="pkg:/components/ArcInterpolator.brs"/>
</component>
ArcInterpolator.brs
sub init()
m.pi = 3.1415927
end sub
sub onCoordinateSet()
' check that no two points are the same
if (m.top.start[0] = m.top.middle[0] and m.top.start[1] = m.top.middle[1]) or (m.top.start[0] = m.top.end[0] and m.top.start[1] = m.top.end[1]) or (m.top.middle[0] = m.top.end[0] and m.top.middle[1] = m.top.end[1]) then
return
else
setValues()
end if
end sub
sub setValues()
startpoint = m.top.start
midpoint = m.top.middle
endpoint = m.top.end
numOfPoints = 11
dim keys[numOfPoints-1]
dim values[numOfPoints-1]
keys[0] = 0.0
keys[numOfPoints-1] = 1.0
values[0] = startpoint
values[numOfPoints-1] = endpoint
' a bunch of calculation is done here and keys and values are set
m.top.key = keys
m.top.keyValue = values
end sub
事实证明是的,可以扩展一个插值器,但我的做法是错误的。插值器上有一个名为 fraction
的字段,它会在动画过程中更新。还有一个名为 fieldToInterp
的字段,它描述了要更改的节点和字段。
为了编写自己的插值器,您需要找到fieldToInterp
描述的节点和字段并将其存储在m
中,然后观察fraction
并更新该节点的字段根据分数是多少。这是最终的样子:
ArcInterpolator.brs:
sub init()
m.pi = 3.1415927
m.top.observeField("fraction", "calculateValue")
m.top.observeField("fieldToInterp", "findNodeToMove")
end sub
sub findNodeToMove(event as object)
nodeAndField = event.getData()
if right(nodeAndField, 12) <> ".translation" then return
length = len(nodeAndField)
nodeName = left(nodeAndField, length - 12)
currentNode = m.top
while currentNode.getParent() <> invalid
currentNode = currentNode.getParent()
node = currentNode.findNode(nodeName)
if node <> invalid
m.nodeToMove = node
exit while
end if
end while
end sub
sub onCoordinateSet()
' check that no two points are the same
if (m.top.start[0] = m.top.middle[0] and m.top.start[1] = m.top.middle[1]) or (m.top.start[0] = m.top.end[0] and m.top.start[1] = m.top.end[1]) or (m.top.middle[0] = m.top.end[0] and m.top.middle[1] = m.top.end[1]) then
return
else
setValues()
end if
end sub
sub setValues()
' do some math to set the center of the circle, total angle, start angle etc.
end sub
sub calculateValue(event as object)
fraction = event.getData()
angle = fraction * m.totalAngle + m.startAngle
dim position[1]
position[0] = m.center[0] + m.radius * cos(angle)
position[1] = m.center[1] + m.radius * sin(angle)
m.nodeToMove.translation = position
end sub