是否可以扩展插值器?

时间:2019-11-12 17:09:21

标签: roku brightscript

我正在尝试扩展Vector2DFieldInterpolator,以便在给定三个点(起点,终点和中间的一点)的情况下制作平滑的弧形动画。

我已经通过在常规key上设置keyValueVector2DFieldInterpolator字段来使其工作,但是现在我想将其全部整合到一个组件中,以便于轻松使用重用。

以下是我目前拥有的最小可行示例:

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

1 个答案:

答案 0 :(得分:1)

事实证明是的,可以扩展插值器,但是我这样做的方式是错误的。插值器上有一个称为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