How do I have an iframe / embedded C3 game communicate with an external program like Twine?

Not favoritedFavorited Favorited 0 favourites
  • 6 posts
From the Asset Store
[C2] [C3] Support C3 build service and Android 14
  • I know that Construct 3 has a sandbox environment. But is there a way for an embedded iframe to communicate a variable to a program like Twine / Pubcoder? I would love to subscribe to and use Construct, but I've not found anything that works and it's a necessity for me? Thank you for any and all help.

  • Messaging between frames on the same page can be done with the postMessage() JavaScript API. Some services also provide a JavaScript API you can use.

    If neither is applicable and you want to communicate with an entirely separate application which does not provide any JavaScript API, it is tricky. Your best options are probably a WebSocket or a browser extension - but you'll still need to know how the external application works and how to message it.

  • Thank you for your reply! Sorry, but I'm slightly struggling with the postMessage(). I'm trying to apply it to Action > Browser > Execute Javascript but it says that 'window' isn't recognised as an object. Am I going about this the correct way, and if so, what is the correct line of code which won't be restricted by Construct?

    I've tried some variations based around window.parent.postMessage("message", "*");

  • Don't use 'Execute Javascript', you can just insert a script action directly in the event sheet which is much easier to work with.

    You probably need to turn off 'Use worker' in project properties, as by default the runtime runs in a web worker without direct access to DOM properties like 'window' and 'document'. The manual guide on JavaScript in Construct explains that more. And if you use a script action in the event sheet, Construct defaults worker mode to off so all those APIs will just work like you expect.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Thanks, that worked :)

    For anyone reading this who is trying to do the same as I was, here are a few suggestions/tips:

    1) Firstly, obviously, make sure you set it up correctly. On the Event Sheet, after adding an event, add the script (the option 'add...' is furthermost right). Ensure 'Use worker' is set to no in the project properties.

    2) After exporting the game, to test it, I found using Netflify is a good website to host the game (don't use Itch.io - it blocks the postMessage, though you might figure out how to stop it from doing that).

    3) If you want to test that the recipient page is working, you can write a simple code (button with postMessage)then embed the iframe on your page (I used Glitch.com).

  • I made a example.

    ---

    This is a simple counter page.

    Demonstrates how to communicate between the iframe and Construct via postMessage() and addEventListener().

    How to get/set Construct variables in the iframe

    How to get/set iframe variables in Construct

    Webpage

    There is a text showing the counter,

    and 2 buttons.

    Button 1, updates the iframe count only.

    Button 2, updates the iframe count and postMessage() to Construct, makeruntime to set the variable.

    The iframe is also listening for an Event from Construct. and when it is triggered, it will update its counter to the parameter value.

    • Preview
    • html
      <!DOCTYPE html>
      <html>
      <head>
       <style>
       #content {
       display: inline-block;
       border: 1px solid #FF0000;
       padding: 6px;
       }
       </style>
      </head>
      <body>
       <div id="content">
       <p>Count: </p><div id="counter">0</div>
       <button id="ButtonA">Set iframe Only</button>
       <button id="ButtonB">Set C3 Both</button>
       </div>
       <script>
      
       const appData = {
       count: 0
       };
      
       const addCounter = (value = 1) => {
       appData.count = Math.min(appData.count + value, 99);
       displayText();
       };
      
       const setCounter = (value = 0) => {
       appData.count = Math.min(value, 99);
       displayText();
       };
      
       const displayText = () => {
       document.getElementById('counter').innerText = appData.count;
       };
      
       const sendMessage = () => {
       const target = window.location.origin;
       window.parent.postMessage({ type: 'increment', value: appData.count }, target);
       };
      
       document.getElementById('ButtonA').addEventListener('click', () => {
       addCounter(2);
       });
      
       document.getElementById('ButtonB').addEventListener('click', () => {
       addCounter();
       sendMessage();
       });
      
       window.addEventListener('changeDataFromC3', (event) => {
       setCounter(event.detail.value || 0);
       displayText();
       });
      
       document.addEventListener('DOMContentLoaded', () => {
       displayText();
       });
      
       globalThis.appData = appData;
      		
       </script>
      </body>
      </html>
      

    html

    <html>
    	<head>
    		 <style></style>
    	</head>
    	<body>
     <div id="counter">0</div>
     <button id="ButtonA"></button>
     <script>
     document.getElementById('ButtonA').addEventListener('click', () => {
     window.parent.postMessage({ type: 'message', value: value });
     });
     </script>
    </body>
    </html>
    

    postMessage

    const sendMessage = () => {
     const targetOrigin = "*";
     window.parent.postMessage({ type: 'message', value: data}, targetOrigin);
    };
    

    globalThis

     const appData = {
     count: 0
     };
    
    globalThis.appData = appData;
    

    Eventsheet

    Load the page in Construct

    Add Listener Events

    const messageHandlers = {
    	increment: data => {
    		const { value } = data;
    		runtime.globalVars.Variable1 = value; // Set Construct Global Variable
    		console.log(`on message: ${value}`);
    	},
    	default: data => {
    		console.log(`no event: ${data.type}`);
    	}
    };
    
    const handleMessage = ({ data = {} }) => {
    	const { type } = data;
    	(messageHandlers[type] || messageHandlers.default)(data);
    };
    
    window.addEventListener('message', handleMessage);
    

    Signal

    runtime.signal("clear-input");
    

    Some Event for Testing

    Send Event to webpage

    const value = 0;
    const event = new CustomEvent('message', { detail: { value } });
    window.dispatchEvent(event);
    

    Get webpage data via globalThis

    const key = localVars.key; // Construct Local Variable & Function Parameter
    const value = globalThis.appData?.[key] ?? 0; // Set globalThis data
    runtime.setReturnValue(value); // Set Function Return Value
    
    {"is-c3-clipboard-data":true,"type":"events","items":[{"functionName":"getDataFromIframe","functionDescription":"","functionCategory":"","functionReturnType":"number","functionCopyPicked":false,"functionIsAsync":false,"functionParameters":[{"name":"key","type":"string","initialValue":"","comment":""}],"eventType":"function-block","conditions":[],"actions":[{"type":"script","script":"const value = globalThis.appData?.[localVars.key] ?? 0;\nruntime.setReturnValue(value);"}]}]}
Jump to:
Active Users
There are 0 visitors browsing this topic (0 users and 0 guests)