Like, let's say my game is about a spy talking to a wealthy businessman with the aid of Mission Control in their ear. How can I have these two conversations happening simultaneously but on different sides of the screen?
Hmm… I don't think this should be too hard to achieve. Would probably need some changes to the HTML to add a second output section; and a system for determining which side a given page should be loaded on. Would you want a link to always load a section on the same side; or perhaps have each section tagged with which output area you want it to appear in?
Either way, it would need quite a bit of tweaking to the HTML document, and to squiffy.template.js
. Do you have much javascript experience?
Ah! Always great to see you, mrangel!
I have some experience. I've learned a lot just from making a few games. I'm very experienced with tweaking the HTML and CSS of a game. Although it would take forever for me to come up with solutions, I'm experienced enough to understand what every line of code does and tweak it to my needs.
I think this interface should possess a few of the same qualities as the inventory interface you created. I've studied that a bit, so we're not in completely new territory!
I think the project I'm currently working on only calls for links to always load a section on the same side. But afterward, it would be worth exploring the latter option you suggested for our fellow Squiffy community.
One other thing I want to point out is that this split screen view should have the ability to be toggled on and off (not by the player. Just by me. I decide when this feature can be used).
I haven't got Squiffy on my new laptop yet; but I suspect adding a second output area to the HTML document should be easy enough.
I suspect that you'll need to use some code in the click handler to identify which output area the link is in, and set a variable accordingly. Maybe set a squiffy attribute, like _outputpane
, so that you can use a normal @set
line to change it if you want to. Then you could modify squiffy.ui.write
and similar functions to make them deal with the appropriate pane.
It may also be necessary to make sure that the save and load functions deal with both panes; unless you create them inside the default output container.
So yeah. This feels much trickier than I thought (for me. Probably not for you). My initial instinct is to make something like
var rightPane = link.attr('rightPane');
if (rightPane) {
appear on the right pane. Duh.
}
But I'm also having a bit of trouble creating two divs for these left and right panes that act the same but aren't. I know the solution isn't to duplicate all the code.
One of the other things I have to figure out is how to make it so that attributes are shared through both panels but that a section in one panel doesn't disable the section links in the other.
I think I just need a bit of guidance, and maybe that starts with knowing what I should change about this:
<div id="squiffy"></div>
I think I just need a bit of guidance, and maybe that starts with knowing what I should change about this:
<div id="squiffy"></div>
I'd suggest something like:
<div id="squiffy" class="outputpane">
<div id="outputLeft" class="outputpane"/>
<div id="outputRight" class="outputpane"/>
</div>
Although you'll need a bunch of CSS to make the divs appear and look how you want them. I'm thinking that the outputpane
class can be used later; when a link is clicked, we search for the closest parent with that class.
So near the start of the function handleLink
, you'd have something like:
var outputPane = link.parents().filter('.outputpane').first();
(this means that you can also have silly stuff like inline panes if you want; any div which has the outputpane
class will cause links inside it to be opened inside the div)
It looks like this will be more complex than I expected, because you also need to be tracking currentSection
. Now, there's two ways I can see to do this. One is to drop the tracking of the current section and hunt for the last section in the selected outputpane; the other would be replacing the currentSection variable with a plain object, and changing every place it is used.
Off the top of my head, I'd suggest adding a function which accesses the current section. So, in handleLink
you would have something like:
var outputPane = link.parents().filter('.outputpane').first();
squiffy.set("_outputpane", outputPane.attr("id"));
Then everywhere currentSection
is accessed, change it to a function. So:
currentSection.append('<hr/>');
becomes:
squiffy.getCurrentSection().append('<hr/>');
The function would be defined as something like:
squiffy.getCurrentSection = function (pane) {
if (pane && $('#'+pane).length) {
squiffy.set("_currentpane", pane);
} else {
pane = squiffy.get("_currentpane");
}
if (!squiffy.ui.currentSections) {
squiffy.ui.currentSections = {};
}
if (!squiffy.ui.currentSections[pane]) {
squiffy.ui.currentSections[pane] = $('#'+pane).children('div').last();
}
return (squiffy.ui.currentSections[pane]);
};
(This changes the current pane if it is given a pane name as an argument; and uses the current one otherwise)
Then you'd need to modify the function to create a new section:
var newSection = function(pane) {
if (pane && $('#'+pane).length) {
squiffy.set("_currentpane", pane);
} else {
pane = squiffy.get("_currentpane");
}
var currentSection = getCurrentSection(pane);
if (currentSection) {
disableLink(jQuery('.squiffy-link', currentSection));
currentSection.find('input[attribute]').each(function () {
set ($(this).data('attribute'), this.value);
this.disabled = true;
});
currentSection.find("[contenteditable][attribute]").each(function () {
set ($(this).data('attribute'), this.innerHTML);
this.disabled = true;
});
currentSection.find('textarea[attribute]').each(function () {
set ($(this).data('attribute'), this.value);
this.disabled = true;
});
}
var sectionCount = squiffy.get('_section-count') + 1;
squiffy.set('_section-count', sectionCount);
var id = 'squiffy-section-' + sectionCount;
currentSection = jQuery('<div/>', {
id: id,
}).appendTo($('#'+pane));
squiffy.set('_output-section', id);
if(!squiffy.ui.currentSections) {
squiffy.ui.currentSections = {};
}
squiffy.ui.currentSections[pane] = currentSection;
};
Outside that function, everywhere that currentSection
is accessed, it would change to getCurrentSection()
. And you'd also want to change:
squiffy.story.save = function() {
squiffy.set('_output', squiffy.ui.output.html());
squiffy.set('_current_sections', jQuery.map(squiffy.ui.currentSections, (section, pane) => ({pane: pane, section: section.attr('id')}));
};
squiffy.story.load = function() {
var output = squiffy.get('_output');
if (!output) return false;
squiffy.ui.output.html(output);
squiffy.ui.currentSections = {};
jQuery.each(squiffy.get('_current_sections'), function(i, v) {
squiffy.ui.currentSections[v.pane] = jQuery('#'+v.section);
})
squiffy.story.section = squiffy.story.sections[squiffy.get('_section')];
var transition = squiffy.get('_transition');
if (transition) {
eval('(' + transition + ')()');
}
return true;
};
That's all off the top of my head, not tested. But I hope it makes a decent starting point.
… that's going to break passages. I think that passage links look for a passage in the last loaded section; which means that they'll start breaking if you go to a different section in the other pane.
Wowzers. Off the top of your head. One day I will be able to do that.
Let me test it out and fiddle with it, and I'll get back to you on how it works.
Thank you so much for your help!
So one thing that really makes it difficult for me to test this out is that when I preview my game, the divs inside:
<div id="squiffy" class="outputpane">
<div id="outputLeft" class="outputpane"/>
<div id="outputRight" class="outputpane"/>
</div>
Just keep disappearing. I think this might be because when Squiffy restarts a game, it deletes the squiffy-section divs by removing all divs every single div inside div#squiffy. How can I bypass this?
In the function squiffy.story.restart
is the line:
squiffy.ui.output.html('');
You could either put the HTML inside the quotes in that line; or change it to (another top-of-my-head kludge):
squiffy.ui.output.find(':not(.outputpane):not(:contains(.outputpane))').remove();
Which I think should only remove elements which don't have the outputpane
class.
You probably also want to add
squiffy.ui.currentSections = {};
to the restart function, do that it doesn't try to disable links in previous sections that no longer exist.
Huzzah! It worked! Now I can see my two divs! Now it's time to try putting things together.
Thanks again for your quick responses!
So far, all the code seems to fit in nicely. After digging around, I noticed that this line of code
squiffy.set('_current_sections', jQuery.map(squiffy.ui.currentSections, (section, pane) => ({pane: pane, section: section.attr('id')}));
is missing a parenthesis. I think the corrected code should be
squiffy.set('_current_sections', jQuery.map(squiffy.ui.currentSections, (section, pane) => ({pane: pane, section: section.attr('id')})));
Also, there is a reference error here:
var currentSection = getCurrentSection(pane);
It says that getCurrentSection
is not defined. I'm unsure where to define it and what to put in that variable. I know we've defined the squiffy.getCurrentSection
function in the handleLink
function.
And when I do get this all to work, how do I assign an output area to a section?
It says that getCurrentSection is not defined.
Ah… it should be squiffy.getCurrentSection, the same as the other ones. That's me being careless.
And when I do get this all to work, how do I assign an output area to a section?
I've thought again about the restart issue. It might actually make more sense to put the divs for the two panes in the first section. So your first section would look something like:
<div id="outputLeft" class="outputpane">
Initial contents of left pane goes here.
</div>
<div id="outputRighr" class="outputpane">
Initial contents of right pane goes here.
</div>
That way, they automatically come out when the game is restarted; and both panes can have something in them. Clicking a link in either pane will cause the target section to open in the same pane. And if you want to override that, I think you could do something like:
@set _outputpane = outputLeft
(Assuming I've not got confused about the order things are evaluated in)
Gah! I’ve been messing with this on and off for a while, but there’s still a lot of errors. I think I’ll post a work in progress demo very soon that I can link into this forum so you can take a look at what I have so far.
Okay, I made a demo.
https://textadventures.co.uk/games/view/osxyqeno50oglnxr3qo9dq/two-games-side-by-side-test
The only problem is nothing is showing up.
This is not a publishing bug. It's just the way it is.
This is the bugless version that I've composited. There shouldn't be any bugs other than you can't see the game. But I can't make much progress given my lack of JS knowledge.
Again, it is always greatly appreciated if you can help in any way. Thank you for what you have done so far!
mrangel's DeSquiff tool is not even seeing this as a Squiffy game, if that provides any clues. I see you're using Squiffy 5.0.0 for for OS X. I had such a janky and disappointing time with that when I used to use it.
This is confusing me a lot; I'm not sure why the game isn't working, but the issue with desquiff is (probably?) a separate thing.
The weird thing is that I can't get any kind of output from it. I tried modifying a copy of it to add debug statements, and nothing seems to be coming out; which I really can't understand.
I'll keep on trying this when I've got a little more time (really behind schedule with work this month). I'll try to remember to keep this on my "to do" list.
Thank you, fellers! Means a lot to me. Hopefully, some really cool things can come about from this!