UnityアプリをDiscordアクティビティとして実装してみる
1.embedded-app-sdkについて
3/18にアクティビティ(Discord上で動くアプリ)を個人で開発できるembedded-app-sdk
が公開されました。
こちらはウェブページをアクティビティとして組み込めるsdkで
nodeで動く環境であれば割となんでも動かせそうです。
なので今回はUnityアプリをWebGLビルドで出力しアクティビティとして組み込みたいと思います。
基本的なDiscordの設定等の内容は既にzennに投稿してくださっている方がいるののでそちらを参考にしてください
2.今回作成するもの
今回はDiscordのユーザー名をUnity上に表示する単純なアプリを作成します。
環境
下記環境での今回の記事は執筆しています。
node v20.11.1
npm 10.2.4
Unity 2022.3.4f1
3.Unityプロジェクトの作成
Unityのバージョンは下記を使用しています。
2022.3.4f1
プロジェクトの作成
プロジェクトをDiscordApp
という名前で作成します。
UIの設置
下記のような形で名前を表示するUIを作成します。
テキスト変更用のスクリプトを作成
- C#スクリプトを
NameViewer.cs
という名前で作成 - 下記のスクリプトを記述
using TMPro;
using UnityEngine;
public class NameViewer : MonoBehaviour
{
public void SetText(string text)
{
var textUi = GetComponentInChildren<TextMeshProUGUI>();
textUi.text = text;
}
}
- Canvasにスクリプトをアタッチ
プロジェクトの出力
- プロジェクト設定→Player→WebGLの設定→圧縮形式を
無効
に変更する
- WebGLビルドで出力
今回はDiscordApp
という名前でディレクトリを作成し、そこに出力しました。
下記の通りに出力されました。
DiscordApp/
├── Build/
├── TemplateData/
└── index.html
4.Reactプロジェクトの作成
次に出力したUnityアプリを今回はReact
上に表示したいと思います。
プロジェクトはembedded-app-sdk
のチュートリアルでも用いられたvite
を使用します。
それとUnityアプリをReact上に表示するために下記ライブラリを使用します。
viteでのプロジェクトの作成
- 親ディレクトリを
discord-unity-app
という名前で作成します。 -
discord-unity-app
ディレクトリ内で下記コマンドを実行します
$ npm create vite@latest client -- --template react-swc-ts
$ cd client
$ npm i
$ npm i react-unity-webgl
$ npm i @discord/embedded-app-sdk
3.discord-unity-app/client/public
下に出力したUnityアプリを配置
下記の様な配置になりました。
discord-unity-app/client/public/
├── Build/
├── TemplateData/
├── index.html
└── vite.svg #vite生成時に生成されたアイコン
Unityアプリを表示するためのコンポーネントを作成
-
discord-unity-app/client/src/
下にUnityComponent.tsx
という名前でコンポーネントを作成 -
UnityComponent.tsx
に下記を記述
import { useEffect } from "react";
import { Unity, useUnityContext } from "react-unity-webgl";
interface UnityCompoonentProps {
userName: string;
}
const UnityComponent = (props: UnityCompoonentProps) => {
// UnityContextを準備、表示するUniyアプリを指定
const { unityProvider, sendMessage, isLoaded } = useUnityContext({
loaderUrl: "Build/DiscordApp.loader.js",
dataUrl: "Build/DiscordApp.data",
frameworkUrl: "Build/DiscordApp.framework.js",
codeUrl: "Build/DiscordApp.wasm",
});
// useEffectの対象にisLoadedを含めない場合
// 環境によってはsendMessageが動作しない問題がある
useEffect(() => {
if (isLoaded) {
// Unityアプリに対してメッセージを送信
// sendMessage("オブジェクト名", "関数名", 引数)
sendMessage("Canvas", "SetText", props.userName);
}
}, [isLoaded]);
return <Unity id="unity-canvas" unityProvider={unityProvider} />;
};
export default UnityComponent;
-
client/src/App.tsx
を下記のように変更
import UnityComponent from "./UnityComponent";
function App() {
return <UnityComponent userName={"test"} />;
}
export default App;
-
client/src/index.css
に下記のように変更
body {
margin: 0;
overflow: hidden;
}
#unity-canvas {
width: 100vw;
height: 100vh;
}
-
client
ディレクトリ内で下記コマンドを実行
$ npm run dev
表示されるURLにアクセスし下記のような表示がされれば成功
Discordアクティビティとして動かすために処理を追加
-
discord-unity-app
ディレクトリ下にgetting-started-activity
リポジトリ[1]の一部ファイルを追加
server
ディレクトリとexample.env
をdiscord-unity-app
に配置後、
example.env
を.env
に変更する
下記の様な配置になりました。
discord-unity-app
├── client/
├── server/
└── .env
-
.env
ファイルとsever
ディレクトリ内をセットアップする
冒頭に紹介した記事を参考にしてください -
discord-unity-app/client/vite.config.ts
を下記のように変更
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
envDir: "../",
server: {
proxy: {
"/api": {
target: "http://localhost:3001",
changeOrigin: true,
secure: false,
ws: true,
},
},
hmr: {
clientPort: 443,
},
},
});
-
discord-unity-app/client/App.tsx
を下記のように変更
import { useEffect, useState } from "react";
import UnityComponent from "./UnityComponent";
import { DiscordSDK } from "@discord/embedded-app-sdk";
function App() {
let auth;
const discordSdk = new DiscordSDK(import.meta.env.VITE_DISCORD_CLIENT_ID);
const [userName, setUserName] = useState("");
useEffect(() => {
setupDiscordSdk();
}, []);
async function setupDiscordSdk() {
await discordSdk.ready();
// Discordクライアントの認証
const { code } = await discordSdk.commands.authorize({
client_id: import.meta.env.VITE_DISCORD_CLIENT_ID,
response_type: "code",
state: "",
prompt: "none",
scope: ["identify"],
});
// サーバーからaccess_tokenを取得
const response = await fetch("/api/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
code,
}),
});
const { access_token } = await response.json();
// access_tokenを用いた認証
auth = await discordSdk.commands.authenticate({
access_token,
});
if (auth == null) {
console.log("Authenticate command failed");
throw new Error("Authenticate command failed");
}
// ユーザー情報の取得
const user: { username: string } = await fetch(
`https://discord.com/api/users/@me`,
{
headers: {
Authorization: `Bearer ${auth.access_token}`,
"Content-Type": "application/json",
},
}
).then((reply) => reply.json());
// ユーザー名の設定
setUserName(user.username);
}
return <UnityComponent userName={userName} />;
}
export default App;
5.アクティビティの起動
冒頭に紹介した記事を参考にDiscordアクティビティを起動
下記のような表示がされれば成功
デバッグについて
PTBまたはCanary版のいずれかであれば開発者ツールが以下のショートカットで開けます
Ctrl + Shift + I
⌥+⌘+I
-
getting-started-activity
リポジトリはembedded-app-sdk
のチュートリアルプロジェクトのようなもので冒頭で紹介したzennの記事でも使用している ↩︎
Discussion