Game Life Cycle
Game's life cycle is exactly the same as common Moscrif native application. Immediately after a game starts, a splash screen is displayed. After that Game.start is invoked. Splash screen is delayed until this event is completly finished. That means, you should load mostly used game resources in the Game.start event. The good practice is to prepare all mostly used graphics, sounds, data during the splash screen. Users expect to wait a few seconds for starting the game, but don't expect to wait any longer after they click on "new game" button.
// create new game instance var game = new Game(); // prepare game instance before its run
game.onStart = function()
{
// load graphics
GFX.load();
//load sounds and musics
SFX.load();
// create menu scene
this.menu = new MenuScene();
// start with menu scene
this.push(this.menu); } game.run();
Note, If you like more object oriented code, you will overwrite the start method instead of handling the onStart event.
class MyGame : Game { // prepare game instance before its run
function start()
{
// load graphics
GFX.load();
//load sounds and musics
SFX.load();
// create menu scene
this.menu = new MenuScene();
// start with menu scene
this.push(this.menu);
}
} new MyGame().run();
Loading Resources
As mentioned before, the best place to load external graphics, sounds, musics, fonts, data, etc. is Game.onStart/Game.start. This is especially true for frequently used objects (game backgrounds, buttons, sprites, HUD, etc). Whereas these objects are used often, wrapping classes will be implemented as static and/or with static members only. Let's say graphics resources are wrapped by GFX class:
// This class manages graphical resources such as bitmaps, vectors etc. class GFX
{
// root dir for graphics files
const root = "app://gfx/"; // static bitmap for game's background
var background;
// ... etc // this function is also static
function load()
{
assert this === GFX;
background = Bitmap.fromFile(root + "background.jpg");
// ... etc
} }
Loading of the GFX, called within Game.onStart/Game.start can look like:
class MyGame : Game { // prepare game instance before its run function start()
{
// load graphics
GFX.load();
// … etc
} }
… and the usage of the GFX and its fields will be pretty straightforward:
function draw(canvas) {
canvas.drawBitmap(GFX.background, 0, 0);
// ... other drawings ... }
Source File Optimalization
If you want to deliver a high quality game, the graphics must be high quality too. That's a problem nowadays because you have to cope with a big fragmentation of screen resolutions. Probably you will have to embed several sets of graphics which leads to a bigger installation files. Here are some tools, that can reduce an image size:
Scalable vector graphics (SVG) allows you to solve screen fragmentation very effectively, but you have to keep it in mind before you start developing. Even though SVG will also reduce file size drastically, it isn't applicable for all scenarios (e.g.: backgrounds, pixel-art graphics)...
See Canvas.path and Path class for more info related to SVG in Moscrif.
Use the Advantages of Offscreen rendering
Moscrif uses OpenGL for drawing elements which renders the graphics to the devices window directly using GPU (if present). Moscrif also allows you to use advanced techniques such as: a drawing of a shadows or an outlines, several types of gradients, applying an effects to a fonts and/or a bitmaps, an advanced color and mask filters, a basic image effects like blur, dilate, erode etc… But these advanced techniques do additional computation out of GPU. As a result, using these advanced features can decrease performance (for 40-50FPS down to 20FPS or less).
In this case, the offscreen rendering makes a sense. The offscreen render is an approach, where you don't draw directly to the screen, but to memory (bitmap rather) instead.All complicated drawings are pre-rendered, like the following:
include "lib://core/log.ms" include "lib://game2d/game.ms"
include "app://gfx.ms" // custom game class
class Offscreen : Game
{
function start()
{
super.start(); // load graphical resources
GFX.load(); // offscreen drawing
this._offscreen = Bitmap.fromRect(200, 200); // created offscreen bitmap
var canvas = Canvas.fromBitmap(this._offscreen); // get canvas to paint to
var paint = new Paint();
paint.imageFilter = ImageFilter.blur(5, 5); // apply blur filter to a bitmap
canvas.drawBitmap(GFX.box, (this._offscreen.width - GFX.box.width)/2, (this._offscreen.height - GFX.box.height)/2, paint); // prepare game with two sprites, the first on has "normal" bitmap, the second one has bitmap altered by "advance" method
this._initSprites(GFX.box, this._offscreen);
} function draw(canvas)
{
// custom drawings - background
canvas.drawBitmap(GFX.background, 0, 0);
// default drawings
super.draw(canvas);
} function process()
{
// just rotate all sprites
for (var sprite in this._sprites)
sprite.angle += 0.1;
} function _initSprites(normal, offscreen)
{
// create the first sprite
this.add(new Sprite({image:normal, x:System.width/3, y:System.height/2}));
// create the second sprite
this.add(new Sprite({image:offscreen, x:System.width/3*2, y:System.height/2}));
} } // create instace and run the game new Offscreen().run();
In this example there is just one bitmap used for sprites. The first sprite, displayed on the left side of the screenshot uses "normal" bitmap. No special effects, just simple bitmap.

The second sprite, shown on the right side of the screenshot is based on the same bitmap, but there is advanced technique applied (a blur image effect). Check out the result:

Imagine how many awesome things can be done using offscreen rendering. Some examples of things that can leverage offscreen:
- using SVG to reduce file size but keep high quality, This saves you from screen resolution fragmentation
- applying effects to fonts or images without additional resources
- pre-rendering complicated game objects or scenes
- etc...
|