UNPKG

rot-js

Version:

A roguelike toolkit in JavaScript

117 lines (93 loc) 3.59 kB
<h2>Asynchronous game engine</h2> <h3>async/await</h3> <p>The <code>ROT.Engine</code> API documented on this page is provided for backwards compatibility only. In a modern JavaScript, you shall use the <code>async/await</code> facility to coordinate individual asynchronous actors. The main game loop can be implemented (without <code>ROT.Engine</code>) in a trivial manner (the <code>mainLoop</code> function): <div class="example"> async function mainLoop() { while (1) { let actor = scheduler.next(); if (!actor) { break; } await actor.act(); SHOW(output.join("")); } } let scheduler = new ROT.Scheduler.Simple(); let output = []; let actor1 = { // sample actor: pauses the execution when dead lives: 3, act: function() { output.push("."); this.lives--; if (!this.lives) { scheduler.remove(actor1); scheduler.add(actor2); return new Promise(resolve => setTimeout(resolve, 500)); // pause } } } let actor2 = { act: function() { output.push("@"); } } scheduler.add(actor1, true); mainLoop(); </div> <p>Client-side JavaScript is non-blocking: all long-running operations are asynchronous. The <code>ROT.Engine</code> loop is well suited to orchestrating the possibly-async coordination of various game actors.</p> <p>To use the engine, you first need a <a href="#timing/scheduler">scheduler</a> that stores your actors and manages their priority. This scheduler is passed to <code>ROT.Engine</code>'s constructor. Once the engine is started, it correctly calls the <code>act()</code> method on proper actors (picked by the scheduler). It is possible to recursively stop (lock) the engine, should some operation (such as displaying a dialog or waiting for user input) block the execution. Once all lock levels are unlocked, the engine continues its execution.</p> <div class="example"> var scheduler = new ROT.Scheduler.Simple(); var engine = new ROT.Engine(scheduler); var output = []; /* sample actor: pauses the execution when dead */ var actor1 = { lives: 3, act: function() { output.push("."); this.lives--; if (!this.lives) { scheduler.remove(actor1); engine.lock(); /* pause execution */ setTimeout(unlock, 500); /* wait for 500ms */ } } } scheduler.add(actor1, true); var unlock = function() { /* called asynchronously */ var actor2 = { act: function() { output.push("@"); } } output = []; scheduler.add(actor2, false); /* add second (non-repeating) actor */ engine.unlock(); /* continue execution */ SHOW(output.join("")); } engine.start(); SHOW(output.join("")); </div> <h3>Promises</h3> <p><code>ROT.Engine</code> is ready for a promise-based async control flow: if any actor returns a "thenable" from its <code>act()</code> method, the engine locks itself and waits for the thenable to get resolved (via its <code>then()</code> method). This feature is independent on the Promise implementation used; feel free to supply your own, use a library or leverage your browser's native Promises.</p> <div class="example"> var scheduler = new ROT.Scheduler.Simple(); var engine = new ROT.Engine(scheduler); var output = []; /* sample actor: pauses the execution when dead */ var actor = { lives: 3, act: function() { var done = null; var promise = { then: function(cb) { done = cb; } } output.push("."); SHOW(output.join("")); this.lives--; /* if alive, wait for 500ms for next turn */ if (this.lives) { setTimeout(function() { done(); }, 500); } return promise; } } scheduler.add(actor, true); engine.start(); </div>