Scenario is a cutscene engine for Sphere which allows you to coordinate complex cutscenes and other actions (such as animations) using multiple timelines and cooperative multithreading.
The current version is
Scenario 3.8.1, released on
March 14, 2015.
Get the script:Changelog:v3.8.1- Added support for minisphere's IsSkippedFrame.
v3.8- Refactored entire codebase and added documentation comments for all methods and scenelets.
- Fixed bugs when forking inside of a doWhile loop where instructions inside the loop could overwrite each others' state.
- Changed doWhile and doIf to take a function (lambda) as argument. The function will be called at scene time and should return true or false to determine how to proceed.
- Removed scenelets doUntil and set.
v3.7.3- Hotfix for broken doIf and doUntil scenelets.
v3.7.2- Hotfix release to fix call scenelet regression in 3.7.
v3.7.1- Hotfix release to restore fork functionality which was completely broken in 3.7.
v3.7:- BREAKING CHANGE - Removed 'state' argument from all scenelet functions; scenelets should store state data using 'this' instead. Any custom scenelets will have to be rewritten.
- New optional finish handler for scenelets, called immediately after the scenelet stops running (i.e. when its update function returns false).
- Support for variables: Use set to set a variable; increment or decement to add or subtract 1 from its value, respectively. Variables can be accessed in scenelet code via scene.variables['var_name']
- New control-flow commands: doIf, doWhile, doUntil. doIf executes a block of commands only if a specified condition is met, the other two are similar but execute the same block repeatedly (loop) while or until the condition is met, respectively.
v3.6:- Renamed beginFork and endFork to fork and end, respectively.
- New scene looping feature: Pass 'true' to the Scenario() constructor for an endlessly looping scene. This is useful for running looping animations in the background. Call Scenario.stop() if you need to break the loop.
- New optional waitUntilDone argument for run() that mimics the old blocking behavior. Helpful for cutscenes.
- Color mask for the fadeTo command is now shared by all scenes and persists after a scene ends. Don't forget to fade back in or the player won't be able to see anything!
- Screen fades and camera manipulations are no longer reverted automatically at the end of a scene. This must now be done manually.
- Running a scene no longer clears its command queue. This lets you run the same scene more than once. Great for caching animation commands!
v3.5.4:- Sphere map engine is no longer required to be running to execute a scenario.
v3.5.3:- Running a scenario no longer detaches input automatically. If this is needed, you must detach and reattach the input yourself.
v3.5.2:- Added new commands marquee and tween. The latter is great for coordinating complex UI animations.
v3.5.1:- Removed unusable marquee command.
v3.5:- User is required to call Scenario.initialize before using the engine.
- Calls to Scenario.update and Scenario.render must be added to the update and render scripts, respectively.
- run() now returns immediately instead of running its own update loop. If your game relied on the old blocking behavior, you'll have to modify it.
- New method: scene.isRunning checks whether the scene is still executing and returns true if it is, false if not.
v3.1:- Built-in commands now use seconds instead of milliseconds for duration.
- Renamed 1 identifier:
- Added support for cascaded command calls. This is the preferred method for scene composition now; examples updated accordingly.
- Completed refactoring started in 3.0.
v3.0:- Major refactoring to make the codebase more readable and less bug-prone.
- Renamed 4 identifiers:
- defineAction -> defineCommand
- walkPerson -> movePerson
- execute -> run
- handleInput -> checkInput
How to use Scenario:First things first: The Sphere map engine must be running in order for Scenario to work. Then when you need a cutscene, you write something like this:
DetachInput();
new Scenario()
.marquee("Chapter 13: Some Random Girl Blows Up")
.movePerson("Katelyn", "north", 100, 2, true)
.pause(2.0) // 2-second delay
.killPerson("Katelyn")
.playSound("BigExplosion.wav")
.run(true); // true to wait until scene finished, false to run in background
AttachInput("hero");
The real power of Scenario, however, lies in its forking feature, which enables multiple simultaneous timelines. For example, you can have the background music (or the screen!) fade in while other actions take place at the same time. As in this example:
DetachInput();
new Scenario()
.fork() // fork the timeline
// we're fading in, so we specify a transparent color (alpha=0) to fade to
.fadeTo(CreateColor(0, 0, 0, 0), 5.0) // fade in over 5 seconds
.end() // end the fork block
.marquee("Chapter 13: Some Random Girl Blows Up")
.movePerson("Katelyn", "north", 100, 2, true)
.synchronize() // pause until all forks are finished - we want to make sure the fade-in has finished before she blows up!
.killPerson("Katelyn")
.playSound("BigExplosion.wav")
.run(true);
AttachInput("hero");
Starting with version 3.7, Scenario also includes support for conditional execution and looping.
// The following scene flashes the screen to white and back twice:
var flashes = 0;
new Scenario()
.doWhile(function() { return flashes++ < 2; }) // 2 iterations
.fadeTo(CreateColor(255, 255, 255, 255), 0.25)
.fadeTo(CreateColor(0, 0, 0, 0), 0.25)
.end()
.run();
I changed your gist to use the Spherical [ gist ] tags, but it appears there is no limit to the box for the code. N E O should try and see if he can limit the height, so that scrollbars could pop up (I'm going to keep yours long like this, so N E O could test it). It's nice to have a gist here since I think it'll update as you update the source, and someone can copy and/or ask for the raw code all in one place.
Haha, thanks Radnen, I had no idea about the gist tag. I was wondering why you guys wanted me to use Gist for this... now I know. :)
Awesome! I modified some version of Scenario to allow facing diagonal directions and to allow diagonal movement. Maybe I'll merge it or something, if you think that might be useful. I think I changed something else too (removed an obscure SpiderMonkey-specific trick, I think).
Was the SpiderMonkey-specific trick my use of the "getter" syntax for the framerate property? If so that was probably a wise move what with TurboSphere now using V8, and I believe that syntax is deprecated in newer versions of SpiderMonkey anyway. I really wish JS had an elegant method of defining properties outside of an object literal...
Anyway, feel free to merge it, yeah. I'm actually in the process of cleaning up Scenario's codebase right now, making the code easier to read. Right now it's a bit of a mess as I did some odd stuff (not putting spaces between function arguments, etc.)
@Radnen - thanks for the heads-up about long gists; I've added a bit of CSS to limit the height of a gist's content (not including the footer) to 20em and add scrollbars as needed.
Was the SpiderMonkey-specific trick my use of the "getter" syntax for the framerate property? If so that was probably a wise move what with TurboSphere now using V8, and I believe that syntax is deprecated in newer versions of SpiderMonkey anyway. I really wish JS had an elegant method of defining properties outside of an object literal...
Ah yes, that was it. The reason was actually because Esprima (https://github.com/ariya/esprima) can't parse that syntax, even in the Harmony branch which parses a lot of SpiderMonkey-specific syntax. I'm using Esprima to do some... evil... stuff, compiling JS to JS so I can write a debugger as a separate Sphere game that can see all the local variables of the game being debugged... it's complicated and yucky, but in theory it might work.
Anyway, feel free to merge it, yeah. I'm actually in the process of cleaning up Scenario's codebase right now, making the code easier to read. Right now it's a bit of a mess as I did some odd stuff (not putting spaces between function arguments, etc.)
OK. How do I merge it? A new Gist?
Oh, I assumed you already knew how. I'm personally not at all familiar with git, but according to them, all gists are full git repositories, so I'd assume you could just commit to it somehow. I don't know, either that or just tell me exactly what changes you made and I'll integrate them into Scenario 3.0... :)
GitHub has edit functionality (ie, a button labeled Edit) that apparently automates the "pull clone, commit update to clone, send pull request for merge" process all the way until the repo owner's choice to merge the edit or reject it. On gists, it shows up when you view the gist's revisions.
Oh, and glad to see Scenario back on the forums! I had an interesting time integrating it into my NShoot core for my Artyxx (https://github.com/apollolux/artyxx) demo :)
I should also say that your Scenario had inspired me to make a clone of it for my RadLib library. It's a re-implementation of it: eventmanager.js (https://github.com/Radnen/radlib/blob/master/scripts/radact/eventmanager.js).
Oh, I assumed you already knew how. I'm personally not at all familiar with git, but according to them, all gists are full git repositories, so I'd assume you could just commit to it somehow. I don't know, either that or just tell me exactly what changes you made and I'll integrate them into Scenario 3.0... :)
I don't really know how with Gists. Cool that they're full git repos, I wasn't aware of that.
Thanks NEO!
So the plan was originally just to clean up the Scenario codebase a little and do a minor version bump to 2.2, but instead I ended up getting caught up in a major refactoring exercise. So needless to say, it's going to take longer than originally planned, but hopefully Scenario 3.0 will be worth the wait. :)
Here's Scenario 2.1 (not 2.1.1) extended to support diagonal movement.
Feel free to incorporate this into Scenario 3.0 if you want, Lord English. It's not particularly complicated anyway.
Haha, to be honest I don't even remember what I changed between 2.1 and 2.1.1. It couldn't have been anything major or I would have bumped it to 2.2 instead. Oh well, I'll look over it, thanks alpha!
Edit: Hm, so apparently 2.1.1 was all refactoring, and somehow I managed to make the code MORE of a mess than it already was in the process. I really have to get 3.0 finished as quickly as possible! :)
The long-awaited Scenario 3.0 is finished! I did some major refactoring on the codebase, documented the important methods in the JS file, and as per alpha123, added diagonal support to facePerson. I refrained from incorporating the diagonal support in movePerson (renamed from walkPerson in 2.1.1) as it would require modifications to the way the step count is calculated, as walk speed is implemented as a vector with independent X and Y speeds. Maybe that'll make it into 3.1...
A comment on your usage of the 'with' keyword. I never really understood ( or was not motivated enough to understand ) why it is evil. In your demo it makes totally sense. But if you want to avoid it, you could have all your scene functions return the scene itself.
var myScene = new Scenario();
myScene
.beginFork() // Forks the timeline
// We're fading in, so we specify a transparent color (alpha = 0) to fade to
.fadeTo(CreateColor(0, 0, 0, 0))
.endFork()
.movePerson("Katelyn", "north", 100, 2, true)
.pause(5000)
.synchronize() // Pauses until all subforks are finished - we want to wait until the fade-in is finished before she blows up!
.playSound("BigExplosion.wav")
.killPerson("Katelyn")
.run()
Or the user could tie the $ sign to it:
var $ = new Scenario();
$.beginFork(); // Forks the timeline
// We're fading in, so we specify a transparent color (alpha = 0) to fade to
$.fadeTo(CreateColor(0, 0, 0, 0));
$.endFork();
$.movePerson("Katelyn", "north", 100, 2, true);
$.pause(5000);
$.synchronize(); // Pauses until all subforks are finished - we want to wait until the fade-in is finished before she blows up!
$.playSound("BigExplosion.wav");
$.killPerson("Katelyn");
$.run();
It'll run a bit faster this way, only because cascading function calls can have some overhead for huge cutscenes. Of course this is just style, but you should implement what Metallix wants too, since it can an option that way.
Radnen, can you explain the overhead in big scenes to me? If I have function1().function2() isn't function2 executed after function1 returned completely? Or do I got something wrong? :o
Well, in any case I implemented the cascading scene composition to be unveiled with Scenario 3.1. It required a single line of code: return this; at the end of defineCommand(). I wish all features were that easy to implement!
Radnen, can you explain the overhead in big scenes to me? If I have function1().function2() isn't function2 executed after function1 returned completely? Or do I got something wrong? :o
You know what, I don't think there is much overhead with that. I was thinking that because the same reference to Scenario is not being used, that there might be some overhead with the call stack. I could see the interpreter doing something like:
a.func1().func2().func3();
// becomes:
z1 = a.func1();
z2 = z1.func2();
z3 = z2.func3();
//...
Which might be a bit unnecessary. Now, I don't know what optimizations v8 does. So, with that version of JS I don't think it matters.
Well then, looks like I'll soon need to update the version of Scenario I've embedded into NShoot :)
Scenario 3.1 has been released. A couple breaking changes in this one, might want to check the changelog before upgrading any existing projects! :)
Scenario 3.5 is out! This a major upgrade which introduces asynchronous operation (scene.run() returns immediately instead of blocking). Now multiple scenarios can be run at the same time so you can coordinate stuff other than cutscenes (animations, for example)! ;D
You'll have to call Scenario.initialize at the beginning of your game now, and add Scenario.update() and Scenario.render() to your update/render scripts, respectively. To determine whether a given scenario is still running or has finished, you can use the new isRunning() method.
So what features would you guys like to see in Scenario 4.0? I was originally considering doing something with event flags and conditional execution, but now that I think about it that may be overreaching on scope a bit (it's a cutscene coordinator, not a game framework) Besides, persist.js is better for that kind of thing anyway...
Just released Scenario 3.5.2, now with tweening! See the OP for details, I added an example to illustrate it. :)
Another hotfix to 3.5.3, running a scenario no longer steals the map engine input focus. :)
Just released Scenario 3.6. This will probably be the last update for a while (barring hotfixes, please test this for me so I don't have to find all the bugs myself! :P) while I think about where to go with Scenario 4.0. 3.6 is an awesome release: It doesn't take over control of the map engine anymore (camera changes and screen fades during a scene aren't reverted at the end, you have to do it yourself), which means you can use it for all kinds of stuff, not just cutscenes. I'm using it in Spectacles for UI animations now, for example. :)
Also, Scenario doesn't require the map engine to be running anymore (unless you use map commands like 'panTo'!), which means if you need to, you can even use Scenario's scene management functionality for your title screen or whatnot.
Just released v3.7, gist updated.
This was originally supposed to be Scenario 4.0, but I decided to release the new conditional execution and looping features as 3.7 instead since it wasn't nearly as much work as I thought it'd be and it should get some testing. I haven't had a need for these features in Specs yet, so it won't get adequate testing with just me having the code.
For 4.0, my plans now are much more ambitious, including a cutscene language (composing scenes directly in JS is awkward, the queuing behavior makes it so there's a lot of things you can't do the "natural" way) and the ability to load scenelets from other JS files.
For 4.0, my plans now are much more ambitious, including a cutscene language (composing scenes directly in JS is awkward, the queuing behavior makes it so there's a lot of things you can't do the "natural" way) and the ability to load scenelets from other JS files.
I'd be more than happy to help you with this, given that I actually have written a cutscene language for Scenario. It probably still needs a bit of work before it's more useful than JS for cutscenes though. Additionally, I don't think it works in Sphere 1.5 (it uses some SpiderMonkey 1.8+ specific syntax) although that should be easy to fix.
Anyway, I'm happy to talk about this in this thread or over PM if you have suggestions for syntax or whatever.
You can see the source for it here (https://github.com/alpha123/Arq/tree/cutscenes/arqscript). There's no documentation, but you should be able to figure out the syntax from the parser which is easy enough to read (I can't say the same about the compiler).
Warning: if you do choose to go this route, it's a
lot of code. IMO it's worth it, but it will at least double if not triple the size of Scenario. You'll be requiring prospective users to learn a whole new language as well - although if the cutscene language is well-designed this may be easier than learning how to use Scenario through JS.
Regarding Scenario 3.7, I can't really see how Scenario variables are more useful than JS ones since they're set before the scene is run instead of during, which makes them equivalent to regular variables, no? Wouldn't
scene.movePerson('hero', 'north', 5 * GetTileHeight(), 1, true)
.set('heroX', GetPersonX('hero'))
.set('heroY', GetPersonY('hero'))
.panTo(scene.variables.heroX, scene.variables.heroY, 1)
.run();
move to the location of 'hero'
before the
movePerson()?
If
set() accepted a function instead of a value, then it could call the function at scene run time to produce the value.
scene.variables could be a function that accepts the name of a variable and returns a function that returns the value of the variable. Other scenelets could then accept that function and get the variable's value. In code,
scene.movePerson('hero', 'north', 5 * GetTileHeight(), 1, true)
.set('heroX', function () { return GetPersonX('hero'); })
.set('heroY', function () { return GetPersonY('hero'); })
.panTo(scene.variables('heroX'), scene.variables('heroY'), 1)
.run();
Damn it, somehow I broke fork in 3.7, nobody download this yet until I figure it out. :(
All right, fixed it. Very embarrassing regression, the fix was a trivial edit to one line of code.
Regarding Scenario 3.7, I can't really see how Scenario variables are more useful than JS ones since they're set before the scene is run instead of during, which makes them equivalent to regular variables, no?
[snip...]
If set() accepted a function instead of a value, then it could call the function at scene run time to produce the value. scene.variables could be a function that accepts the name of a variable and returns a function that returns the value of the variable. Other scenelets could then accept that function and get the variable's value. In code,
scene.movePerson('hero', 'north', 5 * GetTileHeight(), 1, true)
.set('heroX', function () { return GetPersonX('hero'); })
.set('heroY', function () { return GetPersonY('hero'); })
.panTo(scene.variables('heroX'), scene.variables('heroY'), 1)
.run();
Yeah, I really only added variable support to get loops to work. To be fair though, scenelets can modify variables as well (via the
scene.variables object), but your lambda method is certainly better. But really, this is the a good case in point for why I want to do a dedicated scene language, as it illustrates a use case where the intuitive method of doing things doesn't work properly.
So anyway, I do know that adding the new features is going to majorly increase the size of Scenario's codebase, which is why I was thinking of making it an optional component. If you just include Scenario.js, you get exactly what you do now (plus whatever other new features make it into 4.0), and then you could also require 'SceneLanguage.js' or something to get the new scene language parser.
Yeah, I really only added variable support to get loops to work. To be fair though, scenelets can modify variables as well (via the scene.variables object), but your lambda method is certainly better. But really, this is the a good case in point for why I want to do a dedicated scene language, as it illustrates a use case where the intuitive method of doing things doesn't work properly.
I agree a dedicated scene language is almost necessary once you start adding more advanced features such as variables and loops. JS is not a very good host language for internal DSLs, unlike say Ruby where you could create a little scene language within Ruby. I'm not entirely convinced a whole new language is the way to go though (despite the fact that I've already written one).
So anyway, I do know that adding the new features is going to majorly increase the size of Scenario's codebase, which is why I was thinking of making it an optional component. If you just include Scenario.js, you get exactly what you do now (plus whatever other new features make it into 4.0), and then you could also require 'SceneLanguage.js' or something to get the new scene language parser.
That sounds like a good approach. Again, if you want help implementing the scene language, I'd like to help you.
By the way, the
call scenelet is broken: it should be
[].slice.call(arguments, 2) since
state isn't an explicit argument anymore.
By the way, the call scenelet is broken: it should be [].slice.call(arguments, 2) since state isn't an explicit argument anymore.
Whoops. I don't think that one would have taken very long to bite me, as I use that functionality in a couple places in Specs. Thanks for the heads up!
On a sidenote, I do really like the lambda-function approach to variables, I think I'll implement that for Scenario 3.8. I already have the
call scenelet to call functions at runtime (functionality which, as noted above, I do use), this would just be an extension of that mentality. :D
Edit: Fixed the
call scenelet.
scene.movePerson('hero', 'north', 5 * GetTileHeight(), 1, true)
.set('heroX', function () { return GetPersonX('hero'); })
.set('heroY', function () { return GetPersonY('hero'); })
.panTo(scene.variables('heroX'), scene.variables('heroY'), 1)
.run();
I just realized, your above code could be done much more simply with the
focusOnPerson scenelet. I know it was just an example, but I don't know if you were aware or not:
scene.movePerson('hero', 'north', 5 * GetTileHeight(), 1, true)
.focusOnPerson('hero', 1.0)
.run();
I just realized, your above code could be done much more simply with the focusOnPerson scenelet. I know it was just an example, but I don't know if you were aware or not:
scene.movePerson('hero', 'north', 5 * GetTileHeight(), 1, true)
.focusOnPerson('hero', 1.0)
.run();
Oh, thanks! I actually wasn't aware of that, in fact I was using
call() to fake something like my above example with lambda-variables. Perhaps I should have read all the way through the code.... :-[
Still, I'm sure there are probably other use-cases for lambda-variables. Either way, I think they'd be worth it because the current approach doesn't really work in an intuitive manner. Although they're quite ugly. :/ (This is where a dedicated scene language would be a big win.)
This is where a dedicated scene language would be a big win.
As would JS having a proper lambda operator, but can't win 'em all I suppose. (CoffeeScript has one I believe, but I hate everything about CS; coming from a C background, I rather appreciate JS's Java-ness)
Is there a way to persist a scene? For example: you save the game during an ongoing event. Load the game and it's still going on. So I guess in that case scenario may be used for more than just a static cutscene that rips control away from the user. Picture the "city fair" scene from Chrono Trigger entirely ran by Scenario (the runners, bumping into the girl, the teleport).
It's probably something best suited to a layer between persist/analogue and Scenario.
That would be a ton of work, require major changes to the architecture, and I don't know that Scenario is really the best application for that anyway (seems better done in realtime with the entities' command generators or some framework wrapping those). I'll add it to the to-do list and see what I can do anyway, though. :)
Edit: The biggest problem I can see with Scenario being used for this is, suppose a background scene like the runners in CT is going on and then I want to do a cutscene wherein one of the runners walks over and talks to the heroes. The problem: the background scene wants to force him to keep following his path, causing odd things to happen. You could pause the whole running scene, but that might not be desirable to have all the runners just abruptly stop in their tracks. Whereas if it's done in real time, you just suspend command generation for the one entity and everything's fine.
In case anyone missed it, I put up another hotfix earlier to fix the doUntil and doIf scenelets. By now it must be painfully obvious to everyone that 3.7 was put out in a big hurry. :P Remember kids: Haste makes waste!
That's not the real reason I'm posting, though. The real reason is to get suggestions for Scenario 4.0. I want 4.0 to be awesome, so I figured I'd solicit suggestions from the forumites here, now that I know people actually use Scenario (in one form or another ;) ). So far my feature request list looks like this:
• Scene scripting language (tentative - may drop)
• Use lambdas to set variables dynamically at scene time and pass them to scenelets
• Ability to persist runtime state of a scene across sessions
Anyone have anything else to add to that list?
A scenelet debug overlay. YES.
See a graph of forks, sync spots and the current tracking through the scene. I'm sure this will be a challenge, but I mean it only takes looking at the current queue.
@Radnen
Neat idea, I'll see what I can do. Technically you have to look at more than just the current queue, you basically have to traverse the whole graph, since forks can be nested and sync is local to the fork level it appears in (this is more intuitive than waiting for all threads and also prevents deadlocks). It'd be an interesting challenge to implement, to say the least.
I am unsure of the utility if this, though. Scenario is simple enough in concept that it's pretty easy to tell at a glance exactly what will happen when the scene is run. A debug view like this seems like a lot of work for little gain.
Every little bit helps :)
But, I'd wait a couple months or so until people start pointing out flaws or
engaging themselves in ideas where you can take it, then proceed on updating any further.
Or when you yourself have pooled a good collection of ideas to weed out and then implement.
Makes sense to me, but just an idea.
Love to see more projects from da Bruce.
So I just refactored the
doIf and
doWhile scenelets to take a function as its argument, to be unveiled in Scenario 3.8. This allows you to use normal JS variables instead of relying on the clunky Scenario-specific variable implementation in 3.7. Here's an example:
var loopCount = 0;
new Scenario()
.doUntil(function() { return loopCount++ < 3; }) // loop 3 times
// add scenelet calls here
.end()
.run();
I want to say at this point that the
set scenelet is redundant, as you can just use
call to do anything else you need to do, like modifying variables or calling API functions. The only real problem is passing variables to scenelets, so I may need to keep the
set scenelet around anyway...
Haha, just found another bug: If you put a fork in a loop and the loop executes more than once, the forks will trample each others' state data. The problem is that a context is only created for each instruction once--when it's queued. If the same instruction is encountered again (as in a loop), it reuses the same state data, which is a problem in a multithreaded situation. :) Will be fixed in 3.8, for now don't try to use fork in a loop unless you synchronize at the end of each iteration.
+1 on lambdas and passing state.
One thing I might want to see (I'm not fully decided on it yet, and I'll say why in a minute) is a scenelet having the ability to watch the state of another independent scenelet and act accordingly. I've seen this particular paradigm called "co-threading" among other terms in numerous projects independent of each other and is basically how byuu was able to set up bsnes to interact internally.
I'm not fully decided on wanting that yet because I know it can be done using global vars and probably more simply as a result; also, it's more likely that it'd be easier to just add a fork at a particular point within the given scenelet based on the global var to handle the state in question. The not-yet-updated Artyxx demo shows the easier method in action, IIRC, so I know such a thing can be done practically.
An example of how I'd probably use co-threading in Artyxx would be one scenelet "controls movement of a mook" (aka "mook movement" and for this example set to loop at least 8 times if mook isn't killed), one scenelet "controls movement of a boss" (aka "boss movement"), and the "boss movement" scenelet would trigger a bullet spray if "mook movement" scenelet numLoops>0 && numLoops%2==0. It's an idea I've been kicking around my brain for a while and I know it'd enhance the perception of enemy AI in NShoot.
Just released 3.8, which fixes bugs related to doWhile and fork, adds lambda conditionals, and a bunch of under-the-hood refactoring.
@NEO
Yeah, not sure on that. If I'm understanding this correctly, you're referring to something like what Lua calls "coroutines", where two functions run in a kind of relay race: One does what it needs to do then yields to the other, which does what IT needs to do then yields to the original function, and so on and so forth. Cooperative multithreading, in other words. Unless I'm misunderstanding and you actually mean something different?
"Cooperative multithreading" was the exact term I was looking for that was shortened to "co-threading," yes.
As I said, I haven't even completely sold myself on needing it explicitly.
Yeah, you can already kind of do this anyway, even without resorting to global variables. Every scenelet gets a reference to the scene running it as an argument to the update function. All you do, in your mook mover, is have it increment a variable bound to the scene object (be careful not to overwrite any internal properties or methods!), then in your boss mover have it examine that same property and act accordingly. For 3.9 I think I'll change it to not pass the scene object directly but a separate context object, to prevent accidents.
EDIT: Never mind, that won't work. Several internal scenelets (such as fork) rely on being passed the real scene object and would be a lot more complicated to implement otherwise.
Where can I download the latest Scenario script?
Where can I download the latest Scenario script?
The first page of this topic. (http://forums.spheredev.org/index.php/topic,31.0.html) Click on the "View Raw" link at the bottom of the Gist and then save that file.
I didn't see a gist there... until I hard-refreshed the page (ctrl F5). Xenso should do the same. That's a weird issue.
I didn't see a gist there... until I hard-refreshed the page (ctrl F5). Xenso should do the same. That's a weird issue.
I'd wager that's a result of a delayed or incomplete load of the GitHub script that embedding the gist actually calls. If so, that's a GitHub issue rather than an SMF or spheredev.org issue.
I didn't see a gist there... until I hard-refreshed the page (ctrl F5). Xenso should do the same. That's a weird issue.
Weird. What browser are you on? It works fine for me in Firefox 22 on Windows 7.
So, nearly two years later and the best I can come up with is a minor point release adding support for a minisphere-only feature (I may have fixed a bug or two in the interim as well, but I'm not positive on that). Oh well. In any case, Scenario 3.8.1 is available. :)
For anyone that doesn't know, Scenario is now included with minisphere as part of miniRT, since way back to version 1.1 in fact. It works exactly the same as before, except you include miniRT.js (using RequireSystemScript) instead of Scenario.js and you use "new mini.Scene()" instead of "new Scenario()"