Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

JavaScriptBridge 싱글톤

웹 빌드에서 JavaScriptBridge 싱글톤는 JavaScript 및 웹 브라우저와의 상호 작용을 허용하고 웹 플랫폼에 고유한 일부 기능을 구현하는 데 사용할 수 있습니다.

쿼터니언(quaternions) 으로 보간하기

때로는 웹용 Godot를 내보낼 때 제3자 SDK, 라이브러리와 같은 외부 JavaScript 코드와 인터페이스하거나 단순히 Godot에서 직접 노출되지 않는 브라우저 기능에 액세스해야 할 수도 있습니다.

JavaScriptBridge 싱글톤는 Godot 스크립팅(예: GDScript 및 C#)의 맥락에서 자연스러운 느낌을 주려고 하는 Godot :ref:`JavaScriptObject <class_JavaScriptObject>`에 기본 JavaScript 객체를 래핑하는 방법을 제공합니다.

JavaScriptBridge.get_interface() 메서드는 전역 범위에서 객체를 검색합니다.

extends Node

func _ready():
    # Retrieve the `window.console` object.
    var console = JavaScriptBridge.get_interface("console")
    # Call the `window.console.log()` method.
    console.log("test")

JavaScriptBridge.create_object() <class_JavaScriptBridge_method_create_object>`는 JavaScript ``new` 생성자를 통해 새 객체를 생성합니다.

extends Node

func _ready():
    # Call the JavaScript `new` operator on the `window.Array` object.
    # Passing 10 as argument to the constructor:
    # JS: `new Array(10);`
    var arr = JavaScriptBridge.create_object("Array", 10)
    # Set the first element of the JavaScript array to the number 42.
    arr[0] = 42
    # Call the `pop` function on the JavaScript array.
    arr.pop()
    # Print the value of the `length` property of the array (9 after the pop).
    print(arr.length)

보시다시피 JavaScript 개체를 ``JavaScriptObject``로 래핑하면 기본 Godot 개체인 것처럼 상호 작용하고 메서드를 호출하고 속성을 검색(또는 설정)할 수 있습니다.

기본 유형(int, float, string, boolean)은 자동으로 변환됩니다(float는 Godot에서 JavaScript로 변환할 때 정밀도가 떨어질 수 있습니다). 다른 것(예: 객체, 배열, 함수)은 JavaScriptObjects 자체로 표시됩니다.

단점

Godot에서 JavaScript 코드를 호출하는 것은 좋지만 때로는 대신 JavaScript에서 Godot 함수를 호출해야 할 때도 있습니다.

이 경우는 좀 더 복잡합니다. JavaScript는 가비지 수집에 의존하는 반면 Godot는 메모리 관리를 위해 참조 계산을 사용합니다. 즉, 콜백(JavaScriptObjects 자체로 반환됨)을 명시적으로 생성해야 하며 해당 참조를 유지해야 합니다.

JavaScript가 콜백에 전달한 인수는 단일 Godot ``Array``로 전달됩니다.

extends Node

# Here we create a reference to the `_my_callback` function (below).
# This reference will be kept until the node is freed.
var _callback_ref = JavaScriptBridge.create_callback(_my_callback)

func _ready():
    # Get the JavaScript `window` object.
    var window = JavaScriptBridge.get_interface("window")
    # Set the `window.onbeforeunload` DOM event listener.
    window.onbeforeunload = _callback_ref

func _my_callback(args):
    # Get the first argument (the DOM event in our case).
    var js_event = args[0]
    # Call preventDefault and set the `returnValue` property of the DOM event.
    js_event.preventDefault()
    js_event.returnValue = ''

경고

JavaScriptBridge.get_interface() <class_JavaScriptBridge_method_get_interface>`(위 예에서는 ``_my_callback`)를 통해 생성된 콜백 메서드 반드시 정확히 하나의 Array 인수를 취해야 하며, 이는 JavaScript `인수 개체 <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments>`__가 배열. 그렇지 않으면 콜백 메서드가 호출되지 않습니다.

다음은 사용자에게 `알림 권한 <https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API>`__을 요청하고 권한이 부여되면 알림을 전달하기 위해 비동기적으로 기다리는 또 다른 예입니다.

extends Node

# Here we create a reference to the `_on_permissions` function (below).
# This reference will be kept until the node is freed.
var _permission_callback = JavaScriptBridge.create_callback(_on_permissions)

func _ready():
    # NOTE: This is done in `_ready` for simplicity, but SHOULD BE done in response
    # to user input instead (e.g. during `_input`, or `button_pressed` event, etc.),
    # otherwise it might not work.

    # Get the `window.Notification` JavaScript object.
    var notification = JavaScriptBridge.get_interface("Notification")
    # Call the `window.Notification.requestPermission` method which returns a JavaScript
    # Promise, and bind our callback to it.
    notification.requestPermission().then(_permission_callback)

func _on_permissions(args):
    # The first argument of this callback is the string "granted" if the permission is granted.
    var permission = args[0]
    if permission == "granted":
        print("Permission granted, sending notification.")
        # Create the notification: `new Notification("Hi there!")`
        JavaScriptBridge.create_object("Notification", "Hi there!")
    else:
        print("No notification permission.")

내가 좋아하는 도서관을 이용할 수 있나요?

아마도 그럴 수 있을 것입니다. 먼저 페이지에 라이브러리를 포함해야 합니다. 내보내는 동안 :ref:`Head 포함 <doc_javascript_export_options>`을 사용자 정의하거나(아래 참조) :ref:`자신만의 템플릿 <doc_customizing_html5_shell>`을 작성할 수도 있습니다.

아래 예에서는 Head Include``를 사용자 정의하여 콘텐츠 전송 네트워크에서 외부 라이브러리(`axios <https://axios-http.com/>`__)를 추가하고 번째 ``<script> 태그를 사용자 정의 기능을 정의합니다.

<!-- Axios -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- Custom function -->
<script>
function myFunc() {
    alert("My func!");
}
</script>

그런 다음 이전 예제에서 했던 것처럼 Godot의 라이브러리와 함수 모두에 접근할 수 있습니다:

extends Node

# Here create a reference to the `_on_get` function (below).
# This reference will be kept until the node is freed.
var _callback = JavaScriptBridge.create_callback(_on_get)

func _ready():
    # Get the `window` object, where globally defined functions are.
    var window = JavaScriptBridge.get_interface("window")
    # Call the JavaScript `myFunc` function defined in the custom HTML head.
    window.myFunc()
    # Get the `axios` library (loaded from a CDN in the custom HTML head).
    var axios = JavaScriptBridge.get_interface("axios")
    # Make a GET request to the current location, and receive the callback when done.
    axios.get(window.location.toString()).then(_callback)

func _on_get(args):
    OS.alert("On Get")

번역 형식

웹 빌드에서 JavaScript 싱글톤이 구현됩니다. eval이라는 하나의 메서드를 제공하는데, 같은 이름의 JavaScript 함수와 비슷하게 작동합니다. 문자열을 인수로 가지며 JavaScript 코드로 실행합니다. 이걸로 Godot와 통합될 수 없는 스크립트 언어를 브라우저와 상호작용할 수 있게됩니다.

func my_func():
    JavaScriptBridge.eval("alert('Calling JavaScript per GDScript!');")

마지막 JavaScript 명령문의 값은 GDScript 값으로 변환되며 특정 경우에 eval()에 의해 반환됩니다:

  • JavaScript number는 GDScript에서 float로 반환됨

  • JavaScript boolean은 GDScript에서 bool로 반환됨

  • JavaScript stringGDScript에서 String으로 반환됨

  • JavaScript ArrayBuffer, TypedArray 그리고 DataView는 GDScript에서 class_PoolByteArray로 반환됨

func my_func2():
    var js_return = JavaScriptBridge.eval("var myNumber = 1; myNumber + 2;")
    print(js_return) # prints '3.0'

다른 JavaScript 값은 null로 반환됩니다.

HTML5 내보내기 템플릿은 보안성을 위해 싱글턴을 지원하지 않고 빌드되었을 수 있습니다. 그런 템플릿의 경우 HTML5 이외의 플랫폼에서 JavaScript.eval를 호출하면 null을 반환합니다. 싱글턴의 지원여부는 아래와 같이 JavaScript 기능 태그로 확인할 수 있습니다:

func my_func3():
    if OS.has_feature('web'):
        JavaScriptBridge.eval("""
            console.log('The JavaScriptBridge singleton is available')
        """)
    else:
        print("The JavaScriptBridge singleton is NOT available")

my_func3() 처럼 3개의 큰따옴표 """ 로 둘러싸인 GDScript의 멀티라인 문자열은 JavaScript 코드의 가독성을 높이는데 유용합니다.

eval 메서드는 두번째 옵션인 Boolean 인자도 받으며 이 인자는 전역 실행 컨텍스트에서 코드를 실행하는 것들을 지정합니다, 전역 네임스페이스가 오염되지않기 위해 기본적으로 false입니다:

func my_func4():
    # execute in global execution context,
    # thus adding a new JavaScript global variable `SomeGlobal`
    JavaScriptBridge.eval("var SomeGlobal = {};", true)

다운로드

Godot 웹 내보내기에서 사용자 컴퓨터로 파일(예: 저장 게임)을 다운로드하는 것은 JavaScript와 직접 상호 작용하여 수행할 수 있지만 매우 일반적인 사용 사례인 경우 Godot는 생성된 버퍼를 다운로드할 수 있는 전용 JavaScriptBridge.download_buffer() 함수를 통해 이 기능을 스크립팅에 노출합니다.

어떻게 작동하는 지의 예제입니다:

extends

func _ready():
    # Asks the user download a file called "hello.txt" whose content will be the string "Hello".
    JavaScriptBridge.download_buffer("Hello".to_utf8_buffer(), "hello.txt")

다음은 이전에 저장한 파일을 다운로드하는 방법에 대한 보다 완전한 예입니다.

extends Node

# Open a file for reading and download it via the JavaScript singleton.
func _download_file(path):
    var file = FileAccess.open(path, FileAccess.READ)
    if file == null:
        push_error("Failed to load file")
        return
    # Get the file name.
    var fname = path.get_file()
    # Read the whole file to memory.
    var buffer = file.get_buffer(file.get_len())
    # Prompt the user to download the file (will have the same name as the input file).
    JavaScriptBridge.download_buffer(buffer, fname)

func _ready():
    # Create a temporary file.
    var config = ConfigFile.new()
    config.set_value("option", "one", false)
    config.save("/tmp/test.cfg")

    # Download it
    _download_file("/tmp/test.cfg")