참고
- https://react-unity-webgl.dev/docs/api/event-system
리액트에서 Unity 함수를 호출하였으므로, 반대로 Unity에서 React의 state를 변경해보자.
유니티 구현
OnMouseOver를 추가하여 왼쪽으로 클릭하면 속도가 빨라지게, 오른쪽으로 클릭하면 느려지게 구현한다.
private void OnMouseOver()
{
if(Input.GetMouseButtonDown(0))
{
Debug.Log("Left, Speed Up");
unitySpeedUp(5.0f);
return;
}
if (Input.GetMouseButtonDown(1))
{
Debug.Log("Right, Speed Down");
unitySpeedDown(5.0f);
return;
}
}
reactSpeedUp/Down은 react에서 변수를 증가시키거나 감소시킨다.
구체적인 구현은 react에서 하기 때문에 extern으로 선언한다.
[DllImport("__Internal")]를 사용하기 위해 InteropServices를 선언한다.
using System.Runtime.InteropServices;
public class Test : MonoBehaviour
{
...
[DllImport("__Internal")]
private static extern void reactSpeedUp(float curSpeed, float value);
[DllImport("__Internal")]
private static extern void reactSpeedDown(float curSpeed, float value);
unitySpeedUp/Down은 아래와 같이 구현한다.
실제 유니티 오브젝트의 speed를 변경하고, WebGL에서는 react 함수도 호출하도록 구현한다.
public void unitySpeedUp(float value)
{
#if UNITY_WEBGL == true && UNITY_EDITOR == false
reactSpeedUp(rotateSpeed, value);
#endif
rotateSpeed = rotateSpeed + value;
}
public void unitySpeedDown(float value)
{
#if UNITY_WEBGL == true && UNITY_EDITOR == false
reactSpeedDown(rotateSpeed, value);
#endif
rotateSpeed = rotateSpeed - value;
}
전체 스크립트는 다음과 같다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
public class Test : MonoBehaviour
{
bool rotating = true;
float rotateSpeed = 30.0f;
Vector3 offset, rotation;
[DllImport("__Internal")]
private static extern void reactSpeedUp(float curSpeed, float value);
[DllImport("__Internal")]
private static extern void reactSpeedDown(float curSpeed, float value);
public void changeRotate()
{
rotating = rotating ? false : true;
}
public void unitySpeedUp(float value)
{
#if UNITY_WEBGL == true && UNITY_EDITOR == false
reactSpeedUp(rotateSpeed, value);
#endif
rotateSpeed = rotateSpeed + value;
}
public void unitySpeedDown(float value)
{
#if UNITY_WEBGL == true && UNITY_EDITOR == false
reactSpeedDown(rotateSpeed, value);
#endif
rotateSpeed = rotateSpeed - value;
}
private void OnMouseOver()
{
if(Input.GetMouseButtonDown(0))
{
Debug.Log("Left, Speed Up");
unitySpeedUp(5.0f);
return;
}
if (Input.GetMouseButtonDown(1))
{
Debug.Log("Right, Speed Down");
unitySpeedDown(5.0f);
return;
}
}
void Update()
{
if (rotating)
{
offset = Vector3.one;
rotation.y = -(offset.x + offset.y) * Time.deltaTime * rotateSpeed;
transform.Rotate(rotation);
}
}
}
Plugin 만들기
구현만 해서는 안되고 함수를 내보내기 위해서는 플러그인이 필요하다.
먼저 Assets/Plugins/WebGL 폴더를 만든다.
그리고 Show in Explorer를 클릭하자.
메모장이나 EditPlus 등을 이용하여 아래와 같이 jslib 파일을 만든다.
파일 이름은 원하는 대로 만들 수 있다.
jslib에서 아래와 같이 코드를 작성해야 Unity → 자바스크립트 함수를 호출할 수 있게 된다.
위에서 extern했던 reactSpeedUp, reactSpeedDown 그리고 변수명을 넣어주었다.
파일을 정상적으로 저장하였다면 유니티에서 아래와 같이 플러그인이 생성된 것을 알 수 있다.
리액트 구현
useState로 speed( = rotateSpeed)를 선언한다.
유니티에서 초기 속도가 30.0f였기 때문에 30으로 초기화하였다.
const [speed, setSpeed] = useState(30.0);
useUnityContext 에서는 add/removeEventListener를 추가한다.
const {
unityProvider,
sendMessage, // unity 함수를 호출하기 위한 sendMessage 추가
addEventListener, // unity -> react 통신
removeEventListener, // unity -> react 통신
UNSAFE__detachAndUnloadImmediate: detachAndUnloadImmediate,
} = useUnityContext({
loaderUrl: "build/html-hosting.loader.js",
dataUrl: "build/html-hosting.data",
frameworkUrl: "build/html-hosting.framework.js",
codeUrl: "build/html-hosting.wasm",
});
리액트에서는 속도를 보기만 할 뿐이므로, 아래와 같이 setSpeed로 speed의 값만 변경한다.
const setSpeedUp = useCallback((curSpeed, value) => {
setSpeed(curSpeed + value);
}, []);
const setSpeedDown = useCallback((curSpeed, value) => {
setSpeed(curSpeed - value);
}, []);
위의 speed의 변화를 p 태그로 추가하면 된다.
<p>{`speed : ${speed}`}</p>
마지막으로 EventListener들을 useEffect에서 처리하면 된다.
useEffect(() => {
addEventListener("reactSpeedUp", setSpeedUp);
addEventListener("reactSpeedDown", setSpeedDown);
return () => {
detachAndUnloadImmediate().catch((reason) => {
console.log(reason);
});
removeEventListener("reactSpeedUp", setSpeedUp);
removeEventListener("reactSpeedDown", setSpeedDown);
};
}, [
detachAndUnloadImmediate,
addEventListener,
removeEventListener,
setSpeedUp,
setSpeedDown,
]);
전체 코드는 다음과 같다.
import React, { useCallback, useEffect, useState } from "react";
import { Unity, useUnityContext } from "react-unity-webgl";
const Router2 = () => {
const [speed, setSpeed] = useState(30.0);
const {
unityProvider,
sendMessage, // unity 함수를 호출하기 위한 sendMessage 추가
addEventListener, // unity -> react 통신
removeEventListener, // unity -> react 통신
UNSAFE__detachAndUnloadImmediate: detachAndUnloadImmediate,
} = useUnityContext({
loaderUrl: "build/html-hosting.loader.js",
dataUrl: "build/html-hosting.data",
frameworkUrl: "build/html-hosting.framework.js",
codeUrl: "build/html-hosting.wasm",
});
const setSpeedUp = useCallback((curSpeed, value) => {
setSpeed(curSpeed + value);
}, []);
const setSpeedDown = useCallback((curSpeed, value) => {
setSpeed(curSpeed - value);
}, []);
useEffect(() => {
addEventListener("reactSpeedUp", setSpeedUp);
addEventListener("reactSpeedDown", setSpeedDown);
return () => {
detachAndUnloadImmediate().catch((reason) => {
console.log(reason);
});
removeEventListener("reactSpeedUp", setSpeedUp);
removeEventListener("reactSpeedDown", setSpeedDown);
};
}, [
detachAndUnloadImmediate,
addEventListener,
removeEventListener,
setSpeedUp,
setSpeedDown,
]);
return (
<div>
{/* 버튼 추가 */}
<button onClick={() => sendMessage("Cube", "changeRotate")}>
Rotate!!
</button>
<p>{`speed : ${speed}`}</p>
<Unity unityProvider={unityProvider} style={{ width: "50%" }} />
</div>
);
};
export default Router2;
리액트를 실행해서 유니티 오브젝트를 왼쪽/오른쪽 클릭하면 오브젝트의 속도가 변하고
리액트에도 속도(<p> 태그의 speed)가 변경되는 것을 알 수 있다.
Unity Plus:
Unity Pro:
Unity 프리미엄 학습:
'개발 > Unity' 카테고리의 다른 글
유니티 - 세 점을 지나는 평면 구하기 (Creating a Plane from 3 Dots) (0) | 2023.03.27 |
---|---|
유니티 - 스트로보 효과 (Stroboscopic Effect with Unity) (0) | 2023.03.26 |
유니티 - 리액트에서 Unity 오브젝트 컨트롤하기 (Communication from React to Unity) (0) | 2023.03.23 |
유니티 - 라인 렌더러로 그리드 만들기 (Make Grid with LineRenderer) (0) | 2023.01.01 |
유니티 - 컨벡스 헐로 임의의 점을 모두 포함하는 사각형 구하기 (Points in a Rectangle with Convex Hull) (0) | 2022.12.28 |
댓글