🐕

React+TypeScriptなWebアプリで、Tweenしてみた001。(回転しながら横移動)

2023/12/31に公開

Abstract

React+TypeScriptで、tween.jsライブラリを使ってアニメーションするシリーズ1回目。
今回の参考はここ(hello_world)

結論

今回の成果物はココ↓
https://github.com/aaaa1597/react-tweenjs001

tween.jsライブラリとは

道路標識みたいなせ目的地とかを空間上に表示する機能。
回転、拡縮、横移動を簡単に実装できるアニメーションライブラリ。複雑なアニメーションを簡単に表現できる。

前提

手順

1.プロジェクト生成 -> VSCodeで開く

めんどいから、このスケルトンコードから始める。react-r3f-tutorial010
で、下記コマンドでフォルダ名とか整備する。

フォルダリネームとか
$ D:
$ cd .\Products\React.js\            # ご自身の適当なフォルダで。
$ rd /q /s D:\Products\React.js\react-r3f-advanced010
$ git clone https://github.com/aaaa1597/react-r3f-tutorial010.git
$ rd /q /s react-r3f-tutorial010/.git
$ ren react-r3f-tutorial010 react-tweenjs001
$ cd react-tweenjs001

準備

$ npm install --save three
$ npm install --save @types/three
$ npm install --save @react-three/fiber
$ npm install --save @react-three/drei
$ npm install --save @tweenjs/tween.js

App.tsx

まず全体。

App.tsx
-import React, {useRef} from 'react';
+import React, {useRef, useEffect } from 'react';
import './App.css';
import { Canvas, useFrame, MeshProps  } from '@react-three/fiber'
import * as THREE from 'three'
import { OrbitControls, Environment } from '@react-three/drei'
+import TWEEN from '@tweenjs/tween.js'

const Box = (props: MeshProps) => {
  const ref = useRef<THREE.Mesh>(null!)
+ useEffect(() => {
+   const tween = new TWEEN.Tween(ref.current.position)
+                 .to({x: 1, y: 3, z: 0,  rotation: 0}, 2000)
+                 .delay(1000)
+                 .easing(TWEEN.Easing.Elastic.InOut)
+   const tweenrot = new TWEEN.Tween(ref.current.rotation)
+                 .to({x: Math.PI, y: 0, z: 0,  rotation: 0}, 2000)
+                 .easing(TWEEN.Easing.Elastic.InOut)
+   const tweenBack = new TWEEN.Tween(ref.current.position)
+                 .to({x: 1, y: 1, z: 1, rotation: 0}, 3000)
+                 .easing(TWEEN.Easing.Elastic.InOut)
+   tween.chain(tweenrot)
+   tweenrot.chain(tweenBack)
+   tweenBack.chain(tween)
+   tween.start()
+ }, []);

  useFrame((_, delta) => {
-   if( !ref.current) return
-   ref.current.rotation.x += 1 * delta
-   ref.current.rotation.y += 0.5 * delta
+   // ref.current!.rotation.x += 1 * delta
+   // ref.current!.rotation.y += 0.5 * delta
  })

  return (
    <mesh {...props} ref={ref}>
      <boxGeometry />
      <meshNormalMaterial />
    </mesh>
  )
}

const Tween = () => {
  useFrame(() => {
    TWEEN.update()
  })
  return(<></>)
}

const App = () => {
  return (
-   <div style={{ width: "75vw", height: "75vh" }}>
+   <div style={{ width: "100vw", height: "75vh" }}>
      <Canvas camera={{ position: [3, 1, 2] }}>
        <Box position={[1, 1, 1]} name="A" />
+       <Tween />
        <Environment preset="forest" background />
        <OrbitControls />
        <axesHelper args={[5]} />
        <gridHelper />
      </Canvas>
    </div>
  );
}

export default App;

で、実行。


出来た!!

ポイント

  1. TWEENをimportする。
App.tsx
import TWEEN from '@tweenjs/tween.js'
  1. Tween関数コンポーネントを作って、<Tween />タグを埋め込む。
App.tsx
const Tween = () => {
  useFrame(() => {
    TWEEN.update()
  })
  return(<></>)
}
~略~
   <Tween />
  1. new TWEEN.Tween()で生成、いろいろ設定して、startで開始する。
App.tsx
  const tween = new TWEEN.Tween(ref.current.position)
                .to({x: 1, y: 3, z: 0,  rotation: 0}, 2000)
                .delay(1000)
                .easing(TWEEN.Easing.Elastic.InOut)
  const tweenrot = new TWEEN.Tween(ref.current.rotation)
                .to({x: Math.PI, y: 0, z: 0,  rotation: 0}, 2000)
                .easing(TWEEN.Easing.Elastic.InOut)
  const tweenBack = new TWEEN.Tween(ref.current.position)
                .to({x: 1, y: 1, z: 1, rotation: 0}, 3000)
                .easing(TWEEN.Easing.Elastic.InOut)
  tween.chain(tweenrot)
  tweenrot.chain(tweenBack)
  tweenBack.chain(tween)
  tween.start()
  1. useEffectで初回startすると、動き続ける。デフォルト繰り返し?
    to()に設定するrotationは値設定しても意味ないみたい。
    移動させたいときは、new TWEEN.Tween()の引数に、ref.current.positionを設定して、
    回転させたいときは、new TWEEN.Tween()の引数に、ref.current.rotationを設定する。
    一度に移動させたいときは...?調査中。


Discussion