JS arrays in squiffy

According to what I'm reading, variables (and arrays) in JS are all global in nature. However, I'm not having a lot of luck seeing arrays in functions. An example:

[[Start]]:

    var Arr1 = [];
    Arr1[0]=50;

    set("test1",Arr1[0]); //works
test1={test1}

[[Next]]

[[Next]]:
    set("test2",Arr1[0]); //fails
test2={test2}

Any ideas on how to use an array in other places (either JS functions or other squiffy sections)?


Declaring a variable with var is optional, and makes it local to the current function.


Taking Var out of this code causes it to crash in Squiffy.

Actually, last night I poked around some more and found a conversation where someone talked about the same thing - JS variables and arrays do not cross into new sections - they are local to that section.

If you want to jump a variable to another section, you have to carry it across in a squiffy variable, using Set and Get commands. Which means arrays are out.

Which is okay. Last night in bed, I thought about it and figured a way to do it with just squiffy variables. I'm not sure how keen I am with this -an array would have been perfect. But you do what you can do with this application, I guess.


Actually, last night I poked around some more and found a conversation where someone talked about the same thing - JS variables and arrays do not cross into new sections - they are local to that section.

Technically, undeclared variables aren't even variables; they're properties.

If you just do Arr1 = [] without the var, it doesn't declare a local variable. It assumes Arr1 is shorthand for this.Arr1. But Squiffy does something a little odd (which I'd forgotten about), so even though this refers to something like squiffy.story.sections['Start'], setting an attribute on it doesn't work as expected.

The usual way of handling global variables in cases like this is to use an object you know to be global. For example, you can refer to window.Arr1, and know that it's the same variable everywhere. That's the easy way to use global JS variables in Squiffy.

But there's a downside. Squiffy attributes are stored in LocalStorage, so they're still there when the player closes the browser and opens it again. The same isn't true for JS variables, which only last as long as the window exists. So in this case, it still might be helpful to use a Squiffy attribute.

Which means arrays are out.

I don't see why it should be.

How about:

[[Start]]:
    var Arr1 = [0, 1, "foo"];
    set ("Arr1", JSON.stringify(Arr1));

The attribute Arr1 has been set to the string: '{Arr1}'.

OK, now try [[Next]].

[[Next]]:
    var Arr1 = JSON.parse(get("Arr1"))
    set("test2", Arr1[1])

The middle element of that array is {test2}.

JSON lets you turn a javascript data type into a string and back again. It's normally used when stuff like arrays and objects needs to be sent between a client and server; but it works just fine for storing arrays or other data in a Squiffy attribute. This method works fine whether it's arrays or plain objects you're dealing with. Or even arrays of objects.


An alternative I've used, to avoid having to explicitly use JSON everywhere, is to store them in a javascript variable, and put that into an attribute when saving. Something like (off the top of my head):

[[Start]]:
    // Redefining the save function, so that it will save our custom variable
    squiffy.story.save = function () {
        // This is what 'save' does by default:
        squiffy.set('_output', squiffy.ui.output.html());

        // Save our custom variable
        squiffy.set('myvariable', JSON.stringify(window.myvariable))

        // And abuse the 'transition' mechanism to make sure it's loaded again
        // by causing the javascript in a particular section to to be run as soon as this saved game is loaded
        squiffy.set('_transition', "squiffy.story.sections['load variables'].js")
    }
    window.myvariable = [];
    // Now we've guaranteed that window.myvariable exists, it will be accessible because it's in the context chain
    // so we don't need to look at it again

Now, take a look at the [[first section]].

[[load variables]]:
    window.myvariable = JSON.parse(get("myvariable"))

This section should never actually be visited, so it doesn't need text. It just makes sure that the variable is saved correctly.

[[first section]]:
    myvariable = ["apple", "banana"];

So what next?
Do you  like [more bananas], [cherries], or [peaches]?
Or would you like to see [[what the variable contains]]?

[more bananas]:
    myvariable.push("all the bananas")

Okay! Now what?

[cherries]:
    myvariable.push("cherry")

Okay! Now what?

[peaches]:
    myvariable.push("peaches")

Okay! Now what?

[[what the variable contains]]:
    set ('testvariable', myvariable.join(', '))

That variable contains: {testvariable}.

This means you have all the flexibility of a JS variable, which is accessible anywhere as long as you explicitly refer to it as window.myvariable the first time. And it persists into a saved game as well.


I think that might do it. I'm going to have to play with it a bit. One thing I did see - I'm expecting it to be pretty large (800+). It (your first example) doesn't seem to like leaving the array open - does it need to be allocated?

[[Start]]:
    var Arr1 = [];
    set ("Arr1", JSON.stringify(Arr1));

    Arr1[1]=5;
    
The attribute Arr1 has been set to the string: '{Arr1}'.

OK, now try [[Next]].

[[Next]]:
    var Arr1 = JSON.parse(get("Arr1"))
    set("test2", Arr1[1])

The middle element of that array is {test2}.

In this case, I get back true, not 5.


doesn't seem to like leaving the array open

Not sure what you mean there.

does it need to be allocated

No; javascript is a high level language. An array is created by using [], whether or not you put values in them.

In this case, I get back true, not 5.

When you do set ("Arr1", JSON.stringify(Arr1));, you're setting the squiffy attribute to the string "[]" - the current values in that array. You can then add an element to the array, but the array is just a local variable.

The line in the second function, Arr1 = JSON.parse(get("Arr1")), restores that variable to the exact values it had when set ("Arr1", JSON.stringify(Arr1)) was called. In this example, an empty array.

So your second section, you look at Arr1[1] and get back undefined because the array is empty. I'm not sure what weirdness of Squiffy's text processor causes this to render as "true", but I think I've come across that quirk before.

If you want to add values to the array, you need to do that before the call to JSON.stringify.

That's one of the reasons I prefer the second option. 8 lines of script at the start of your game, and then you can trust Squiffy to save the values after each section.


[[Start]]:
    var Arr1 = [];
    set ("Arr1", JSON.stringify(Arr1));
    var Arr2 = [];
    set ("Arr2", JSON.stringify(Arr2));
    Arr1[1]=5;
    Arr2[1]=42;
    set("Arr2_1",JSON.stringify(Arr2));
    
The attribute Arr1 has been set to the string: '{Arr1}'.

The attribute Arr2 has been set to the string: '{Arr2}'.

The attribute Arr2_1 has been set to the string: '{Arr2_1}'.

OK, now try [[Next]].

[[Next]]:
    var Arr1 = JSON.parse(get("Arr1"))
    set("test2", Arr1[1])
    var Arr2 = JSON.parse(get("Arr2"))
    set("test3", Arr2[1])
    var Arr2_1 = JSON.parse(get("Arr2_1"))
    set("test3", Arr2[1])
    set("test4", Arr2_1[1])

The middle element of that array is {test2}.

The middle element of that array is {test3}.

The middle element of that array is {test4}.

Peek 2021-01-03 20-53


Log in to post a reply.

Support

Forums