0 votes
asked by (470 points)
edited by

I want to have additional flexibility in my game. Images on every page would be sized by width, height or original size. Normally I would save the choice to DB or cookies, but it is different here since players have savefiles. That means that they would also want to move their settings. So here are the questions:

  • How do I access save variable through JS(JQ)? 

(Clarification: I expect it to be an object like $settings.images.sizing = (in range) 0-2. Depending which number is saved I will add a line to styles so it displayed correctly.)

  • Or is there any other way to make this work?

2 Answers

+3 votes
answered by (120k points)
selected by
 
Best answer

NOTE: All of the following examples should be considered prototypes, as they contain the bare minimum of error catching.

I would break down your request into two parts:

1. How to handle User Custom Settings on the current web-browser.

I would use the Setting API to handle that as it allows you to add Toggles and Lists to the built-in Settings Dialog, and the state of these settings are automatically persisted in the current web-browser's local storage.

eg. If you implement the widescreen based handler & addToggle() call examples from the Setting.addToggle documentation within your story's Story Javascript area, and add the following CSS to your story's Story Stylesheet area:

html.widescreen {
	background-color: green;
}

... then Play the story and select the Settings button in the left side bar you should see a new toggle option, and using that option should result in the background colour instantly changing each time you toggle it.

Obviously you would want to implement other settings than the widescreen example but the principle is the same.

2. Allow the Use to transfer their Custom Settings between web-browsers.

There are (at least) two potential ways you can use the built-in Save API to handle the persistence of this data, both of these ways make use of the Config.saves.onSave handler & the Config.saves.onLoad handler and the related save object's metadata property.

WARNING: One issue with using the onSave / onLoad event handlers is that they are called for both the Slot based functionality as well as the Disk based, and the only semi-reliable means I could find to differentiate between the two types of Save/Loading was that the save object passed to the Slot based functionality included a title property where as the Disk based functionality didn't.

2a. Persisting/restoring the Custom Settings data during the Save to Disk  and the Load From Disk processes.

The following Javascript example demonstrates how to persist & restore the current state of the above widescreen setting within the save object's metadata property, using this method means that the state of the custom settings will not change when a Slot is loaded.

Config.saves.onSave = function (save) {
	/* WARNING: The following method of testing for the "Save to Disk"
	* onSave event is extremely brittle and could fail for future versions
	* of SugarCube 2.
	*/
	if (! save.title) {
		save.metadata = {'widescreen' : settings.widescreen};
	}
};

Config.saves.onLoad = function (save) {
	/* WARNING: The following method of testing for the "Load from Disk"
	* onLoad event is extremely brittle and could fail for future versions
	* of SugarCube 2.
	*/
	if (! save.title) {
		settings.widescreen = ((save.metadata) ? save.metadata.widescreen : false);
		settingWidescreenHandler();
	}
};

... notice the call to the settingWidescreenHandler() handler defined previously, this is needed to simulate the toggling of the related option.

2b. Persisting/restoring the Custom Settings data during the Slot Save and the Slot Load processes.

Using this method means that loading a Slot could potentially change the current state of the custom settings.

Config.saves.onSave = function (save) {
	/* WARNING: The following method of testing for the "Slot Save"
	* onSave event is extremely brittle and could fail for future
	* versions of SugarCube 2.
	*/
	if (save.title) {
		save.metadata = {'widescreen' : settings.widescreen};
	}
};

Config.saves.onLoad = function (save) {
	/* WARNING: The following method of testing for the "Slot Load"
	* onLoad event is extremely brittle and could fail for future
	* versions of SugarCube 2.
	*/
	if (save.title) {
		settings.widescreen = ((save.metadata) ? save.metadata.widescreen : false);
		settingWidescreenHandler();
	}
};

 

commented by (470 points)
edited by
Thank you for the reply!

But I still have questions. Firstly, it is much better to use addList() because I have at least 3 styles of the background image.

So... "Saves the settings to storage. " description about Setting.save() function tells that data is saved only to the browser. When I save actual savefile there won't be anything about this setting?

Next, I couldn't understand why you wrote so much about 2a and 2b till they are literally the same except one check for a non-existing title, the other one for existing. Why don't I combine them into one without that if at all?

Lastly, I am going to have a lot of different settings that I need to save. Can I just send the whole Settings object there or should I save everything separately?
commented by (120k points)

I have at least 3 styles of the background image.

Toggles are for True/False or Yes/No situations, Lists are for situations where you want the end-user to select one item from a list of possible items. If you have three mutuality exclusive but related items to select from then use a List, if more than one of the three possible items can be selected (true) at the same time then use three Toggles.

When I save actual savefile there won't be anything about this setting?

That's correct because by default Settings data is only saved to the current web-browser's local storage, which is the storage mentioned in the "Saves the settings to storage." statement you quoted. You generally don't need to use the Settings object's save() or load() functions because each time an end-user changes an option within the Settings dialog the new settings state is automatically saved within the current web-browser's local storage.

 I couldn't understand why you wrote so much about 2a and 2b...

Method 2b persists the current state (of the Custom Settings you decide to track) each time you save to one of the Slots, this means that Slot 1 could have a different style of background image than Slot 2. (assuming that the background image style setting was changed between the saving of Slot 1 and the saving of Slot 2)

Method 2a only persists the current state (of the Custom Settings you decide to track) when the Save to Disk options is used. I believe this is the better method if your main purpose is to allow the user to transfer their custom settings between web-browsers.

Implementing both 2a and 2b at the same time is redundant because you either want each Slot (within the save-file) to contain it's own copy of the current settings state or you don't.

Can I just send the whole Settings object...

The problem with saving the whole of that object is that it contains both data properties (you custom settings) as well as functions (like load(), save(), addList(), etc...), and there can be issues if the end-user loads an old save-file over an updated version of the Settings object.

eg. If the developer releases a new version of SugarCube with an enhanced version of the Settings object, and you create a new version of your story using this new version. If the end-user loads a save-file containing a copy of the previous version of the Settings object, and if you override the whole of the new Settings object with the old Settings object, then the new enhancements with disappear which could result in errors if those enhancements were used internally.

...going to have a lot of different settings...

What do you call "a lot" and what sort of settings are you talking about?
Settings generally consist of things that effect the whole (or large parts) of the story layout/styling. eg. widescreen, colour/style themes, font sizes, over-all image sizes, etc...

+2 votes
answered by (57.1k points)

To access a story variable, you can find it on the State.variables object in JS: 

$settings /% TwineScript %/

State.variables.settings // JavaScript

More info

You probably want to define the image styles as classes in css, then save that class to a variable and add the class variable to the images via jQuery or the DOM macros during play, probably in a PassageDone special passage or a task object. That's what I'd do anyway. 

commented by (470 points)
edited by

Nice. I mean add 1 line of css or add a class doesn't really matter. Save to variable? Hm.. It is something like: 

$var = "class-name";
$("selector").toggleClass($var);

The only problem is how to let a user see the changes immediately? He clicked button and image resized right after that. How to change variable not leaving the page in Sugarcube? And after that, I would need to run script somehow. 

I was going to do simply something like this: 

if (a = 1) {
  //remove other classes before and add new one that was checked
  $("selector").toggleClass("class-name");
}

And yet still. It needs to have variable changed and saved before a user leaves the page til otherwise nothing will change after leaving. 

...