Howdy, Stranger!

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

[SugarCube 2.12.1] Modifying sidebar CSS during passage transitions

edited February 2017 in Help! with 2.0
Hi,

I'm trying to add a mechanic to my story where the background color of the sidebar changes to reflect the time of day in the story, which passes by in real time and can be sped up and slowed down. This system I've written works pretty well while a passage is being displayed, but creates visual artifacts during passage transitions.

Long story short, I use setInterval() to create a game tick, and during each tick I update the game's internal clock and update the styles on various elements.

During a passage transition, some time after PassageDone, the StoryCaption is redrawn and the custom styles are reverted to default. The styles are corrected during the next game tick, but this leaves a few milliseconds where everything is the noticeably the wrong color.

Is there a better way to dynamically recolor the UI bar? Failing that, is there some way to reliably hook into UI bar updates so I can reapply custom styles before those updates are rendered?

Relevant snippets of code below:

StoryInit Passage
<<set $game_clock to new Date(Date.UTC(0, 0, 1, 12, 0, 0))>>
<<set $time_factor to 1>>
<<run window.setInterval(window.gametick, 33)>>

Story Javascript
// ...
window.lastTick = new Date().getTime();
window.gametick = function() {
    var now = new Date().getTime(), 
        interval = now - window.lastTick;
    window.lastTick = now;
    
    window.timeSystem.addTime(interval);  // updates $game_clock
    window.uiSystem.updateUI(); // modifies DOM
}
// ... 
window.timeSystem = {
    addTime: function (interval) {
        var clock = variables().game_clock,
            timeFactor = variables().time_factor;

        clock.setTime(clock.getTime() + (interval * timeFactor));
    },
    // ... 
}
// ... 
window.uiSystem = {
    // ... 
    updateUI: function () {
        var time_system = window.timeSystem;

        // calculate new background colours based on current game time
        var bgColor = this.getTimeGradient(this.colors.bgPanelDay, this.colors.bgPanelDelta),
            textPanelColor = this.getTimeGradient(this.colors.textPanelDay, this.colors.textPanelDelta),
            dropShadowColor = this.getTimeGradient(this.colors.dropShadowDay, this.colors.dropShadowDelta);
		
        // update any DOM elements displaying the current time and date
        jQuery(".timespan").text(time_system.getTime());
        jQuery(".dayspan").text(time_system.getDays());

        // recolour the background, using the new colors
        jQuery("#ui-bar, #ui-bar-2").css('background-color',  bgColor);
        jQuery("body, .story-box").css('background-color', textPanelColor);
        jQuery("#ui-bar, #ui-bar-2, .story-box").css('box-shadow', '0px 0px 5px 0px '  + dropShadowColor);
    }
    // ... 
};

Comments

  • edited February 2017
    FYI - This question took a bit of time to get through moderator approval, and since then I discovered various posts by @TheMadExile and @greyelf that allowed me to completely remove the default UI bar and replace them with entirely new UI bars that are manually updated during postrender.

    This allows me to call updateUI() within the same task object, ensuring that the custom styles are applied before the user sees anything.
    /* Create the UI bars */
    $('#ui-bar').remove();
    $(document.head).find('#style-ui-bar').remove();
    
    var $leftUiBar = $('<div id="ui-bar-1"></div>').insertAfter("#ui-dialog");
    $leftUiBar.append('<div id="ui-bar-body-1"></div>');
    
    var $rightUiBar = $('<div id="ui-bar-2"></div>').insertAfter("#ui-bar-1");
    $rightUiBar.append('<div id="ui-bar-body-2"></div>');
    
    /* Update the UI bars */
    postrender["Update Sidebars"] = function (content, taskName) {
    	setPageElement('ui-bar-body-1', 'LeftPanel');
    	setPageElement('ui-bar-body-2', 'RightPanel');
    	window.uiSystem.updateUI();
    };
    
  • edited February 2017
    I understand you have solved your question but I was wondering why you did not just assign a CSS class to the html element, one for each time period, and then use a set of CSS selectors based on each class to style the related areas?

    eg. if you have X CSS classes (period1, period2, period3, etc..) the related CSS selectors could look something like:
    /* styles for first time period */
    html.period1 #ui-bar, html.period1 #ui-bar-2 {
      background-color: blue;
      box-shadow: 0px 0px 5px 0px white;
    }
    html.period1 body, html.period1 .story-box {
      background-color: grey;
    }
    html.period1 .story-box {
      box-shadow: 0px 0px 5px 0px white;
    }
    
    /* styles for second time period */
    html.period2 #ui-bar, html.period2 #ui-bar-2 {
      background-color: grey;
      box-shadow: 0px 0px 5px 0px orange;
    }
    html.period2 body, html.period2 .story-box {
      background-color: green;
    }
    html.period2 .story-box {
      box-shadow: 0px 0px 5px 0px orange;
    }
    
    /* styles for third time period */
    html.period3 #ui-bar, html.period3 #ui-bar-2 {
      background-color: green;
      box-shadow: 0px 0px 5px 0px grey;
    }
    html.period3 body, html.period3 .story-box {
      background-color: blue;
    }
    html.period3 .story-box {
      box-shadow: 0px 0px 5px 0px grey;
    }
    
    ... and the Javascript to assign each time periods class to the html element:
    $('html').removeClass().addClass('period1');
    
    or
    
    $('html').removeClass().addClass('period2');
    
    or
    
    $('html').removeClass().addClass('period3');
    
  • I did consider doing something like that, but then I would not have been able to create a smooth color curve as the seconds tick by.

    I'm in the middle of rewriting my story engine before I port my existing content into it, but feel free to take a peek at the work in progress:
    http://rokiyo.net/games/cetacea/Story%20Engine.html

    If you click the time factor buttons, time will speed up and slow down accordingly. My intention is that the player will be able to perform activities that take a certain amount of time, such as sleeping for 6 hours. While the player is asleep, time will pass really quickly until 6 hours have passed, and then it slow back down to real time.

    The end goal here is to go for something of an X-COM vibe, where the player feels like they are managing a situation that will continue to progress even as they take actions to try and stop it. I really want the player to feel the importance time passing, which is why I'm putting so much effort into creating something of a realtime experience.
  • greyelf wrote: »
    ... and the Javascript to assign each time periods class to the html element:
    $('html').removeClass().addClass('period1');
    
    or
    
    $('html').removeClass().addClass('period2');
    
    or
    
    $('html').removeClass().addClass('period3');
    
    Never use .removeClass() on the document element without a parameter. SugarCube makes use of the document element itself, so blindly removing all classes is a good way to break things.

    If you want to do something to that effect, specify all of the classes you intend to use within the call to .removeClass(). For example:
    $('html')
    	.removeClass('period1 period2 period3')
    	.addClass('period1');
    
Sign In or Register to comment.