Skiaで物体が放物線の動きを描いて移動していくサンプルです。"RUN"ボタンを押すと実行されます。
静的な放物線を描画するだけであれば<Path />
の曲線を使えばよさそうです。ただ動的に位置を移動させるとなると各移動位置の座標が必要そうなため、三角関数のsinカーブで放物線の座標を計算することにしました。X軸がθ(角度)でY軸がsinθのグラフの場合、θが0〜180の場合に上向きの放物線になるため、それを利用します。
以下でXが0からπ(180°)までの場合のY座標の位置をそれぞれ取得し配列にしておきます(100分割してます)。
const curveYPath = useMemo(() => {
const curveHeight = canvasSize.height - 200
return range(0, 100)
.map(i => (Math.PI / 100) * i)
.map(theta => {
const sin = Math.sin(theta) * curveHeight
return -sin
})
}, [])
-sin
しているのは、CanvasではYが上から下に向けて値が大きくなっていたため、縦位置をマイナスにする必要があるためです。
動的に変化する値としてpos
というvalueを用意しておき、
const pos = useValue(0)
移動させるタイミングでpos
の値を0からMath.PI
(180°)に変化させます。
runTiming(pos, Math.PI, { duration: 3000 })
Canvasで動かしたいシェイプを囲んだ<Group>
に対しtranslateX
、translateY
を指定します。interpolate
でpos
の値を元に移動量を割り当てます。 translateX
はpos
が増えると等分に横に移動していき、translateY
は作成しておいたY座標位置の配列を元に移動させます。
return (
<Canvas style={{ flex: 1 }}>
<Group
transform={useComputedValue(() => {
return [
{
translateX: interpolate(
pos.current,
[0, Math.PI],
[0, canvasSize.width - ballRadius * 2],
),
},
{
translateY: interpolate(
pos.current,
range(0, 100).map(i => (Math.PI / 100) * i),
curveYPath,
),
},
]
}, [pos])}
>
<Circle
r={ballRadius}
cx={startPos.x}
cy={startPos.y}
color="lightblue"
style="fill"
/>
</Group>
</Canvas>
)
全体のコードは以下で確認できます。