This library provides a collection of classes and functions that aim to simplify some of the heavy-lifting involved in implementing simple 2D games using HTML5. It aims to be lightweight and provide a clear API that's both powerful and easy to use, and lets you focus on game logic instead of working with all the technical details behind the scenes.
This engine is still in ongoing development. The release version is stable, but API may change in future releases.
To get started, create a HTML file with your favorite HTML5 template and add a canvas element of desired dimensions to it:
<canvas id="myCanvasId" width="500" height="400"></canvas>
Add myst.js and the associated scripts for your game to the HTML:
<script src="path/to/myst.min.js"></script>
<script src="path/to/game.js"></script>
You can now use myst.js in your code! Hooray! All we need to create a basic myst.js game is a game state and the game definition.
Put the following code in your JavaScript file:
// create a game state
let myState = new myst.State();
// state draw function
myState.draw = function() {
// clear the surface
this.surface.clear();
// draw a red square
this.paint.rectFill(10, 10, 50, 50, 'red');
};
// setup the game
let myGame = new myst.Game({
canvasId: 'myCanvasId',
state: myState,
simpleLoop: true
});
// run the game when window finishes loading
window.addEventListener('load', myGame.run);
That's it! Your first myst.js game is complete. If you run it in your browser, you will see a nice red square displayed on your canvas.
A game state represents a single segment of the game, or a screen. You may for example create one state for the game menu, another for the actual game, yet another for story screen, and so on. Alternatively, you can pack your entire game into a single state - your choice.
In the code above, we're using the state's draw
function to paint to the screen. This function gets called by the Game object whenever this particular state is active. Note the state: myState
line which informs the engine that we would like myState
to be the initial state when the game runs. This argument is needed for the game to run and is not optional. Once running, we may change the active game state using myGame.setState(nextState)
.
Note the line that reads simpleLoop: true
. This informs the engine that we would like to make a game where we don't care for logic updates, we only want to draw to the screen. Defining this flag will make the engine run an alternate game loop that's optimized for this mode. Use it if your game relies on user input to "push" the game forward. To avoid entering this mode, simpy skip the definition.
What if we want to make a simple animation instead? Let's define both update and draw functions for our state, and let's use a regular loop for our game:
// create a game state
let myState = new myst.State();
// state init function
// gets called once as the state initializes
myState.init = function() {
// initialize all our goodies here
this.rotation = 0;
};
// state draw function
myState.draw = function() {
// clear the surface
this.surface.clear();
// draw a blue circle
let circle_x = 50 * Math.cos(this.rotation) + 200;
let circle_y = 50 * Math.sin(this.rotation) + 200;
this.paint.circleFill(circle_x, circle_y, 30, 'blue');
};
// state update function
myState.update = function() {
// increase rotation
let speed = 0.1;
this.rotation += speed;
};
// setup the game
let myGame = new myst.Game({
canvasId: 'myCanvasId',
state: myState
});
// run the game when window finishes loading
window.addEventListener('load', myGame.run);
This will display a blue circle orbiting around a central point. Note the init
function, which is meant for initialization of variables and preparation of data. This function is called once as the state is being initialized. This happens automatically when the state is activated for the first time, or you can initialize states manually using myGame.initStates([state1, state2, ...])
. Either way, init
is guaranteed to only be executed once per state and before enter
.
Note that we are not using simpleLoop
in the above example. This means that the engine will call both update
and draw
functions on the active game state.
Ideally, we would do all of our state calculations in the update
function and we would only use draw
for rendering calls. However, doing some calculations inside draw
makes the example above simpler since we don't need to bother with defining extra variables. Generally speaking, it's ok to do some calculations on the rendering side of your game as long as you keep all the game logic updates in the update
function. The purpose of the update
function is to update the game state to a renewed state, constantly keeping it afresh as it were, and the purpose of the draw
function is to render whatever state the game is currently in, to the screen. You should always keep performance in mind when writing any sort of code in either of these functions, as they are being updated in real time (in most cases that means about 60 times per second).
See the /examples/ folder for more examples on usage. See the /doc/ folder for API reference.
Below is a short summary of classes found in myst.js and examples on how to use them.
The Game class constructs a Game object that exists at the core of a myst.js game. It handles initialization and runs the main game loop. It is initialized in the following way:
let myGame = new myst.Game({
canvasId: 'myCanvasId',
state: myState
});
The argument canvasId
is the id of the <canvas>
element in the DOM tree. The state
argument points to the initial game state. Both parameters are required. Optionally, you can define simpleLoop: true
to the options argument to make the engine use a simplified loop that doesn't call the update
function on states.
The game will not start automatically. To start the game, use:
myGame.run();
To change the active game state:
myGame.setState(nextState);
To retreive the active game state:
let activeState = myGame.getState();
States will initialize automatically when they are first entered into. For cases where you wish to manually initialize states, use:
myGame.initStates([state1, state2, ...]);
myst.js can handle the view for your game. To set view mode, use one of the following:
// centers canvas element to parent
myGame.setViewMode('center');
// scales canvas element to parent maintaining a fixed aspect ratio
myGame.setViewMode('scale-fit');
// scales canvas element to parent fully, ignoring aspect ratio
myGame.setViewMode('scale-stretch');
// expands canvas element to parent, changing physical diemensions of the canvas
myGame.setViewMode('expand');
Note that changing the view mode changes elements' CSS and has an effect on user input since coordinates must be translated accordingly. This is handled automatically by the Input class.
The State class allows you to create State instances. These can be used to handle various game screens. At least one state is needed for a myst.js game to function. A state with its corresponding functions is defined in the following way:
let myState = new myst.State();
myState.init = function() {
/* initialize state here */
};
myState.draw = function() {
/* draw to screen here */
};
myState.update = function() {
/* update state here */
};
myState.enter = function() {
/* state was entered */
};
myState.exit = function() {
/* state was exited */
};
All functions are optional. When simpleLoop
is used, update
will be ignored.
You can use an alternate syntax if you want to:
let myState = new myst.State({
init: function() {
/* initialize state here */
},
draw: function() {
/* draw to screen here */
},
update: function() {
/* update state here */
},
enter: function() {
/* state was entered */
},
exit: function() {
/* state was exited */
}
});
The init
function initializes and prepares the state and is guaranteed to only be invoked once per state. The draw
function is used for rendering graphics to screen and update
is used for updating state logic. When a state becomes active, enter
is called. Similarly, when the state stops being active, exit
is called.
To check whether a state is active:
let stateIsActive = myState.isActive();
The Render class contains functions that deal with on-screen rendering. An instance of Render is automatically initialized whenever a Surface is initialized (see next section for information on the Surface class).
It can be accessed via state.surface.render
or the shorthand state.paint
. It is preferable to use the shorthand method. Methods are listed below. Note the optional and default values.
Rendering shapes:
// line
line(x1, y1, x2, y2, [lineColor='#fff'], [width=1]);
// rectangle
rect(x, y, width, height, [lineColor='#fff'], [width=1], [radius=0]);
// filled rectangle
rectFill(x, y, width, height, [color='#fff'], [radius=0]);
// circle
circle(x, y, radius, lineColor, [width=1)];
// filled circle
circleFill(x, y, radius, [color='#fff']);
// arc (part of a circle)
arc(x, y, radius, startAngle, endAngle, [lineColor='#fff'], [width=1]);
// filled arc
arcFill(x, y, radius, startAngle, endAngle, [color='#fff']);
// circular sector
sector(x, y, radius, startAngle, endAngle, [color='#fff'], [width=1]);
// filled circular sector
sectorFill(x, y, radius, startAngle, endAngle, [color='#fff']);
// polygon
points = [[x1, y1], [x2, y2], ...];
polygon(points, [color='#fff'], [width=1]);
// filled polygon
polygonFill(points, [color='#fff']);
Rendering graphics and tiles:
// plain or stretched graphics
graphics(gfxSource, x, y, [width], [height]);
// surface
surface(surfaceSource, x, y);
// tile
tile(gfxSource, tileX, tileY, tileWidth, tileHeight, sourceX, sourceY);
// stretched tile
stretchTile(gfxSource, tileX, tileY, sourceWidth, sourceHeight, sourceX, sourceY, tileWidth, tileHeight);
// native text
text(textString, x, y, [textColor='#fff'], [alignment='left'], [font='11px sans-serif']);
// bitmap text
bmptext(fontObject, text, x, y, [colorIndex=0], [align=0]);
Alpha blending example:
myState.draw = function() {
this.surface.clear();
this.paint.setAlpha(0.5); // set alpha level
this.paint.rectFill(0, 0, 100, 100, 'red');
this.paint.setAlpha(); // restore alpha
};
Rotation example:
myState.draw = function() {
this.surface.clear();
let angle = 45; // angle of rotation
let point = [50, 50]; // rotation pivot point
this.paint.rotate(angle, point); // rotate at 45 degrees around point 50, 50
this.paint.rectFill(0, 0, 100, 100, 'red');
// once we are done rotating, we need to restore saved context
this.paint.restore();
};
If you require additional rendering functions, you can extend the renderer.
You can access the global surface's render like so:
myGame.getSurface().render
To add a custom function to renderer:
myst.compose(myGame.getSurface().render, {
blueCircle: function(x, y) {
// renders a blue circle at x, y
// use this.ctx for raw API calls
this.ctx.strokeStyle = 'blue';
this.ctx.lineWidth = 10;
this.ctx.arc(x, y, 20, 0, Math.PI * 2);
this.ctx.stroke();
}
});
myState.draw = function() {
// we can now use the function in any state
this.surface.clear();
this.paint.blueCircle(20, 20);
};
Surface is a class that wraps a <canvas>
element and includes a Render. A global surface is instantiated on the main canvas element when the game first runs and is available to all game states. You can instantiate your own surfaces to pre-render graphics. This is useful for optimizing expensive graphic calls.
To create a Surface object:
let mySurface = new myst.Surface({
width: 200,
height: 200
});
This creates a Surface with its own internal <canvas>
of specified dimensions.
You may also create a Surface that wraps an existing <canvas>
element:
let sourceCanvas = document.getElementById('someCanvasId');
let mySurface = new myst.Surface({
fromCanvas: sourceCanvas
});
You can access the internal <canvas>
element with mySurface.canvas
.
To draw on a Surface, simply access the internal render
object and use any of its methods:
// paints a yellow rectangle of size 50x50 at 20, 20 onto mySurface
mySurface.render.rectFill(20, 20, 50, 50, 'yellow');
To clear a surface:
mySurface.clear();
By default, surfaces will clear to transparent color. You can set a solid fill color instead if needed:
// sets fill clear method with default (black) color
mySurface.setFillClearMethod();
// sets fill clear method with custom color
mySurface.setFillClearMethod('#aabbcc');
To toggle back to default clear method:
mySurface.setDefaultClearMethod();
The Input class is used for handling mouse and touch events. The engine does not differentiate between mouse and touch events, they are treated in an equivalent way.
To instantiate an Input object, you need to associate it with a Game object:
let myInputHandler = new myst.Input(myGame);
You can register events with the on
function. You can register one of three events: press, move or release:
myInputHandler.on('press', function(coords) {
// mousedown or touch-start has occured
let cx = coords[0]; // event x coordinate
let cy = coords[1]; // event y coordinate
});
myInputHandler.on('move', function(coords) {
// mousemove or touch-move has occured
});
myInputHandler.on('release', function(coords) {
// mouseup or touch-end has occured
});
Note that the above events will fire any time an event is detected, regardless of the currently active state. To associate an event with a state context, you can use bindTo
:
myInputHandler.on('press', function(coords) {
/* ... */
}).bindTo(myState);
myInputHandler.on('move', function(coords) {
/* ... */
}).bindTo(myState);
myInputHandler.on('release', function(coords) {
/* ... */
}).bindTo(myState);
Above events will only fire whenever myState
is the active game state.
If you want to be able to deregister an event, you need to associate an identifier with it:
myInputHandler.on('press', function(coords) {
/* ... */
}, 'myId');
To deregister an event, use off
with a desired identifier:
myInputHandler.off('press', 'myId');
To deregister all events of given type:
myInputHandler.off('press');
To deregister all events, call off
with no arguments:
myInputHandler.off();
The KeyInput class handles keyboard events.
To create a handler:
let myKeyInputHandler = new myst.KeyInput();
To poll last keyboard event:
let keyEvent = myKeyInputHandler.pollEvent();
The return value stored in keyEvent
will contain two properties, type
and keycode
- type
can be either myKeyInputHandler.KEYDOWN
or myKeyInputHandler.KEYUP
, which are static values representing the event type. The keycode
property contains a value with the corresponding key code.
The keyboard handler conatins key codes for all common keys. You can access them in your handler by the key prefix:
myKeyInputHandler.keyEnter
myKeyInputHandler.keyA
myKeyInputHandler.keyB
myKeyInputHandler.key1
myKeyInputHandler.key2
To clear the event queue and key buffer:
myKeyInputHandler.clear();
To check if a key code is alphanumeric:
myKeyInputHandler.isAlphanumeric(keyEvent.keycode);
To convert a key code into a character:
myKeyInputHandler.getCharacter(keyEvent.keycode);
To check if a given key is in keydown state:
let key = myKeyInputHandler.keyEnter; // check if Enter is currently pressed
myKeyInputHandler.isKeyDown(key);
The keyboard handler is typically used in the update
function of some game state thereby binding it to that particular state.
Example usage:
myState.update = function() {
// fetching keyboard events
// loop through keyboard events until there are none left
let keyEvent;
while (keyEvent = myKeyInputHandler.pollEvent()) {
if (keyEvent.type === myKeyInputHandler.KEYDOWN) {
// a keydown event has occured
// do something with keyEvent.keycode
}
else if (keyEvent.type === myKeyInputHandler.KEYUP) {
// a keyup event has occured
// do something with keyEvent.keycode
}
}
// checking individual key states
let isKeyWDown = myKeyInputHandler.isKeyDown(myKeyInputHandler.keyW);
let isKeyQDown = myKeyInputHandler.isKeyDown(myKeyInputHandler.keyQ);
};
The AssetLoader class is used to preload various types of game assets, and provides a way to access them later on.
AssetLoader includes a few default handlers for loading assets. Custom handler functions can be defined to process various types of data. Default handlers can be safely overriden as well.
To create an AssetLoader, use:
let myAssetLoader = new myst.AssetLoader();
You will need a list of assets that point to the files. This list needs to have specific category names that correspond to the appropriate load handler functions. The default handlers are graphics
for any type of image files, data
for JSON files and text
for plaintext files.
let myAssets = {
graphics: {
player: 'path/to/player.png',
monster: 'path/to/monster.png',
background: 'path/to/background.jpg'
},
data: {
levels: 'level.json'
},
text: {
story: 'story.txt'
}
};
To preload assets, use the load
function. Use the assets
attribute to point to a list of assets you want preloaded. Attach a done
function to inform you of when all processing is complete. Optionally, you can attach a progress
function to track the load progress:
myAssetLoader.load({ // returns the resource list
assets: myAssets,
done: function() {
// we are done loading assets!
// typically we would run the game here, or continue to the main screen
},
progress: function(loaded, all) {
// track progress
console.log('Loaded ' + loaded + ' out of ' + all + ' assets!');
}
});
Note: When loading multiple asset lists into a single AssetLoader instance, resources from all lists will merge into a single resource list so be mindful of name clashes between the lists. (A common usage of multiple asset lists is for loading one asset list with assets required for the game's load screen, and another asset list with the game's actual resources, which you load while the load screen is displayed.)
To retreive resources, you can use the get
function:
let gfxPlayer = myAssetLoader.get('graphics.player');
let storyText = myAssetLoader.get('text.story');
To retreive several resources at once:
let gfx = myAssetLoader.get('graphics.player graphics.monster graphics.background');
// we can now use gfx.player, gfx.monster, gfx.background
You can use the from
function for better readability:
let gfx = myAssetLoader.from('graphics').get('player monster background');
let storyText = myAssetLoader.from('text').get('story');
You can also retreive the resource list directly:
let resourceList = myAssetLoader.getResources();
let gfxPlayer = resourceList.graphics.player;
In some cases, you may want to use the following pattern to "convert" the asset list into a resource list (actually you're retreiving a reference to the resource list and overriding myAssets with it - so be careful when loading multiple asset lists):
myAssets = myLoader.load({
assets: myAssets,
done: function() {
let gfxPlayer = myAssets.graphics.player;
}
});
To define a custom category, add a handler function to the list of handlers:
myAssetLoader.handler.custom = function(filename, ready) {
// process file given by filename
let object;
/* ... */
// call ready with the loaded object when done
ready(object);
};
You can now use a custom category:
let myAssets = {
custom: {
/* keys and filenames */
}
};
This is an example for a sound effect asset handler using howler.js:
myAssetLoader.handler.sfx = function(filenames, ready) {
let sfx = new Howl({
src: filenames,
autoplay: false,
loop: false,
volume: 1,
onload: function() {
// return sfx once everything is loaded
ready(sfx);
},
onloaderror: ready // will return an undefined asset
});
};
let myAssets = {
sfx: {
foo: ['foo.ogg', 'foo.aac', 'foo.wav'].
bar: ['bar.ogg', 'bar.aac', 'bar.wav']
}
};
myAssets = myAssetLoader.load({
assets: myAssets,
done: function() {
// retreive sfx
let sfx_foo = myAssets.sfx.foo;
let sfx_bar = myAssets.sfx.bar;
// play foo
sfx_foo.play();
}
});
The Grid2D class is a container for a 2D matrix of values. It can be instantiated in the following way:
// creates a grid of size 100x100 with the default value 0
let gridWidth = 100;
let gridHeight = 100;
let gridDefaultValue = 0;
let myGrid = new myst.Grid2D(gridWidth, gridHeight, gridDefaultValue);
Use the clear
function to clear the entire grid to the default value specified in the constructor:
myGrid.clear();
Important: note that on instantiation, every cell in the grid has a value of undefined until clear
is applied (or values are set manually).
Use the set
function to set a grid value:
let x = 10;
let y = 10;
let value = 20;
myGrid.set(x, y, value);
Use the get
function to retreive a value from the grid:
let x = 10;
let y = 10;
let value = myGrid.get(x, y);
The Timer class is used for creating simple, tick-based timer objects that can be used in conjunction with a state's update
function.
To create a Timer object:
let interval = 60; // specifies the rate at which the timer ticks. 60 ticks ~ 1 second
let myTimer = new myst.Timer(interval);
A timer's interval represents the number of ticks that need to occur for the timer to tick. Example usage:
myState.init = function() {
this.showRectangle = true;
};
myState.draw = function() {
this.surface.clear();
if (this.showRectangle) {
this.paint.rectFill(20, 20, 100, 100, 'purple');
}
};
myState.update = function() {
if (myTimer.run()) {
// timer has ticked
// toggle visibility of rectangle
this.showRectangle = !this.showRectangle;
}
};
The run
function advances the timer state and reports back whether or not the timer has ticked. Alternatively, you can ignore the return value and check whether the timer has ticked or not by accessing the ticked
property.
You can use the reset
function to reset the timer back to initial state:
myTimer.reset();
The Configuration class provides a way to handle persistant storage for your game. It wraps the localStorage API in a neat and easy to use interface. You may instantiate more than one Configuration as long as the key for each configuration remain unique.
A Configuration object is initialized in the following way:
let myKey = 'example';
let myDefaultConfig = {
foo: 'value',
bar: 0
};
let myConfig = new myst.Configuration(myKey, myDefaultConfig);
A configuration object acts like any other object and you may populate it with any sort of data. A default configuration serves as a template for your configuration. A load
call needs to be applied at the start of the game to retreive the active configuration. If the key is not found within localStorage, the default configuration will be used.
You can control saving and loading using the save
and load
functions:
// NOTE: myConfig will remain empty untill a load call is applied!
// load configuration
// load retreives the configuration from local storage if the key is present;
// otherwise it retreives the default configuration
myConfig.load();
// do some changes to configuration
myConfig.foo = 'other value';
myConfig.bar = 2;
// save configuration to local storage
myConfig.save();
The Font class provides a bitmap font construct. This is useful for some games that only require a limited set of characters. The problem with regular HTML5 text routines is that they can slow the game down if the text is being redrawn over and over again. This can be solved by pre-rendering texts and then drawing those instead, but you still can't have dynamic texts unless you develop some sort of a workaround where you dynamically render only changes to the text. The other problem with text is it is very often inconsistent between browsers, where one browser will render your text slightly offset to the top, or the spacing will be different, or hinting, etc. Modern browsers are very complex in their way to render fonts and this comes with its own set of problems with regards to game development. This class essentially dumbs down font rendering by displaying text characters as if they were sprites in a tileset, and provides an interface for ease of use. You are limited to an ASCII range of characters with this class and you will also need to create your own fonts (create graphics and define character widths) to go with it.
Examples on usage can be found in the /examples/ folder.
The Tween class allows tweening (inbetweening) values in a certain range with a desired easing function. This is useful for animations and typically only used for games that use simpleLoop
(games that rely on user input to push game state forward). This is an asynchronous method - do not use in a state's update
function (or at least be very careful with how you handle it - there be dragons).
To construct a tween object:
new Tween(from, to, duration, onUpdate, onDone, easef, procf, resetf);
from
andto
define the range of the tween.duration
is a non-zero, positive number representing the time in milliseconds.onUpdate
is a callback with avalue
parameter that you can use to map the tween to a custom variable.onDone
is a callback that gets called when the tween is done executing.easef
is the easing function. Use one of the functions from myst.ease (myst.ease.linear, myst.ease.quadIn, myst.ease.quadOut, myst.ease.quadInOut, myst.ease.backIn or myst.ease.backOut) or substitute your own. Defaults to myst.ease.linear.procf
is a value post-processing pure function that takes a single number parameter and outputs a single number parameter. Leave undefined for no post-processing. You can useMath.floor
,Math.ceil
for this parameter.resetf
is a reset function intended for manually restoring or finalizing several nested tweens in order to prevent having the animation stuck in mid-state whenevertween.finish()
is called on a single level. This function will get called whenever the tween is interrupted throughtween.finish()
.
All but first three parameters are optional (use null
to skip the function parameters).
The following example tweens from 0 to 2 over 1.5 seconds with quadInOut easing:
(new myst.Tween(0, 2, 1500, function(value) {
console.log(value);
}, function() {
console.log('Tween done!');
}, myst.ease.quadInOut)).start();
The following example tweens from 100 to 0 over 2 seconds with linear easing and floors output values:
(new myst.Tween(100, 0, 2000, function(value) {
console.log(value);
}, function() {
console.log('Tween done!');
}, myst.ease.linear, Math.floor)).start();
To start a tween:
tween.start();
To restart an active tween or start an inactive one:
tween.restart();
To stop a tween:
tween.stop();
To finalize an active tween:
tween.finish();
To check if a tween is active:
let tweenIsActive = tween.isActive();
Listed here are some additional functions included with myst.js that may come in handy when developing games:
compose
takes a number of JavaScript objects and creates a single object out of them. This is useful for creating any sort of entity-component systems, as well as extending functionality of objects or simply using it for syntax sugar.
let result = myst.compose({
apples: 10
}, {
oranges: 20
});
// result: { apples: 10, oranges: 20 }
iter
iterates over members of an object, ignoring any member functions.
let object = {
pumpkins: 30,
strawberries: 40
};
myst.iter(object, function(key, item, index) {
console.log(index + ': ' + key + ' - ' + item);
});
getFilenameExtension
retreives the extension of a filename (always outputs lowercase).
let filename = 'file.json';
myst.getFilenameExtension(filename); // returns 'json'
clamp
returns a number, constrained to a given range.
myst.clamp(number, min, max);
pointInRect
checks whether a point is within a given rectangle.
myst.pointInRect(pointX, pointY, rectX, rectY, rectWidth, rectHeight);
pointInCircle
checks whether a point is within a given circle.
myst.pointInCircle(pointX, pointY, circleX, circleY, circleRadius);
linesIntersect
checks whether two line segments A-B and C-D intersect. Ignores colinearity.
myst.linesIntersect(ax, ay, bx, by, cx, cy, dx, dy);
pointToPointDistance
returns the distance from point A to point B.
myst.pointToPointDistance(ax, ay, bx, by);
pointToLineDistance
returns the distance from point to line segment A-B.
myst.pointToLineDistance(x, y, ax, ay, bx, by);
movePoint
returns a point which was moved from point A towards point B by a difference of d.
myst.movePoint(ax, ay, bx, by, d);
getRandomInt
returns an integer from a range at random.
myst.getRandomInt(min, max); // returns an integer in range [min..max]
coinFlip
returns either true or false at random.
if (myst.coinFlip()) {
console.log('heads!');
}
else {
console.log('tails!');
}
diceRoll
returns the result of a random dice roll. The parameter is the number of sides on the die - default is 6.
myst.diceRoll([N=6]); // returns an integer in range [1..N]
shuffle
shuffles an array.
myst.shuffle(array);
choose
picks an element from an array at random.
myst.choose(array);
pick
picks an element from an array at random and removes that element from the array.
myst.pick(array);