Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9145

React Nativeでイカゲーム!

$
0
0
(1)はじめに 普段はソーシャルワーカーとして障がいをお持ちの方の支援をしています。Advent Calendarに合わせてバージョンアップさせてきたReact Nativeでの3D表示について、今回で仕上げの投稿になります。前回はReact NativeでSocket通信しようで3DキャラクターをSocket通信でマルチプレイができるコードを紹介しました。今回はイカゲームに出てくる、だるまさんが転んだの要素(イカゲームの流行に乗っただけ)を追加して完成にしたいと思います。 大きな敵キャラクターが振り向いたときに、自身のキャラクターが動いているとアウトとなり初期位置に戻ります。githubで公開しましたので、ご興味のある方はどうぞ。 gl.pixelStorei() doesn't support this parameter yet! from TextureLoader が出ますのでnode_modulesにある/three/build/three.js 16527行目からの下記3行をコメントアウトしてください。 ※github expo-threeのissue#196参照 // _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha); // _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, texture.unpackAlignment); // _gl.pixelStorei(_gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, _gl.NONE); (2)Socket通信のサーバーに機能追加 まずは前回のnodejsコードに、一定間隔でtureを送るコードを追記します。Math.floor関数とMath.random関数を使い5~8(0~3 + 5)の整数を返し、それに1000ミリ秒乗算し、setTimeout関数の間隔を設定します。これでアプリ側に5秒から8秒間隔でランダムにtrueを送信することができます。このtrueをアプリが受信すると敵キャラクターが振り向きます。 function enemy() { io.emit("Enemy", true); } (function loop() { let random = (Math.floor(Math.random() * 3) + 5) * 1000; setTimeout(() => { enemy(); loop(); }, random); })(); Expoからnodejsアプリ(上記githubのserverフォルダ内)にアクセスする方法について、windowsであれば設定の「ネットワークとインターネット」からwifiのプロパティにあるIPv4アドレスを設定することでローカルに立てたサーバーにアクセスできます。 const socket = io("http://<IPv4アドレス>:3000"); (3)使った技術 使用するライブラリは前回と一緒です。 ・react-native ・expo 42.0.1 ・expo-gl 10.4.2 ・expo-three 6.0.1 ・gsap 3.6.0 ・three 0.132.0 ← ※バージョンによってはエラーになります ・base-64 1.0.0 ・expo-asset 8.3.3 ・socket.io-client 4.4.0 参考にしたサイト Three.js公式 Expo公式 Mixamo公式 Socket.io公式 blender公式 (4)3Dモデル表示 追加したコードについて説明を記します。敵キャラクターはロイヤリティフリーのMixamoで作成します。振り返る動作をfbx形式でダウンロードしBlenderでスケールを拡大しgbl形式で保存します(testC.gbl)。アニメーションの変数walkCはMixamoで設定されているアニメーションになります。 まだ一部の機能しか使っていませんが、Blenderとても良いです! // 敵のキャラクターを設置 let mixerC; let clockC = new Clock(); const assetC = Asset.fromModule(require("./assets/testC.glb")); await assetC.downloadAsync(); loader.load( assetC.uri || "", (gltf) => { const modelC = gltf.scene; modelC.position.set(0, 0, -40); // 配置される座標 (x,y,z) modelC.rotation.y = Math.PI - 0.7; const animations = gltf.animations; //Animation Mixerインスタンスを生成 mixerC = new AnimationMixer(modelC); // 設定した一つ目のアニメーションを設定 let animation = animations[0]; // アニメーションを変数walkにセット setWalkC(mixerC.clipAction(animation)); // test.glbを3D空間に追加; scene.add(modelC); setModelsC(modelC); }, (xhr) => { console.log("ロード中"); }, (error) => { console.error("読み込めませんでした"); } ; 敵キャラクターが振り向くタイミングについて、先ほど追記したサーバーからの送信されるtrueをsocket.onで受け取ります。 // App.js const [daruma, setDaruma] = useState(false); // サーバーから受信したかどうかをセットする変数 const [stare, setStare] = useState(false); // 自身のキャラクターが動いたらアウトになるタイミングの変数 useEffect(() => { // サーバーのアドレス const socket = io("http://<IPv4アドレス>:3000"); // サーバーからランダムな値を受け取り変数darumaにセット socket.on("Enemy", (data) => { // 敵キャラクターを読み込む前にtrueとなっているためfalseにセットしなおす setDaruma(false); // サーバーから受け取ったtrueをセット setDaruma(data); }); return () => socket.disconnect(); }, [modelsC]); 自身のキャラクターの挙動を実行する関数walkに、変数stareがtrueであれば初期位置に戻るを追加します。 const move = (props) => { walkA.paused = false; // キャラクターのポーズを解除 walkA.play(); // // アニメーションである変数walkを再生 setAction({ z: props.y, x: props.x }); // Position.jsから受け取った座標を変数actionにセット walk(); // walk関数を実行 // 関数moveが実行されているときにdarumaがtrueなら初期座標に戻る if (stare) { TweenMax.set(modelsA.position, { x: 0, y: 0, z: 25, // 中心より手前に初期座標を設定 }); TweenMax.set(cameras.position, { x: 0, y: 2, z: 32, }); walkA.paused = true; send({ x: modelsA.position.x, y: modelsA.rotation.y, z: modelsA.position.z, w: walkA.paused, }); } }; 最後に変数darumaが変化する度にuseEffectで反応させます。敵キャラクターが読み込まれていないとエラーになるので条件式if(modelsC !== null)を設定します。またsetTimeを使って振り向くアニメーションを実行、停止する間隔を2500ミリ秒、アニメーションが実行されて500ミリ秒後に変数stareをtrueにし、自身のキャラクターが動いているとアウトになるタイミングを遅れて開始させます。 useEffect(() => { //darumaがtrueであれば下記を実行する if (daruma) { if (modelsC !== null) { // アニメーション開始 walkC.play(); setTimeout(() => { setStare(true); }, 500); } setTimeout(() => { // 2500ミリ秒後にリセット if (modelsC !== null) { setDaruma(false); setStare(false); // アニメーション停止 walkC.stop(); } }, 2500); } //変数darumaが変化する度に反応する }, [daruma]); (5)終わりに React Nativeでの3D表示について、Advent Calendarに合わせて2週間バージョンアップさせてきました。貴重な機会を利用させていただき感謝します。ほんの少しでもReact Nativeのコミュニティに貢献できたならば嬉しいです。React Native Advent Calendarの皆さんの記事とても勉強になっています

Viewing all articles
Browse latest Browse all 9145

Trending Articles