TikTokでプログラミング - 電卓エフェクトつくってみた

# はじめに

BitStar CPOの出水です。
この記事は[BitStar Advent Calendar](https://qiita.com/advent-calendar/2023/bitstar) 12/15の投稿です。

[BitStar](https://bitstar.tokyo/corp/)はさまざまなSNSプラットフォームでインフルエンサーの方々に商品やサービスの紹介投稿を行なってもらえるインフルエンサーマーケティングプラットフォーム「[BitStar Match](https://bitstar.tokyo/match/)」を運営しています。

2015年にYouTubeを中心に始まったBitStarのインフルエンサーマーケティング事業においても、近年はTikTokを中心とするショート動画の依頼が増えてきました。

さらに、TikTok上で活躍する方の中には、投稿を行うインフルエンサーだけでなく、投稿に使用する音源やエフェクトを作るクリエイターも増えてきている状況です。

そこで今回は、自分がこれまで培ってきたプログラミングの知識を活かして、TikTokエフェクトの作成に入門してみたいと思います。

# TikTokでプログラミング？

https://www.tiktok.com/discover/%E3%82%AB%E3%83%A2%E3%82%B2%E3%83%BC%E3%83%A0

TikTokで上記のような、ミニゲームのエフェクトを使った投稿を見たことないでしょうか？

実はTikTokにはこういった複雑なエフェクトも簡単に(従来プログラミング比)作れてしまう、Effect Houseという開発環境が用意されています。

Effect HouseのWebページに行くと...

https://effecthouse.tiktok.com/?utm_source=tiktok_article_legal&lang=ja

![スクリーンショット 2023-12-15 2.27.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/63089b4e-bd21-b408-ea2e-c80bea7a1d3f.png)

...!!!
明らかにビジュアルプログラミングを行えそうなUIがありますね!
というかその上のUIにはUnityのようなゲームエンジンを彷彿とさせる3D座標が表示されていて、とてつもなくとっつきやすそうな感じがします。
これはプログラミングするしか!

しかも、先述のカモゲームを見ているだけでも
- 入出力(カモの移動)
- 分岐(カモと卵の衝突判定)
- ループ(右から左に卵を流す動き)

があるので、余裕でチューリング完全な上に全然高級なプログラミングができそうですね。
ということで、以下から実際にTikTokでプログラミングをしてエフェクトを作成してみた際の手順について紹介していきたいと思います。

# インストール

なにはともあれまずはEffect Houseのインストールから。

https://effecthouse.tiktok.com/download

M2 macを使っているのでM1/M2用のdmgをダウンロードしてインストール。
それほど時間もかかりませんでした。
起動するとQRコードをTikTokアプリで読み込むだけでログイン完了。簡単ですね。

![スクリーンショット 2023-12-15 2.35.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/fd6fa4d7-d0fe-ce95-4bea-ab5c89e451e5.png)

ちょうど1つ前のバージョンで日本語対応がリリースされたようだったので、UIを日本語に変更しておきました。

https://effecthouse.tiktok.com/latest/release-notes-latest/v3-5-0/

# 何ができるのか

とりあえず、「プロジェクトを作成」から新規プロジェクトを開いてどこまでプログラミングできそうか確認します。

![スクリーンショット 2023-12-15 2.22.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/015c1bc0-a3a3-e24e-ec1d-282eb1ef05e5.png)

シーン画面左上の「3Dを表示」を押すとUnityライクな3Dビューが表示され、その下の「ビジュアルスクリプティング」のところでプログラミングができそうですが、さすがに初見ではどうすればいいのか分からなかったので、ドキュメントを参照。

https://effecthouse.tiktok.com/learn/guides/visual-scripting/

上記ガイドページの最初にある動画を見るだけでもなんとなく把握できました。
ノードベースのプログラミングとなっていて、変数を使ったり、表情の変化などをトリガーとする処理を記述したりできるようです。

実際にビジュアルスクリプティングウィンドウ内で副ボタンクリックしてノードの一覧を開くと、分岐条件を決めるLogic、分岐するControl、数値計算を行うMath、頭の動きや表情の変化を検出するHead & Faceなどがあり、インプットとアウトプットの型も定まっているので、ドキュメントはそれほど見ずとも感覚的にプログラミングできそうでした。

![スクリーンショット 2023-12-15 2.43.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/946826c0-83ab-5a29-4131-edf18fd1a1a6.png)

# 何を作るか

ここまでの機能が揃っていれば、根気さえあれば本当になんでも作れそうに思えます。

しかし、利用可能なノードを一通り眺めて致命的な問題に気づきました。
テキスト出力するノードがないのです。

Text Objectはあり、変数の型としてStringもあり、他の型の値をString型に変換するノードもあるのですが、Text ObjectにStringをセットする方法がないのです。

どうして。

![スクリーンショット 2023-12-15 2.54.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/c3a3bbdb-e8e9-24c6-f99a-47f841fae8db.png)

![スクリーンショット 2023-12-15 2.53.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/b95c0ce6-ef4b-475d-5f62-2d0494bd5505.png)

たぶんビジュアルスクリプト内ではオブジェクトを種類によらず抽象的なオブジェクトとしてしか取り扱っていないので、個別のプロパティにアクセスする方法がまだ提供されていないのかなと思いますが、これは残念。

そんなわけで、本当はTikTok「で」プログラミングというタイトルの通り、Brainf*ckとかのTikTok実装を作って本当にTikTokエフェクト内でプログラミングできるようにしようかとも思っていたのですが、
Stringが扱えないのではHello, World!を表示するのにすら54文字の表示を12文字分=最低でも648個以上のオブジェクトを用意して出し分ける必要が出てくることが目に見えているので、この記事を投稿する2日前に作り始めた状態では到底間に合いません。

そこで、今回は渋々ながら、そこそこプログラミングぽくてすぐに作れそうということで、電卓を作ることにしました。

# 電卓になるTikTokエフェクトをつくる

ここからはStep by Stepで電卓エフェクトを実装した手順を順に解説していきます。

## 数値の表示方法

電卓にしたとはいえ、数字の表示が必要なことには変わりありません。

数字なので文字は10個に減りましたが、すぐに思いつく10個のText Objectを用意してSet visibillityでどれか1つを表示するような制御はなかなか骨が折れます。

そこで、なんかいい方法ないのかなとEffect Houseのページ内検索を漁っていたところ、以下のゲームスコアを表示するライブラリが公開されているのを発見しました!

https://effecthouse.tiktok.com/learn/library/microjam/scoreboard#display-the-score

勝ちましたわ。
サブグラフという形にすることで、ノードのまとまりをライブラリ的に使い回せるようにラッピングできるみたいですね。
作ってくれた方に感謝。

ということで、これを使って数字は表示していくことにしたので、マイナスや5桁以上の数値、3項以上の演算は一旦扱わないこととしました。

## シーンの作成

まずは電卓のUIを決めます。

先述のゲームスコアのライブラリを使って実装するため、そのページにあったサンプルのプロジェクトファイルをベースにシーンを作成していきます。

タップ操作を検知することもできるのですが、せっかくTikTokエフェクトで作成するので、今回はジェスチャーで画面に触れることなく操作できるようにしたいと思います。

そのため、UIにはボタンなどは置かず、シンプルに第一項、演算子、第二項、答えの表示だけを用意します。

スコア表示部分は単にScoreboardのグループオブジェクトとアセットをコピーして第二項と答え用の表示を追加しました。

![スクリーンショット 2023-12-15 12.19.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/67883e74-f3ed-f24a-7b27-8e3913a86772.png)

![visible.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/09d79f13-32c3-2548-68dc-4f3b8fbf5d7e.jpeg)

演算子はText Objectで+, -, ×, ÷の記号を出して同じ位置に重ねています。

第一項、演算子、第二項を一気に入力するのは難しいので、順に設定していく想定でそれぞれのオブジェクトの左側に入力中の値を示す黄色いカーソルも用意しました。

このカーソルも面倒だったのでText Objectで「▶︎」を表示しているだけです。

## 状態遷移設計

扱えるジェスチャーを一通り見たところ、頭を動かすジェスチャーがわかりやすく誤検知も少なそうだったので、これを使っていこうと思います。

凝ったUXを考えている時間もないので、シンプルに第一項入力、演算子入力、第二項入力、答えの表示の4つの状態を作り、その間を「頷き」で遷移、数値と演算子は首を左右に傾げることで選択、という形にしてみました。

![無題の図形描画 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/d21b0459-596e-89c1-80ed-db93ef4eb45b.png)

ゲームなどでよくあるカーソル操作を首の動きに置き換えたような形ですね。

## 初期化の実装

いよいよここからスクリプティングに入ります。

まずは、状態遷移を管理するために変数「Status」を作成し、エフェクトの開始時と録画の開始時に初期化するようにします。

![reset_status.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/10226af6-e4c0-23e7-7dda-6e1c5eab69a8.jpeg)

StartやUpdateが用意されていることから裏でゲームループが回っていることがわかりますが、そのStartやUpdateもフックのような形で用意されている点が特徴的です。

CやJavaなどのよくある手続き型のプログラミング言語ではmainなどの名前のエントリーポイントが1つだけあり、そこからすべての処理がひと繋がりで記述されていきますが、TikTokエフェクトではすべての処理がフックから始まるので、処理タイミングごとに独立した複数のプログラムのまとまりが作成されるような形になります。

感覚としてはJavaScriptでaddEventListenerのみを使ってプログラミングをしているような感じでしょうか。

Startもあくまでもエフェクトの開始時に実行される処理を設定するだけのノードなので、開始時に実行する処理が複数存在する場合には、Startノードを複数作成することになります。

ただ、その形で全てプログラミングしようとするとノードの集まり間の実行順は指定できず、実質全てのノードが同時に実行されているような定義になるので、複数の処理を逐次的に実行したい場合はSequenceノードを使用する必要が出てきます。
(今回は使いませんでしたが)

## 設定項目変更の実装

次に、頷きを検出するためにHead Movement Detectionのノードを追加します。
頷く度にステータスを遷移し、最後のステータスに到達した場合はまた最初のステータスに戻したいので、各ステータスを0~3で表し、Mod 4で4回目の頷きの際にStatusが0に戻るようにします。

![head_move.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/a43a454e-d83b-b9e5-0bc0-43a1078aad34.jpeg)

ここも、手続き型プログラミングであれば

1. 頷きの検出
1. Statusの値の取得
1. Statusのインクリメント
1. Mod計算
1. Statusへのセット

と全ての処理が逐次的に処理されるのに対して、TikTokエフェクトでは副作用部分 (頷きの検出とStatusへのセット) は逐次的に実行されるものの、副作用のない計算処理については逐次処理とは別で計算されて値が使用されているような見え方となっています。

実際に内部でゲームループが回るごとに値が計算されているのか、Statusの設定時に値が必要になったタイミングで計算されているのかまでは理解できていませんが、遅延評価なのだとすると副作用のない部分は宣言型プログラミングに近いようなものを感じます。

## カーソルの実装

次に第一項、演算子、第二項それぞれどれを設定しているのかを表すカーソルの表示・非表示を切り替えられるようにします。

これはほぼビジュアルスクリプティングのガイドページの動画の通りで、Ifを使ってStatusが特定の値の場合だけ表示されるように制御する点だけが違いです。

![スクリーンショット 2023-12-15 2.20.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/d6bf0fd9-4e07-aac1-41bc-7943c88d48e0.png)

operatorは演算子のカーソルを表すText Objectです。

Statusの取得だけではフックが走らないため、毎回の画面描画ごとにStatusを確認して表示/非表示を切り替えるようにUpdateをフックとしている点がちょっと普段のプログラミングからすると分かりづらい点かもしれません。

全く同様の内容で紐付けるText ObjectとEqual Numberで判定するStatusの値だけを変えたものを他2つのカーソル分も作成します。

## 数値設定の実装

次は数値の設定です。

数値の設定には首を傾げるジェスチャーを当てますが、これは右に傾げたか左に傾げたかを区別できるので、右の場合は値を増やし、左の場合は値を減らす形で、カウントアップ/ダウンで数値を設定できるようにしました。

ここはScoreboardのサブグラフが便利なインターフェースを提供してくれているので、それほど難しいところはなく実装できます。
エフェクトの開始時に0にセットし、この数値を設定中のステータスの際に右に傾げたらインクリメント、左に傾げたらデクリメントするだけですね。

![スクリーンショット 2023-12-15 12.38.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/346f37bf-9cbb-596a-3ad1-9b6a589b16c8.png)

なお、設定したい数値の回数だけ首を傾げないといけない仕様にしてしまうと首がやられると思うので、傾げている間は数値が増減し続けるようにStay Execを使いました。

愚直に実装するとこれを第一項用と第二項用の2つ作ることになりますが、せっかくなので今回はサブグラフという機能を使ってまとめるようにしました。
関数のような機能ですね。

サブグラフを追加すると入力と出力のノードがある新しいグラフページが作成されます。
使い方はまあ、直感的にわかりますよね。

![スクリーンショット 2023-12-15 13.08.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/20f4cd14-bd37-fea0-82a9-e3ffa5e41114.png)

ということで、カーソル表示の部分も含めて数値設定周りをまとめてサブグラフにしたものがこちらです。

![スクリーンショット 2023-12-15 2.20.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/3466cd76-5a3d-5e5a-11af-0f8899a0a629.png)

このサブグラフが担うStatusと表示に使用する各位の数値を表すTexture2D、表示を切り替えるカーソルのText Objectを受け取ってカーソルの表示・非表示と数値の増減を制御し、数値が変わった際にはそれを出力する形となっています。

このサブグラフ自体をコピペして2つ並べ、第一項と第二項をそれぞれ設定できるようにしました。

![スクリーンショット 2023-12-15 2.20.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/f00399f9-22d5-ab3c-5fee-7a9b1904c6ff.png)

## 演算子選択の実装

次は演算子選択ですが、ここはライブラリが使用できないので、一番面倒なところになります。

とはいってもそんなに難しい部分はなく、首を傾げるフックから現在のStatusの値が1(=演算子設定状態)かどうかを確認して、演算子の種類を表すOperator変数を増減している部分は数値設定とほぼ同じになります。

![operator.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/7150b806-84ca-ab52-1621-e72f2c0d4baf.jpeg)

今回用意する演算子は4つなので、0~3の値となるように増加時にはMod 4を掛け、逆に0より小さくなった場合は4から引いた値にすることで逆順に選択できるようにしています。

Operator変数の値の設定後に、その値を元に表示を制御する部分も作ります。

![show_operator.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/8ea025ec-5edd-d09e-ae22-e6fb7dfba58f.jpeg)

まずすべての演算子の表示をOFFにしてから、1未満なら+、1以上2未満なら-、2以上3未満なら×、3以上なら÷の表示をONにします。

首を傾げてOperatorの値を設定する部分が1ずつ増加する形だと変化が早すぎて目的の演算子を選びづらくなってしまうので、0.1ずつ増加して幅を持たせて演算子を決定するようにしています。

## 結果計算の実装

最後に実際の計算部分の実装です。
設定項目を決めるStatus変数の値の変更後に、3(=結果を表示するステータス)の場合は計算結果を表示するように実装します。

まずはStatusが3でないときには結果のScoreboardを非表示、3のときだけ表示するようにします。
Scoreboardの初期化も行っておきます。

![スクリーンショット 2023-12-15 2.21.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/36bb40f4-a3ab-6fe5-84fd-bfe7305bb088.png)

その上で、Statusが3の場合は計算結果をScoreboardに表示します。

![スクリーンショット 2023-12-15 16.46.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/c2700966-3dae-ed00-e971-adfb7164fc35.png)

ここでは新しく、UtilityのSelectというノードを使用して、加算・減算・乗算・除算のどの計算結果を使用するのかを判定しています。
演算子の表示部分と同じようにIfで分岐して記述することもできますが、Ifが分岐するのは値ではなく処理順になるため、分岐の数だけScoreboardを用意する必要が出てきてしまうので、ここではSelectを使用しています。

また、第一項と第二項の値を取得する際とOperatorの値を取得する際に、それぞれの値は少数値となっているため、Floorで小数点以下を切り捨てる操作を行っている点にも注意が必要です。

ということで、これで全てのスクリプティングが完了しました!

![スクリーンショット 2023-12-15 16.51.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/13015d37-c700-a0b9-0aac-d6a1d0a1cd7a.png)

# デモ

できたエフェクトを実際に自分で試してみたデモがこちらです!

![movie.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/f1a9342b-0ef6-8cb2-248f-ddc142ea0e0c.gif)

本当は実際にTikTok上に投稿してみたかったのですが、公開までの審査に1~3営業日かかるとのことで、まだ審査中のため、TikTokアプリで試せる機能で試して動画を撮影しました。

# おわりに

いかがだったでしょうか。
今回はTikTok Effect Houseで電卓アプリを作ってみましたが、これだけでもEffect Houseのビジュアルスクリプティングでかなり色々なことができることがわかったのではないでしょうか?
私自身もせっかく一通り作り方がわかったので、またエフェクト作成してみたいなと思っています!

BitStarではTikTokも含むSNSで活躍するクリエイターの方々とのタイアップ実施を支援するBitStar Matchの開発に携わっていただけるエンジニアを積極募集中です!

ご興味のある方はぜひ以下の募集情報をご確認いただければと思います。

[![スクリーンショット 2023-12-04 13.18.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15280/08659eb4-7559-401b-1333-29127fe1faca.png)](https://www.wantedly.com/projects/1508637)

最後までご覧くださりありがとうございました!