JavaScriptBridge in Godot – Complete Guide

Welcome to the exciting world of game development and web interaction in Godot 4! If you’ve ever wanted to take your Godot projects to new heights by integrating with web technologies, you’re in the right place. This tutorial will guide you through the ins and outs of the JavaScriptBridge class, a powerful tool for connecting Godot games with the browser’s JavaScript context upon export. Whether you’re looking to enhance user experiences, access third-party APIs, or simply make your games more interactive on the web, mastering the JavaScriptBridge can open up a world of possibilities.

What is JavaScriptBridge?

JavaScriptBridge in Godot 4 is a singleton that makes the impossible possible, merging the rich world of web technologies with the limitless creativity of game development. It acts as a conduit, allowing your Godot games to communicate with and manipulate the web environment it resides in post-export.

What is it for?

Imagine seamlessly integrating social sharing features, connecting to external databases, or even harnessing the capabilities of other JavaScript libraries directly within your game. JavaScriptBridge makes this a reality. It also helps in creating Progressive Web Applications (PWAs) by handling updates and offering functionalities specific to web capabilities.

Why Should I Learn It?

The digital era is all about interaction and connectivity. By learning how to use the JavaScriptBridge, you’re not only enhancing your games but also future-proofing your skills. With this knowledge, you can create more dynamic, responsive, and interactive experiences for players, standing out in the vast sea of online content. It’s all about bringing your creative visions to life in new and innovative ways!

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Getting Started with JavaScriptBridge

Before you can harness the power of JavaScriptBridge, you need to understand how to set it up within your Godot project. Let’s prepare our Godot environment for interacting with JavaScript.

Firstly, you need to enable the JavaScript singleton in your project. This can be done in the Project Settings under the “Application > JavaScript” category. Enable the “Enable JavaScript Singleton” option. After you’ve done this, you can access the JavaScriptBridge via GDScript using the following code:

var javascript = Engine.get_singleton("JavaScript")

With the JavaScriptBridge enabled, let’s create our first interaction by calling a simple JavaScript alert function from Godot:

javascript.eval("alert('Hello from Godot!')")

This command executes the JavaScript alert function, displaying a message box in the web browser.

Exchanging Data Between Godot and JavaScript

Transferring data between Godot and JavaScript opens up endless possibilities. Let’s pass some basic data types from GDScript to JavaScript and vice versa.

Sending a string from Godot to JavaScript could look something like this:

javascript.eval("console.log('This string came from Godot: ' + arguments[0])", ["Hello, JavaScript!"])

This line sends a string to the browser’s console. The `arguments[0]` corresponds to the first element of the array passed to `eval`.

Now, let’s see how to get data back from JavaScript to Godot. We’ll define a JavaScript function and then call it from GDScript:

In a JavaScript file linked to your HTML page, define the function:

window.getSomeData = function() {
    return "Data from JavaScript";
}

In your GDScript, call this function and capture the return value:

var result = javascript.eval("return window.getSomeData();")
print("Received from JavaScript: ", result)

Calling Godot Functions from JavaScript

We can also call functions defined within Godot from the JavaScript context. Here’s how to set that up:

First, define a function in Godot:

func my_godot_function(param):
    print("Called from JavaScript with parameter: ", param)

Expose it to JavaScript using the `javascript.create_callback` method:

var callback_id = javascript.create_callback(self, "my_godot_function")
javascript.eval("window.myGodotFunction = function(param) { Godot.javascript_callback(" + str(callback_id) + ", param); }")

Now, in your browser’s console or any JavaScript file linked to the exported game’s HTML page, you can call:

window.myGodotFunction("Hello from the browser!")

Godot will now print the message from the JavaScript call to the console.

Utilizing JavaScript Promises in Godot

Sometimes you’ll need to deal with asynchronous operations in JavaScript, such as fetching data from an API. Let’s execute a JavaScript fetch request and process the data in Godot:

Define the asynchronous JavaScript function in your .js file or HTML page:

window.getDataFromAPI = async function(apiUrl) {
    try {
        let response = await fetch(apiUrl);
        let data = await response.json();
        return JSON.stringify(data); // Convert the data to a JSON string for Godot.
    } catch (error) {
        return "error";
    }
}

In Godot, call this function and handle the promise it returns:

var json_data = javascript.eval("""
    new Promise((resolve, reject) => {
       window.getDataFromAPI('https://api.example.com/data')
       .then(resolve).catch(reject);
    });
""")

json_data.then(funcref(self, "_on_data_received"), funcref(self, "_on_error"))

func _on_data_received(data):
    var parsed_data = parse_json(data)
    print("Data received from API: ", parsed_data)

func _on_error(error):
    print("Error: ", error)

In the example above, we are using the JavaScript `fetch` API to request data from an API endpoint. We then handle the promise that is returned in Godot, parsing the successful response or logging an error if something goes wrong.

This second part of the tutorial has guided you through essential JavaScriptBridge operations, allowing for data exchange and function calls between Godot and JavaScript. Stay tuned for our next part where we’ll dive deeper into advanced integrations using JavaScriptBridge in Godot 4!Continuing from where we left off, let’s dive even deeper into the JavaScriptBridge by exploring some advanced code examples that can help us leverage the full potential of web integration in Godot.

Advanced Interactions with JavaScriptBridge

It’s possible to directly manipulate the DOM (Document Object Model) from Godot by using JavaScriptBridge, which can be incredibly useful for custom UI elements or interacting with web-specific elements.

Here’s how we might change the background color of the web page using Godot:

javascript.eval("document.body.style.backgroundColor = 'lightblue';")

Consider a scenario where we want to dynamically create an HTML button and react to its click event in Godot. Here’s what the setup would look like:

First, create the button with JavaScript:

javascript.eval("""
    var button = document.createElement('button');
    button.innerText = 'Click Me';
    button.onclick = function() { Godot.get_instance().emit_signal('button_clicked'); };
    document.body.appendChild(button);
""", [])

Then, in your GDScript, ensure you’re ready to react to the signal:

func _ready():
    connect("button_clicked", self, "_on_button_clicked")

func _on_button_clicked():
    print("HTML button was clicked!")

This code will display a “Click Me” button on the webpage and through Godot’s Signals, you’ll get notified when it gets clicked.

Suppose you want to save data to the local storage of the user’s browser. You could execute something like the following in Godot:

javascript.eval("localStorage.setItem('save_data', arguments[0]);", [to_json(save_data)])

To retrieve the saved data from local storage the next time the user loads the game, you can use:

var save_data = parse_json(javascript.eval("return localStorage.getItem('save_data');"))

This is particularly useful for creating save features in web games without the need for an external server or database.

Interacting with APIs or other web services using JavaScript’s `fetch` is another common use case. For instance, to send player score data to your server, you might use the following code:

javascript.eval("""
    fetch('https://yourserver.com/submit_score', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            name: arguments[0],
            score: arguments[1]
        })
    });
""", [player_name, player_score])

Notice how we use placeholders (`arguments[0]`, `arguments[1]`) to insert GDScript variables into the JavaScript code.

Finally, let’s introduce some error handling in JavaScript for our asynchronous operations. This is essential to ensure that errors do not slip silently by:

var promise = javascript.eval("""
    new Promise((resolve, reject) => {
        window.getDataFromAPI('https://api.example.com/data')
            .then(response => {
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                return response.json();
            })
            .then(data => resolve(JSON.stringify(data)))
            .catch(error => reject(error.message));
    });
""")

promise.then(funcref(self, "_on_data_received"), funcref(self, "_on_error"))

Enhancing Game Performance

While JavaScriptBridge offers many possibilities, it’s also vital to consider performance. All interactions between GDScript and JavaScript must cross the boundary between the game engine and the web browser’s JavaScript engine, which can have a cost in performance, particularly with high-frequency calls.

Therefore, it is recommended to minimize the number and complexity of these calls, batching them when possible, and making sure only necessary interactivity is handled through the bridge.

In conclusion, the JavaScriptBridge class in Godot 4 is a powerful feature that can greatly enhance the web presence of your games. By bridging the capabilities of Godot and the web, you can create innovative experiences that engage your players on another level. Remember to assess the benefits of integrating web technologies on a case-by-case basis to ensure the best performance and user experiences for your games. Keep experimenting, and have fun creating!Integrating web APIs and leveraging browser features are just the beginning when it comes to the capabilities of JavaScriptBridge. Your Godot games can interact with hardware features, social media platforms, and much more. Here are some advanced examples demonstrating the versatility of JavaScriptBridge in Godot 4.

Let’s say we want to access the device’s geolocation information from a Godot game. This can be particularly useful for location-based games or features. We can achieve this by prompting the user for their geolocation data through the browser:

var promise = javascript.eval("""
    new Promise((resolve, reject) => {
        if (!navigator.geolocation) {
            reject('Geolocation is not supported by this browser.');
        } else {
            navigator.geolocation.getCurrentPosition(
                position => resolve({
                    latitude: position.coords.latitude,
                    longitude: position.coords.longitude
                }),
                error => reject(error.message)
            );
        }
    });
""")

promise.then(funcref(self, "_on_geolocation_success"), funcref(self, "_on_geolocation_error"))

The function `_on_geolocation_success(dictionary)` would handle the location data, while `_on_geolocation_error(string)` would handle any errors arising from this request.

Another useful integration is to invoke a request to store player’s data in the IndexedDB, which offers a more robust storage solution compared to the local storage:

javascript.eval("""
    window.saveToIndexedDB = async function(key, data) {
        var dbRequest = indexedDB.open('MyGameDB');
        dbRequest.onupgradeneeded = function(event) {
            var db = event.target.result;
            db.createObjectStore('GameData', { keyPath: 'id' });
        };
        dbRequest.onsuccess = function(event) {
            var db = event.target.result;
            var transaction = db.transaction(['GameData'], 'readwrite');
            var store = transaction.objectStore('GameData');
            store.put({ id: key, data: data });
        };
    }
""", [])

javascript.eval("saveToIndexedDB(arguments[0], arguments[1]);", ['save_key', to_json(save_data)])

Similarly, we can retrieve the data from IndexedDB when needed:

javascript.eval("""
    window.loadFromIndexedDB = function(key, callbackId) {
        var dbRequest = indexedDB.open('MyGameDB');
        dbRequest.onsuccess = function(event) {
            var db = event.target.result;
            var transaction = db.transaction(['GameData'], 'readonly');
            var store = transaction.objectStore('GameData');
            var dataRequest = store.get(key);
            dataRequest.onsuccess = function() {
                Godot.javascript_callback(callbackId, dataRequest.result ? dataRequest.result.data : '{}');
            };
        };
    }
""", [])

var callback_id = javascript.create_callback(self, "_on_data_loaded")
javascript.eval("loadFromIndexedDB(arguments[0], arguments[1]);", ['save_key', callback_id])

Sharing functionality, such as posting to Facebook, can be integrated directly into your game. Here’s an example showing how you might share a player’s high score:

javascript.eval("""
    var url = 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(document.location.href) + '&quote=' + encodeURIComponent('I just scored ' + arguments[0] + ' in this awesome game!');
    window.open(url, '_blank');
""", [player_score])

Finally, consider embedding external tools or widgets directly into your game page. For instance, we can include a YouTube video player:

javascript.eval("""
    var iframe = document.createElement('iframe');
    iframe.src = 'https://www.youtube.com/embed/' + arguments[0] + '?controls=0';
    iframe.width = '560';
    iframe.height = '315';
    document.body.appendChild(iframe);
""", [youtube_video_id])

The examples shown above illustrate the breadth of interactions your Godot game can have with the web through the JavaScriptBridge. Whether syncing game data to cloud storage, sharing content to social media, accessing user location, or simply embedding multimedia content, the JavaScriptBridge class provides a set of powerful tools that can help turn your Godot game into a feature-rich web application.

As you experiment with these examples, always keep in mind the asynchronous nature of web APIs and the need to handle promises in Godot accordingly. With solid error handling and thoughtful design, integrating these advanced functionalities can greatly enhance to the user experience of your game without compromising on performance.

Continue Your Game Development Journey with Zenva

Congratulations on taking the leap into connecting Godot 4 with web technologies using JavaScriptBridge. Your adventure doesn’t have to end here, though. Coding and game development are about continuous learning and practice, and we at Zenva offer you the perfect next step with our Godot Game Development Mini-Degree. This comprehensive program will equip you with the skills to create your own cross-platform games. Dive into a wide range of topics from mastering GDScript to implementing intricate game mechanics across different game genres.

Whether you’re starting from scratch or looking to level up your existing skill set, our curated courses provide you with practical, hands-on experience. The power of the Godot Engine is at your fingertips – all that’s needed is your creativity and passion.

For a broader look at what we offer, including a diverse range of topics that could further enhance your Godot expertise, visit our aggregate of Godot courses. Our learning paths cater to all skill levels and allow you to learn at your own pace, ensuring a flexible and supportive educational experience.

Join our community of learners today and turn your game development dreams into reality. With Zenva, you’re not just learning – you’re building the future of your career in gaming.

Conclusion

In the labyrinth of game development, knowledge is your guiding light, and understanding the power of the JavaScriptBridge is akin to discovering a secret passage that leads to enhanced player experiences and unimaginable creative achievements. Remember, using Godot 4’s JavaScriptBridge is more than just a skill—it’s your key to unlocking the full potential of your games on the web.

Embark on this continuous journey with Zenva’s Godot Game Development Mini-Degree, and let us illuminate your path to mastery. Equip yourself with the arsenal of knowledge that this rich platform has to offer, and transform your passion into tangible, impactful gaming experiences. Together, we’ll take on the challenge of learning and perfecting the art of game creation, ensuring every step you take is another level up in your game development career.

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.