Yann's Forum Posts

  • istavang

    This plugin can load any json file that respects the json format described here: http://www.json.org/

    after that, what you do with the data is up to you =)

    (that's quite a quote you did there)

  • Ldk

    what's called snapping is just rounding off values, you can do it by events. More around here

    And, yes you can use solid behaviors.

  • Ashley

    Ah! indeed "clean" shows the error and if you "save", tizen will generate a new ID and fill the properties for you.

    For a first version it's ok, but the problem is that when you want to update the game you put in the store, you will need the same package ID.

    Otherwise the store system doesn't allows you to upload the binary.

    You'll have to either copy/paste the ID back into the config.xml or delete/create the app you uploaded on the store.

    I think construct2 should generate this ID. Maybe by simply hashing the project ID or just use java type package if possible.

  • troublesum

    Nope, I wouldn't have (:

    My post had more purpose than just to correct you affirmation.

    By going a bit more in-depth into how array works on a lower level, I aimed at offering another perspective on arrays on general. Since it's the main topic. You just gave me a pretext and a starting point.

    I think some misunderstanding about C2's array comes from what they try to emulate (multiD-array) vs what people are, nowadays (mostly with php and javascript), used to (array of arrays).

    Also, I believe that sometimes, digging further in the complexity, makes the current problem simpler by contrast (: ... works sometimes...

    Oh and I won't lie. I like to show off sometimes :D

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • troublesum,

    The way arrays usually work in all programming languages is they are dynamically referable locations of memory. IE. Each level can be accessed by "string" name or variable.

    NOPE[/code:1l4lru5h]An array, in traditional programming language (C/C++/C#, Java, Python,...) is a list of contiguous elements of the same size (in memory). No more, no less. 
    When saying "dynamically referable location" you probably mean that you can use a variable that can dynamically change to access any part of the array. And that's right.
    However, you can access each element using an integer index. Not a string, only an integer.
    
    For example, let say we have an array of 4bytes integers.
    In C (let's get back to the bare basics) you would do[code:1l4lru5h] int myArray[10]; //create an array of 10 ints[/code:1l4lru5h]
    This will exactly reserve 4*10 = 40bytes of memory.
    if we were to represent the array in memory, we could imagine something like that:
    [code:1l4lru5h]
    indices :   0    1    2    3    4    5    6    7    8    9
    schema:    [int][int][int][int][int][int][int][int][int][int]
    offsets  :  0    4    8    12   16   20   24   28   32   36   40 ...
    [/code:1l4lru5h]
    So how does an array work its magic?
    when you do myArray[7], the computer knowing that all element have 4bytes will look at the 7x4th byte from the start of the array
    And indeed the int at index 7 is the one at the offset 28 byte.
    
    That's how array works. No more, no less.
    
    Now, there's something that might confuse people depending on how you use arrays in some programming languages.
    
    [h2]Multi-dimensional arrays  ARE NOT array of arrays![/h2]
    
    A Multi-dimensional array is just an arithmetic trick. In memory, it's still a single line of contiguous data. However an Array of Array is an array of pointers to arrays spread over the memory.
    In C, you declare a 2-dimensional array like this:
    [code:1l4lru5h]int multiArray[2][3]; // initialise a 2D array. For clarity let say it has a height of 2 and a width of 3[/code:1l4lru5h]
    here is what it looks like in memory:
    [code:1l4lru5h]
    indices1:   0    0    0    1    1    1  
    indices2:   0    1    2    0    1    2
    schema:    [int][int][int][int][int][int]
    offsets:    0    4    8    12   16   20   24...
    [/code:1l4lru5h]
    if you want a value at index [1][2]  you get the value at offset (indice1 * width + indice2) * size_of_int  = (1 * 3 + 2) * 4 = 5*4 = 20
    
    Now an array of array, in C is declared like this:
    [code:1l4lru5h]int* arrayOfArray[3] // array of pointers to int. Or, for simplicity's sake: array of arrays of ints[/code:1l4lru5h]
    The special character* means pointer to what is before it.
    It means that you don't have an array of ints anymore, but an array of pointers to an int (yeah those iffy pointers is why people don't like C/C++). 
    For this short explanation, you just have to understand that an array of ints is under the hood a pointer to an int (the first of the array then you use the previously mentionned offset to traverse your memory). Then you can understand that as "array of pointers to an int", or more conceptually "array of arrays of ints"
    in memory, it looks like
    [code:1l4lru5h]
    indices :   0     1     2    3    
    schema:    [int*][int*][int*]
    offsets  :  0     4     8    12...
    [/code:1l4lru5h]
    (yeah pointers often also take 4 bytes but it depends on the compiler)
    
    So when you do 
    [code:1l4lru5h]arrayOfArray[2][/code:1l4lru5h]
    You basically get an array of int.
    Obviously C allows you to get any value in this array as well, so you can do something like
    [code:1l4lru5h]arrayOfArray[2][3][/code:1l4lru5h]
    But what happens isn't the same as with the 2D array. Here you don't do arithmetics per se, you directly go to were a second array of int is,  and use it directly like a simple array. A bit like Matryoshka doll  or like following a path.
    
    One of the main differences between the two, in practice, is that the arrays of your array of arrays can have different sizes (jagged arrays). It allows you for example, to build triangular matrices.[code:1l4lru5h][[3,2,1],
     [2,1]
     [1]][/code:1l4lru5h]
    Using a multi-dimensional array, You you just always have the same width, height, depth,...  So it's a good fit for square matrices.[code:1l4lru5h][1, 0, 0,
     0, 1, 0
     0, 0, 1][/code:1l4lru5h]
    
    Small note about javascript:
    Arrays in javascript are very far away from C arrays. They actually aren't really arrays but objects that expose a behavior close to arrays. Nonetheless, you can't access their elements by strings.
    Also, "true" multidimensional array in javascript, and also php are impossible. People talking about multidimensional array in those language are merely refering to how they use it. But make no mistake, they are indeed Array of arrays in all case.
    
    C2 array object aims to emulate the behavior of a true multidimensional array, that's why your can't easily have jagged arrays.
    
    
    

    accessed by "string"

    What you were refering to is called by many names. "Hashtable","Hashmap","Dictionary","Records",...

    [rant]Basically it's a datastructure which allows you to access a value indexed using a hash.

    Well usually, you don't use the hash but something that can be hashed (let say for example,... a string).

    The hash will correspond to an index in an array of "bucket" (another kind of datastructure) which contains all value whose key have the same hash (hash collision).

    The corresponding value is then inserted in or retrieved from this bucket.

    A hashtable is slightly slower than an array. Since read and write require more computation. But it often doesn't matter.[/rant]

    C2 dictionnary is just a simple basic hashtable.

    This is the limiting factor of C2 where not being able build large complex structures like recursive functions or dynamic data algorithms (closed loop systems)

    You can build recursive function in C2.

    + Function: "factorial"
      + Function: parameter 0 <= 1
        -> Function: set return value to 1
      + else
        -> Function: set return value to Function.param(0) * Function.call("factorial",Function.param(0) - 1)[/code:1l4lru5h]
    
    Also, you can build complex datastructure as well with a few hacks, but since it involves passing and parsing JSON strings arround, it's very inefficient.  And yeah there's no easy way to create things like circular linked list. It's not impossible, but it would require building a whole set of function interfaces to access some data a certain ways to simulate memory references. And safe is to say that we would move toward crippling efficiency. C2 is slow enough :D
    
    I would advise to take a look at my [url=https://www.scirra.com/forum/plugin-json-import-export-generate-edit-inspect_t100042]JSON plugin[/url]. It's still in development but I'm using it at work and it simplify few things.
    
    At home I already implemented the hability to load/save objects by reference. So you will be able to create any cyclic datastructure you want. 
    But since I have no cool ways to save that as json for debugging or saving, I'm still looking for a good solution.
  • I had the same problem, the template of the config.xml seems out of date: Bug report

    One easy fix is just to put any package and id you want. It has to be a unique string amongst all the package on tizen store. You can either use the Java style (I didn't try but I don't see why it wouldn't work, unless a dot is prohibited in a package name)

    <tizen:application id="com.example.myapp" package="com.example" required_version="2.2"/>[/code:1v8f8q6v]or using some hash-like string[code:1v8f8q6v]<tizen:application id="oYjHXcOzlL.myapp" package="oYjHXcOzlL" required_version="2.2"/>[/code:1v8f8q6v]
  • Problem Description

    Hi, I'm building some WGT these days using Tizen SDK and I noticed C2 was generating config.xml with missing informations the SDK complains about.

    Mainly:

    <tizen:application id="1234567890.YourAppName" package="1234567890" required_version="2.2"/>[/code:29zx428n]
    
    source: [url=https://developer.tizen.org/fr/downloads/sample-web-applications/load-web-app-tizen-sdk/sample-config.xml-file?langredirect=1]Tizen Web Application config.xml file[/url]
    
    (Also on a side note, it would be nice if we had a list of  template [[keywords]] we could use if we want to tweak them ourselves... 
    And also... maybe... some way to  select custom template on export, since (I think) modification of the default ones are overwritten when we update C2....)
    
    [b]Construct 2 Version ID[/b]
    r171
  • Hi Ashley,

    I'm working on a game using cocoonjs, and I had to use the CocoonJS.PromptKeyboard action.

    It's all working well on the device, but when testing on the computer basically nothing happens. Which is the expected behavior. But I think it would be nice to emulate this part like this:

        Acts.prototype.PromptKeyboard = function (title_, message_, initial_, type_, canceltext_, oktext_)
        {
            if(typeof cr_is_preview !== "undefined") {
                var text = prompt(message_, initial_); // maybe something to allow the layout to refresh before calling the prompt since it's blocking whereas the cocoon prompt isn't
                if(text !== null) {
                    input_text = text;
                    this.runtime.trigger(cr.plugins_.CJSAds.prototype.cnds.OnKeyboardOK, this);
                } else {
                    this.runtime.trigger(cr.plugins_.CJSAds.prototype.cnds.OnKeyboardCancelled, this);
                }
            } else {
    
                // original code
                if (!this.runtime.isCocoonJs)
                    return;
                
                var typestr = ["text", "num", "phone", "email", "url"][type_];
                
                CocoonJS["App"]["showTextDialog"](title_, message_, initial_, typestr, canceltext_, oktext_);
            }
        };
    [/code:2w354z8b]
    
    What dya think?
  • Yeah I do confirm, I remade the test with the exact same two events discribed above.

    To be more precise, I exported the project and hosted it as a canvas app embedded in a page.

    When I load the game the first time, I get Onready, but If I just F5, the OnReady isn't triggered (Ctrl+F5 sometimes triggers the OnReady)

    I believe the js being in the cache, it's loaded so fast that the call to fbAsyncInit is done before the call to the system OnLayoutStart.

    And I do believe that each OnCreate of each instances of object type are called before the OnLayoutStart so everything is initialized at this point, including the facebook API js added to the page. So the racing condition is quite possible.

    Arne 's solution seems ok to me

    ( Ashley maybe, if you end up modifying the plugin, you could also expose a bit more data in expressions, like the fbAppID ... For now I have to hard code the link the the apps' page (In which I have a like to unlock) for my share button, If I can access the ID directly in runtime I can generate it using events )

  • Foxe92

    Yeah, you necroforophile.

    That's indeed a very old corpse you digged here. These days I tend to avoid such process. Because the string is usually tedious to make, so tedious to maintain and also the events to parse it are tedious to write. Not complex, but tedious.

    These days I just use my JSON plugin

    I find it clearer, easier to use and more versatile. Though I would still use the Array plugin for simple flat list and the Dictionary plugin for simple list of key-value pair.

    I use the JSON plugin when I want to load more complex datastructure and when I want to have something easy to read/maintain.

    For example I could have an array of monsters like this

    [ 
        {type:"orc", hp:50},
        {type:"demon", hp:100},
        {type:"slimy", hp:20},
        ...
    ][/code:17skam44] in a JSON and easily spawn them at random.
    
    Anyway, to answer your question, tokenat allows you to access a part of a string considering a specific character as a separator.
    For example, if you have a string like[code:17skam44]"apple, banana, pear, cherry"[/code:17skam44]if you do[code:17skam44]tokenat("apple, banana, pear, cherry", 2, ",")[/code:17skam44]You split the string into parts (tokens) using the coma as a separator, and you get the part of index 2 (counting from 0). So it returns "pear".[code:17skam44]0: "apple"
    1: "banana"
    2: "pear"
    3: "cherry[/code:17skam44]
    tokenCount on the other end gives you how many token you have in a string, using the given separtor[code:17skam44]tokenCount("apple, banana, pear, cherry", ",")[/code:17skam44]returns 4
    
    So using a clever loop you can easily fill an array[code:17skam44]-> Array: set size (0,1,1)
    + repeat tokenCount("apple, banana, pear, cherry", ",")
        -> Array: push tokenat("apple, banana, pear, cherry", loopindex, ",") to back[/code:17skam44]
  • Sorry if it wasn't clear, in the test I ran, sometimes, On ready wasn't triggered and Is Ready returned true on start of layout. I'll try to investigate. And if I can reproduce it I'll get back to you with more detail on my settings and a capx.

    I'm a bit new to the facebook app creation, maybe I did something wrong setting some parameters in the facebook dev stuff.

  • Problem Description

    The OnReady trigger will never be... triggered... if the facebook API is ready before the first call to the on start of layout.

    I believe it's because, in the runtime Runtime.prototype.trigger function, you're preventing any trigger to fire if the sheet isn't active yet

    Attach a Capx

    Since the facebook plugin depends on a facebook id and the example is very small, I'll just post an image

    Description of Capx

    Either trigger both console log action, or only the OnReady if the facebook API takes time to load

    Steps to Reproduce Bug

    • press F5 or Ctrl+F5
    • look at the console output

    Observed Result

    Kind of race condition.

    Expected Result

    Either:

    The facebook plugin call the window.fbAsyncInit before the start of layout

    which should result in the OnReady being triggered, or put on hold to be triggered just after the start of layout

    -> this is the problem

    Or:

    The facebook plugin call the window.fbAsyncInit after the start of layout

    In this case, the onReady not being true, the part in the on start of layout will not execute

    The OnReady is triggered

    -> this is already working as expected

    Of course, a simple thing to do for now would be

    Facebook: isReady
    System: trigger once
         -> do things[/code:10wumhtn]
    
    [b]Construct 2 Version ID[/b]
    r169
  • Ashley

    Yup, but keep a critical eye, I didn't thoroughly test all implication this would have with combining all possibilities. But since it's so small it should be ok =)

    Aphrodite

    Yeah I'm guilty of not usually checking the manual. I prefer directly go into the plugin's source so I understand everything that occurs under the hood.

  • Problem Description

    Ok... I know it can be viewed as a feature request more than as a bug per se.

    But I choose to report it as a bug because the modification is so small that it looks more like a design oversight than anything else.

    So here is the thing:

    You can't ask the anchor behavior to just anchor your object vertically OR horizontally, leaving the other axis alone.

    In my case, I just wanted a UI element to stick to the left border and keep using its default Y position.

    But in some scaling mode (like scale outer) the difference between window border and object position can change. Thus Unecessarily moving the object.

    And in any cases, I always wondered why the options between Left, Top, Right and Bottom edge were so inconsistent.

    Here is my simple fix:

    edittime.js

    @@ -76,8 +76,8 @@
     // new cr.Property(ept_combo,      name,   "Item 1",       description, "Item 1|Item 2|Item 3")    // a dropdown list (initial_value is string of initially selected item)
     
     var property_list = [
    [ul]
    	[li]new cr.Property(ept_combo,  "Left edge",        "Window left",      "Anchor the object's left edge to a window edge.",  "Window left|Window right"),[/li]
    	[li]new cr.Property(ept_combo,  "Top edge",         "Window top",       "Anchor the object's top edge to a window edge.",   "Window top|Window bottom"),[/li]
    [/ul]+   new cr.Property(ept_combo,  "Left edge",        "Window left",      "Anchor the object's left edge to a window edge.",  "None|Window left|Window right"),
    +   new cr.Property(ept_combo,  "Top edge",         "Window top",       "Anchor the object's top edge to a window edge.",   "None|Window top|Window bottom"),
        new cr.Property(ept_combo,  "Right edge",       "None",             "Anchor the object's right edge.",                  "None|Window right"),
        new cr.Property(ept_combo,  "Bottom edge",      "None",             "Anchor the object's bottom edge.",                 "None|Window bottom"),
        new cr.Property(ept_combo, "Initial state", "Enabled", "Whether to initially have the behavior enabled or disabled.", "Disabled|Enabled")[/code:2hkpntpj]
    
    [b]runtime.js[/b][code:2hkpntpj]@@ -95,7 +95,7 @@
            var bbox = this.inst.bbox;
            
            // Anchor left to window left
    [ul]
    	[li]if (this.anch_left === 0)[/li]
    [/ul]+       if (this.anch_left === 1)
            {
                inst.update_bbox();
                n = (layer.viewLeft + this.xleft) - bbox.left;
    @@ -108,7 +108,7 @@
            }
            
            // Anchor left to window right
    [ul]
    	[li]else if (this.anch_left === 1)[/li]
    [/ul]+       else if (this.anch_left === 2)
            {
                inst.update_bbox();
                n = (layer.viewRight - this.xright) - bbox.left;
    @@ -121,7 +121,7 @@
            }
            
            // Anchor top to window top
    [ul]
    	[li]if (this.anch_top === 0)[/li]
    [/ul]+       if (this.anch_top === 1)
            {
                inst.update_bbox();
                n = (layer.viewTop + this.ytop) - bbox.top;
    @@ -134,7 +134,7 @@
            }
            
            // Anchor top to window bottom
    [ul]
    	[li]else if (this.anch_top === 1)[/li]
    [/ul]+       else if (this.anch_top === 2)
            {
                inst.update_bbox();
                n = (layer.viewBottom - this.ybottom) - bbox.top;[/code:2hkpntpj]
    
    (To really really be complete, maybe adding "window left" and "window top" for right edge and bottom edge option, imagining some cases where the object it is assigned to would change size while still be anchored to it's opposite border window... why not? (:  )
    
    I could of course fork the behavior... but just for that it would be... sad.
    
    In any case, Ash, don't hesitate to throw this post in another part of the forum if you don't think it should be here =)
    
    [b]Construct 2 Version ID[/b]
    r168
    
    [b]Edit:[/b]
    Ok after a bit more fiddling, I realised that the plugin was using the first two edges constraint to position the object and the two last to stretch it... which is highly unintuitive I'd say.
    Using my fix, you'd have strange result if you do Top Edge: None + Bottom Edge: Bottom.  I thought first that the object's bottom edge would stick to its initial bottom position, but with the current implementation, it will just stretch the object vertically to keep the bottom edge at its initial bottom position.
    So ok, it might be a mix of feature request and design/conceptual bug report... A matter of opinion (:
  • zatyka

    Oh, my bad. Makes kind of more sense

    Though I my comment still stands.