Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Calculated Object Properties not updated when other properties of object updated

Twine 2.0.11, Sugarcube 2

Hi, new here, have been using Twine 2.0 desktop version for almost a month now.
Recently came across a tutorial for object oriented programming for Twine and followed a couple more online resources to update my Twine code.

I am having a problem with "non-updating" properties. Consider the following code in my "StoryInit" passage:
<<set $crystal to {
	red: 0,
	yellow: 0,
	white: 0,
	black: 0,
	green: 0,
	get total(){return this.red +this.yellow +this.white +this.black +this.green;},
}>>

And then I do some changes to the total properties in other passages.
<<set $crystal.green+=1>>

My problem is the $crystal.total still remains zero rather than "auto-calculated" with new values in red, yellow, etc.

Thanks in advance for your help.

Comments

  • edited July 2016
    Each time the Reader navigates between passages a copy of all the known variable's values is made and it is this copy of the known variables that is made available to the next passage. This means that object references that use to reference the same object now each reference their own copies of the original object.

    So based on the above information the reason your total function remains zero is because the this reference in the total function is referencing a different object than the one that your $crystal variable is. In your example the object was defined within one passage (StoryInit) and modified within another.

    The following two passage example demonstrates the issue, I have added an extra tgreen function to your original object so you can see that the green property and the this green reference don't always have the same value.

    1. First passage
    <<set $crystal to {
    	red: 0,
    	yellow: 0,
    	white: 0,
    	black: 0,
    	green: 0,
    	get total(){return this.red +this.yellow +this.white +this.black +this.green;},
    	get tgreen(){return this.green;}
    }>>
    
    ''Values before crystal.green is changed.''
    green: <<print $crystal.green>>
    tgreen: <<print $crystal.tgreen>>
    total: <<print $crystal.total>>
    
    <<set $crystal.green += 1>>
    
    ''Values after crystal.green was changed.''
    green: <<print $crystal.green>>
    tgreen: <<print $crystal.tgreen>>
    total: <<print $crystal.total>>
    
    [[Next Passage|Second]]
    
    2. Second passage
    ''Values before crystal.green is changed again.''
    green: <<print $crystal.green>>
    tgreen: <<print $crystal.tgreen>>
    total: <<print $crystal.total>>
    
    <<set $crystal.green += 1>>
    
    ''Values after crystal.green is changed again.''
    green: <<print $crystal.green>>
    tgreen: <<print $crystal.tgreen>>
    total: <<print $crystal.total>>
    
  • @greyelf Actually, that's not quite the problem. While your first paragraph is correct, as usual, the problem here is not with this.

    @sakamoto The actual issue here is that when the variable store is cloned between passages—greyelf is completely correct about that—the getters are being transformed into data properties. This is because the underlying system does not use property descriptors when making the clones.

    If the object was written so that the calculation properties were simply methods instead of getters, then there shouldn't be an issue.

    For example:
    <<set $crystal to {
    	red    : 0,
    	yellow : 0,
    	white  : 0,
    	black  : 0,
    	green  : 0,
    	total  : function () {
    		return this.red + this.yellow + this.white + this.black + this.green;
    	}
    }>>
    
    And access:
    Green: <<print $crystal.green>>
    Total: <<print $crystal.total()>>
    
  • @greyelf and @TheMadExile , thank you very much for the details behavior and working solution. There is a side effect though, which I am not sure could be resolved.

    I tried the function option, but it doesn't seems to "just work" outside a script, the way other variable/object properties do, where there will always be a direct replacement, rather than requiring a <<print >> script.

    Is there a way to get both auto update (using function) and direct replacement (using get) works at the same time?

    Again, thank you very much for your answers. I am very new javascript object programming.
  • edited July 2016
    If you're referring to printing the value of the property just by referencing the $variable.property in normal text—via the naked variable markup—then no. As noted in its documentation, if you need to access a an object's methods, then you'll still need to use <<print>> or its alias <<=>>.

    Basically, the naked variable markup is really to allow an easy way to print the value of variables (i.e. $variable). That it also allows basic property access via the dot notation (i.e. $variable.property) is a bonus to which there are limits.

    For example:
    → While the naked variable markup allows this:
    You have $crystal.green green crystals.
    
    → For method access or more complicated expressions you need to use a print macro:
    You have <<=$crystal.total()>> crystals in total.
    
  • the getters are being transformed into data properties. This is because the underlying system does not use property descriptors when making the clones.
    It is good to learn something new everyday. *smile*

  • If you're referring to printing the value of the property just by referencing the $variable.property in normal text—via the naked variable markup—then no. As noted in its documentation, if you need to access a an object's methods, then you'll still need to use <<print>> or its alias <<=>>.

    Basically, the naked variable markup is really to allow an easy way to print the value of variables (i.e. $variable). That it also allows basic property access via the dot notation (i.e. $variable.property) is a bonus to which there are limits.

    For example:
    → While the naked variable markup allows this:
    You have $crystal.green green crystals.
    
    → For method access or more complicated expressions you need to use a print macro:
    You have <<=$crystal.total()>> crystals in total.
    

    Thank you again for the detailed explanation, & yup, that's exactly what I'm asking, will be using the print notation then. Luckily twine have a pretty good Replace function.
Sign In or Register to comment.