I’ve recently implemented a loading screen for an upcoming version of MindWare, and I would like to take a few moments to explain why and share the solution with you.
One of the biggest and most persistent issues I’ve been dealing with (responsible for most bug reports I’ve received so far) has been missing or improperly initialized variables when starting a new game or loading a save. This can cause all sorts of weird behavior and frustrating bugs for players.
When a person with limited understanding of how the Twine engine works and virtually no experience with the creation of larger interactive fiction games sets out to create a game like MindWare, they may start by placing important variables in the StoryInit passage. All variables placed in this passage are initialized when you start a new game.
The same inexperienced developer may then add additional variables to the StoryInit passage, such as variables for a new part of the UI, and release a new version of their game. You then load your old save and are greeted with an error message because your save is missing the newly added variables. To fix the error, you would have to start a new game—not desirable at all.
I’m not the first person in the world to have dealt with this problem (see here and here, for example), so my solution isn’t something groundbreaking, but I think that it’s polished and reusable enough that others might benefit from it. I also hope to receive feedback from those how are more knowledgable than me.
How it works:
With this solution, I’m able to load variables (most of them anyway) that I have been very generously collected by a Discord user and MindWare supporter UnwrappedGodiva (thank you again!). These variables provide a solid starting point on which I can expand. More importantly, I now have a way to declare future global variables in a way that won’t break old saves.
This script sets up the logic for when to run the initialization process:
:: Scripts-StartingVariables [script]
// Initialize a flag to track whether StartingVariables has run
setup.startingScriptsRun = false;
// Function to run StartingVariables
setup.runStartingVariables = function() {
if (!setup.startingScriptsRun) {
State.variables.previousPassage = State.passage;
setup.startingScriptsRun = true;
} else {
}
};
// Run for new games
$(document).one(':passagestart', function (ev) {
if (ev.passage.title === "Start") {
setTimeout(setup.runStartingVariables, 0);
} else {
}
});
// Alternatively, you can delete the block of code above and call the runStartingVariables function directly from the Start passage like this:
// <<run setTimeout(setup.runStartingVariables, 0); >>
// Run for loaded games
Save.onLoad.add(function () {
setup.startingScriptsRun = false;
setTimeout(setup.runStartingVariables, 0);
});
This is the actual loading screen passage:
:: StartingVariables
<<nobr>><div id="loading-screen">
<div class="loading-content">
<div class="loading-bar-container">
<div id="loading-bar"></div>
</div>
<div class="loading-text">INITIALIZING...</div>
</div>
</div><</nobr>>
// Include as many passages with variables as you want here
// You can also add your variables directly here
<<include "UI Variables">>
<script>
(function() {
// Simulate loading process
var progress = 0;
var loadingBar = document.getElementById('loading-bar');
var loadingInterval = setInterval(function() {
progress += Math.random() * 10;
if (progress >= 100) {
progress = 100;
clearInterval(loadingInterval);
setTimeout(function() {
// Return to the previous passage
SugarCube.Engine.play(SugarCube.State.variables.previousPassage || "Start");
}, 500);
}
loadingBar.style.width = progress + '%';
}, 100);
})();
</script>
A passage with variables to load:
:: UI Variables
<<if ndef $scrollToTopEnabled>>
<<set $scrollToTopEnabled to true>>
<</if>>
The CSS code for the loading screen:
#loading-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
}
.loading-content {
width: 80%;
max-width: 600px;
}
.loading-bar-container {
width: 100%;
height: 20px;
background-color: #111;
border: 2px solid #55BBBC;
box-shadow: 0 0 10px #55BBBC;
}
#loading-bar {
width: 0;
height: 100%;
background-color: #55BBBC;
transition: width 0.3s ease;
}
.loading-text {
color: #55BBBC;
font-family: 'Orbitron', sans-serif;
font-size: 24px;
text-align: center;
margin-top: 20px;
text-shadow: 0 0 10px #55BBBC;
}
If you’ve noticed any mistakes or areas that could be improved, please share them with me here or on Discord. Any feedback I receive is greatly appreciated.