XHXIAIEIN's Forum Posts

  • There are a few ways to do it:

    1. expression choose()

    Player.X + choose(random(-150, -64), random(64, 150))
    

    2. ternary operator condition ? True : False

    Player.X + random(1) > 0.5 ? random(-150, -64) : random(64, 150)
    

    and Use this method by WackyToaster better

    Player.X + random(64,150) * choose(-1,1)
    
  • I think it's theoretically possible to make a plugin for Construct that can run Python code, as it could use a WebAssembly build of the Python interpreter.

    Please do this! That would be cool!

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • If you want to interrupt the currently playing voice, You can add the Stop Speaking action before this

    I have also recently exploring how to make Speech Synthesizer speak different texts texts at the same time. I want to simulate multiple characters reciting together. However, I found this doesn't work. It appears unfeasible to speak multiple voices at the same time. One voice must finish before another can begin.

    But I think it might be possible to achieve it through external TTS technology.

  • I did it using regex. file.c3p

    Functions.TagAt(text, "tag", 0)
    Functions.TagTokenAt(text, "tag", 1, 1)
    Functions.TagTokenCount(text, "tag")
    Functions.TagReplace(text, "tag", "replace", 0)
    

    Eventsheet cheatsheet

    {"is-c3-clipboard-data":true,"type":"events","items":[{"eventType":"group","disabled":false,"title":"BBCode Match","description":"","isActiveOnStart":true,"children":[{"functionName":"TagAt","functionDescription":"","functionCategory":"","functionReturnType":"string","functionCopyPicked":false,"functionIsAsync":false,"functionParameters":[{"name":"text","type":"string","initialValue":"","comment":"The text to search within."},{"name":"tag","type":"string","initialValue":"","comment":"The BBCode tag name to match."},{"name":"index","type":"number","initialValue":"0","comment":"Zero-based index of the tag occurrence to retrieve."}],"eventType":"function-block","conditions":[],"actions":[{"type":"comment","text":"example: This is [u][tag]Hello[/tag][/u] string.\nTagAt(text, \"tag\", 0)\nreturn: [b]Hello[/b]"},{"type":"script","script":"const {text, tag, index} = localVars;\nconst result = matchBBCode(text, tag, index);\nruntime.setReturnValue(result.content);"}]},{"functionName":"TagTokenAt","functionDescription":"","functionCategory":"","functionReturnType":"string","functionCopyPicked":false,"functionIsAsync":false,"functionParameters":[{"name":"text","type":"string","initialValue":"","comment":"The text to search within."},{"name":"tag","type":"string","initialValue":"","comment":"The BBCode tag name to match."},{"name":"index","type":"number","initialValue":"0","comment":"The occurrence index of the tag to replace. 0 indicates replace all; 1 for the first occurrence, and so on."},{"name":"part","type":"number","initialValue":"0","comment":"Zero-based index of the part to return."}],"eventType":"function-block","conditions":[],"actions":[{"type":"comment","text":"example: This is [u][tag]Hello[/tag][/u] string.\nTagTokenAt(text, \"tag\", 0, 1)\nreturn: [b][tag]Hello[/tag][/b]"},{"type":"script","script":"const {text, tag, index, part} = localVars;\nconst result = splitBBCode(text, tag, index, part);\nruntime.setReturnValue(result);"}]},{"functionName":"TagTokenCount","functionDescription":"","functionCategory":"","functionReturnType":"number","functionCopyPicked":false,"functionIsAsync":false,"functionParameters":[{"name":"text","type":"string","initialValue":"","comment":"The text to search within."},{"name":"tag","type":"string","initialValue":"","comment":"The BBCode tag name to match."}],"eventType":"function-block","conditions":[],"actions":[{"type":"comment","text":"example: a [u][tag]Hello[/tag][/u] and [u][tag]World[/tag][/u] string.\nTagTokenCount(text, \"tag\")\nreturn: 2"},{"type":"script","script":"const {text, tag} = localVars;\nconst result = tokenCountBBCode(text, tag);\nruntime.setReturnValue(result);"}]},{"functionName":"TagReplace","functionDescription":"","functionCategory":"","functionReturnType":"string","functionCopyPicked":false,"functionIsAsync":false,"functionParameters":[{"name":"text","type":"string","initialValue":"","comment":"The text to search within."},{"name":"tag","type":"string","initialValue":"","comment":"The BBCode tag name to match."},{"name":"rep","type":"string","initialValue":"","comment":"Content to replace the matched tag with; supports `$1` for the parameter and `$2` for the content."},{"name":"index","type":"number","initialValue":"0","comment":"Occurrence index of the tag to replace; `0` replaces all, `1` for the first, and so on."}],"eventType":"function-block","conditions":[],"actions":[{"type":"comment","text":"example: This is [u][tag]Hello[/tag][/u] string.\nTagReplace(text, \"tag\", [b]\"$2 World\"[/b], 0)\nreturn: This is [b]Hello World[/b] string."},{"type":"script","script":"const {text, tag, rep, index} = localVars;\nconst result = replaceBBCode(text, tag, rep, index);\nruntime.setReturnValue(result);"}]}]}]}

    ImportsForEvents.js

    /**
     * Matches all occurrences of a specified BBCode tag in the text and returns an array of match results.
     *
     * @param {string} text - The input text to search within.
     * @param {string} tagName - The BBCode tag name to match.
     * @returns {Array} Array of match result objects, each containing tagName, param, and content.
     */
    function matchAllBBCode(text, tagName) {
     const regex = new RegExp(`\[${tagName}(?:=([^\\]]+))?\\]([\\s\\S]*?)\[\\/${tagName}\\]`, 'g');
     return [...text.matchAll(regex)].map(match => ({
     tagName,
     param: match[1] || null,
     content: match[2],
     }));
    }
    
    
    /**
     * Matches the BBCode tag at the specified index in the text and returns the match result.
     *
     * @param {string} text - The input text to search within.
     * @param {string} tagName - The BBCode tag name to match.
     * @param {number} index - Zero-based index of the tag occurrence to retrieve.
     * @returns {Object|null} Match result object or null if not found.
     */
    function matchBBCode(text, tagName, index) {
     return matchAllBBCode(text, tagName)[index] || null;
    }
    
    
    /**
     * Replaces specified BBCode tags in the text with new content, supporting references to matched groups.
     *
     * @param {string} text - The original text to search within.
     * @param {string} tagName - The BBCode tag name to match.
     * @param {string} replacement - Content to replace the matched tag with; supports `$0` for the full match, `$1` for the parameter, and `$2` for the content.
     * @param {number} index - Occurrence index of the tag to replace; `0` replaces all, `1` for the first, and so on.
     * @returns {string} Text with the specified BBCode tags replaced.
     */
    function replaceBBCode(text, tagName, replacement, index) {
     const regex = new RegExp(`\[${tagName}(?:=([^\\]]+))?\\]([\\s\\S]*?)\[\\/${tagName}\\]`, 'g');
     let matchCount = 0;
     return text.replace(regex, (match, p1, p2) => {
     matchCount++;
     return (index === 0 || matchCount === index)
     ? replacement
    	 .replace(/\$0/g, match)
    	 .replace(/\$1/g, p1 || '')
    	 .replace(/\$2/g, p2)
     : match;
     });
    }
    
    
    /**
     * Splits the text based on the specified BBCode tag and retrieves parts according to the tagIndex and partIndex.
     *
     * @param {string} text - The original text to split.
     * @param {string} tagName - The BBCode tag name to match.
     * @param {number} tagIndex - Specifies which tag occurrence to split by. `0` for all matches, `1` for the first tag only.
     * @param {number} partIndex - The part to return: 0 for the text before the tag, 1 for the tag itself, and 2 for the text after the tag.
     * @returns {string|null} The extracted part or null if not found.
     */
    function splitBBCode(text, tagName, tagIndex, partIndex) {
     const regex = new RegExp(`(\[${tagName}(?:=[^\\]]+)?\\][\\s\\S]*?\[\\/${tagName}\\])`, 'g');
     const parts = text.split(regex).map(part => part.trim());
    
     if (tagIndex === 0) {
     return parts[partIndex] || null;
     }
    
     if (tagIndex === 1) {
     if (partIndex === 0) return parts[0];
     if (partIndex === 1) return parts[1];
     if (partIndex === 2) return parts.slice(2).join(' ');
     }
     return null;
    }
    
    
    /**
     * Counts the occurrences of a specified BBCode tag in the text.
     *
     * @param {string} text - The original text to search within.
     * @param {string} tagName - The BBCode tag name to count.
     * @param {number} tagIndex - returns the match count;
     * @returns {number} The count based on tagIndex.
     */
    function tokenCountBBCode(text, tagName) {
     const regex = new RegExp(`\[${tagName}(?:=[^\\]]+)?\\][\\s\\S]*?\[\\/${tagName}\\]`, 'g');
     const matches = [...text.matchAll(regex)];
     return matches.length;
    }
    
  • I'm trying to replace text matching a Tag with another text, But the content in the tag is dynamic.

    For example, in this example

    #open=bbcode-tag-range

    xxxxxx [tag=mytag][u]this bit[/u][/tag] xxxxxx
    

    I want use "mytag" to get this bit

  • The Stop Loop just work in System object. but you can use For

    + System: For "" from 0 to JSON.ArraySize("") -1
    
    {"is-c3-clipboard-data":true,"type":"events","items":[{"eventType":"block","conditions":[{"id":"for","objectClass":"System","parameters":{"name":"\"\"","start-index":"0","end-index":"JSON.ArraySize(\"\")-1"}},{"id":"compare-two-values","objectClass":"System","parameters":{"first-value":"loopindex","comparison":0,"second-value":"2"}}],"actions":[{"id":"set-path","objectClass":"JSON","parameters":{"path":"\".\" & loopindex"}},{"id":"set-text","objectClass":"TextInput","parameters":{"text":"JSON.GetAsBeautifiedString(\".\")"}},{"id":"set-text","objectClass":"TextInput","parameters":{"text":"JSON.Get(\".name\")"}},{"id":"stop-loop","objectClass":"System"}]}]}
    

    ---

    BTW: I submitted a suggestion to add more ACEs to JSON. If you are interested, you can add a 👍 emoticon to the OP.

    github.com/Scirra/Construct-feature-requests/issues/8

  • Example cdn.discordapp.com/attachments/225550155531812865/1209210754952335370/PushJSON_Into_RootArray.c3p

    {"is-c3-clipboard-data":true,"type":"events","items":[{"eventType":"block","conditions":[{"id":"on-start-of-layout","objectClass":"System"}],"actions":[{"id":"parse","objectClass":"JSON","parameters":{"data":"\"[]\""}}],"children":[{"eventType":"block","conditions":[{"id":"repeat","objectClass":"System","parameters":{"count":"4"}}],"actions":[{"id":"set-path","objectClass":"JSON","parameters":{"path":"\"\""}},{"id":"push-value","objectClass":"JSON","parameters":{"where":"back","path":"\".\"","value":"loopindex"}},{"id":"set-object","objectClass":"JSON","parameters":{"path":"\".\" & loopindex"}},{"id":"set-path","objectClass":"JSON","parameters":{"path":"\".\" & loopindex"}},{"type":"comment","text":"add data"},{"id":"set-value","objectClass":"JSON","parameters":{"path":"\".id\"","value":"loopindex"}},{"id":"set-value","objectClass":"JSON","parameters":{"path":"\".name\"","value":"\"user\" & loopindex"}},{"id":"set-value","objectClass":"JSON","parameters":{"path":"\".image\"","value":"replace(\"actor{0}.png\", \"{0}\", str(loopindex))"}}]},{"eventType":"block","conditions":[],"actions":[{"id":"set-text","objectClass":"TextInput","parameters":{"text":"JSON.ToBeautifiedString"}}]}]}]}
  • Maybe Family think that "making games" and "playing games" are the same, both considered distractions from serious pursuits. They may believe that you should focus solely on studying school subjects to achieve higher scores in exams, leading to admission to a good university and obtaining a better job. Or Maybe Their perception of games might be limited to low-quality, non-educational, advertisement-driven games. However, you should inform them that games are more than that.

    In reality, game development is a completely different matter. You can show them some excellent games to help them understand that creating a game requires highly professional knowledge. Developing games allows you to acquire a wide range of skills: art, mathematics, history, psychology, management, economics, programming, and more. All of these skills are highly valuable.

    From an employment perspective, the gaming industry is a very popular profession, offering high salaries in various departments and positions.

    --

    Using GPT Translate:

    You can showcase some excellent games to them:

    "Sid Meier's Civilization" and "Hearts of Iron IV":

    These games allow players to learn about world history through strategic gameplay.

    "Assassin's Creed" and "Persona 5 Royal":

    Even without leaving the house, these games enable players to explore diverse landscapes and cultures.

    "The Sims" and "Animal Crossing":

    These games offer a virtual second life, allowing players to engage in creativity, social interactions, and simulation of everyday activities.

    "League of Legends" and "Dota 2":

    Competitive and challenging, these games teach skills in teamwork, strategy, and quick decision-making.

    By experiencing these games, one can gain insights into history, culture, strategic thinking, teamwork, creativity, and more. Games are a diverse medium that goes beyond mere entertainment.

  • Ashley Does have plans to continue updating this blog so that we can see more reasonable uses of events? It would be very helpful to have a clear guide on when to use A instead of B

    construct.net/en/blogs/construct-official-blog-1/common-mis-used-events-gotchas-822

  • For example, import bootstrap file into project 'Files' folder

    bootstrap.min.css
    bootstrap.min.js
    bootstrap.bundle.min.js
    

    you can also organize folders according to your preferences

    Then reference them in HTML and fill in the correct path.

    <html>
    <head>
     <link href="../dist/css/bootstrap.min.css" rel="stylesheet">
     <script src="../dist/js/bootstrap.bundle.min.js"></script>
    </head>
    <body>
     <div class="container">
    		<button type="button" class="btn btn-primary">Primary</button>
    		<button type="button" class="btn btn-secondary">Secondary</button>
    		<button type="button" class="btn btn-success">Success</button>
    		<button type="button" class="btn btn-danger">Danger</button>
    		<button type="button" class="btn btn-warning">Warning</button>
    		<button type="button" class="btn btn-info">Info</button>
    		<button type="button" class="btn btn-light">Light</button>
    		<button type="button" class="btn btn-dark">Dark</button>
    		<button type="button" class="btn btn-link">Link</button>
     </div>
    </body>
    </html>
    

    Then, load the HTML file through AJAX and display it in the HTML element object.

    Here is an example

    cdn.discordapp.com/attachments/225550155531812865/1201611568903901265/test-HTMLElement-with-bootstrap.c3p

  • 1. Use 'Array' and array file: #open=languages-from-json

    2. Use 'i18n' plugin (JSON): simple example for i18n

  • I think it's straightforward to have translatable flowcharts: instead of an actual piece of text in a value, put the translation key, and look it up for the current language when displaying it.

    It may not be necessary to fill in the translation key, but to find a better way to manage the path. When obtaining output content, point to the translation file based on the relative path.

    But the question now is, how to organize this structure?

    strings.nodes[NodeIndex].outputs[OutputIndex].value
    

    Especially for this NodeIndex, Once it can be identified, localization can be achieved by directly editing the JSON source file of Flowchart, utilizing its existing structure.

  • How should Flowcharts solve the localization?

    If I Duplicate a flowchart file for each language, If I want to change Something, I have to edit it again n times, which is obviously unreasonable and error prone.

    If working with i18n plugin, I need to create a JSON file to manage it. This means that I need to maintain a path similar to flowchart in the JSON file again. And fill in the placeholder for this path in the flowchart.But this obviously loses the convenience of visualizing flowcharts. What better way to cooperate with the i18n plug-in?

    For example: #open=flowchart-questionnaire

    • Tab 1

      I extracted the JSON file of Flowchart from the project file and cleaned up other data: file.json

    • Expand
      {
      	"name": "Questionnaire",
      	"locale": "en-GB",
      	"strings": {
      		"nodes": [
      			{
      				"outputs": [
      					{
      						"name": "Message",
      						"value": "What kind of content do you want to make?"
      					},
      					{
      						"name": "Option1",
      						"value": "Games"
      					},
      					{
      						"name": "Option2",
      						"value": "Animations"
      					}
      				]
      			},
      			{
      				"outputs": [
      					{
      						"name": "Message",
      						"value": "Try Construct Animate! Use the timeline to build sequences of movements and changes over time, and export as a video, GIF, or image sequence."
      					},
      					{
      						"name": "Link",
      						"value": "https://animate.construct.net/"
      					}
      				]
      			},
      			{
      				"outputs": [
      					{
      						"name": "Message",
      						"value": "Are you interested in using coding to develop games?"
      					},
      					{
      						"name": "Option1",
      						"value": "Yes"
      					},
      					{
      						"name": "Option2",
      						"value": "No"
      					}
      				]
      			},
      			{
      				"outputs": [
      					{
      						"name": "Message",
      						"value": "Try using Construct 3 with its event block system. It's a drag-and-drop alternative to programming languages which is easy to learn and yet powerful enough to build sophisticated games with."
      					},
      					{
      						"name": "Link",
      						"value": "https://editor.construct.net/"
      					}
      				]
      			},
      			{
      				"outputs": [
      					{
      						"name": "Message",
      						"value": "Do you already know how to code with JavaScript or TypeSript?"
      					},
      					{
      						"name": "Option1",
      						"value": "Yes, I know JavaScript"
      					},
      					{
      						"name": "Option2",
      						"value": "Yes, I know TypeScript"
      					},
      					{
      						"name": "Option3",
      						"value": "No"
      					}
      				]
      			},
      			{
      				"outputs": [
      					{
      						"name": "Message",
      						"value": "See our tutorial 'Construct for JavaScript developers quick start guide' for an introduction on how to use your existing JavaScript coding knowledge with Construct."
      					},
      					{
      						"name": "Link",
      						"value": "https://www.construct.net/en/tutorials/construct-javascript-2866"
      					}
      				]
      			},
      			{
      				"outputs": [
      					{
      						"name": "Message",
      						"value": "See our tutorial 'Using TypeScript in Construct' for a guide on how to use your existing TypeScript coding knowledge with Construct."
      					},
      					{
      						"name": "Link",
      						"value": "https://www.construct.net/en/tutorials/using-typescript-construct-3003"
      					}
      				]
      			},
      			{
      				"outputs": [
      					{
      						"name": "Message",
      						"value": "See our free 13-part course 'Learn JavaScript in Construct', which teaches the basics of JavaScript coding in Construct!"
      					},
      					{
      						"name": "Link",
      						"value": "https://www.construct.net/en/courses/learn-javascript-construct-79"
      					}
      				]
      			}
      		]
      	}
      }
      
  • It makes sense to support connecting to parent nodes and own nodes

    For example, in some games there are some "trap" or "ask" options that will return to the current node when player select.

    What do you want to know?
     - What is {quest}?
     - Who is {npc}?
     - Option 3
     - Option 4
    
    what do you do first
     - use hand			-> die
     - use tools		-> survive
     - shout for help	-> die
     - do nothing		-> die
    

    After their process ends, they will return to the parent node.This is common in many games.

    Currently, although it is possible to manually add an special Output Name to record the parent node, And through the eventsheet and then position it. But it is not a convenient visualization solution, Just an auxiliary field. it would be more convenient if it could be supported directly.

    But supporting this function will also face a problem, the lines will become confusing.

    a by flowchart demo Adrian Raudaschl