Usage
PreRequisite
Let's get this out of the way right off the bat. JackyJS is for the Web Developer. If you are new to Javascript, HTML, and CSS, you may want to get a primer on all that before taking a dive into web game development. The great news is that there are endless amounts of resources on the web, like w3schools and Mozilla Developer Network.
Here are the minimum requirements for success:
- Moderate experience with Javascript.
- Basic experience with jQuery.
- Basic experience with HTML.
- Basic experience with CSS.
- Basic experience installing a virtual server like XAMPP.
- Basic experience with Firefox/Chrome (and the console).
- High level of passion for game design!
If your qualifications loosely align with the carrots in that list, CONGRATULATIONS, you're ready to develop games with JackyJS!
The Engine
Starting up JackyJS is similar to how Javascript plugins work. You first include any dependencies like jQuery in the <head>, include the core minified JackyJS file, and include your game code like so:
<head>
<script src="jackyjs/3rd-party/jquery/jquery-1.11.2.min.js"></script>
<script src="jackyjs/3rd-party/pixi/pixi-2.2.10.min.js"></script>
<script src="jackyjs/3rd-party/howler/howler-2.0.1.min.js></script>
<script src="jackyjs/build/jacky-min.js"></script>
<script src="jackyjs/build/myNewGame.min.js"></script>
</head>
Then you place the engine's GAME.execute()
function into a container <div> in the <body> like so:
<body>
<div id="jjs-container">
<script>
GAME.execute({
name: 'MyNewGame',
width: 320,
height: 240,
scale: true,
bgColor: '#006699',
orientationLock: 'landscape'
});
</script>
</div>
</body>
As long as the container <div> has an id of "jjs-container", the engine will take it away from here, including automatically creating the canvas element and handling positioning within an arbitrary parent container. See GAME.execute() for more details.
JackyJS works in TWO different contexts:
Standalone
In this context the container <div> is placed in the <body>, with NO wrapping element. This implies that the game is meant for standalone full screen use.
Contained
In this context the container <div> is placed ANYWHERE in the <body> within any nested set of wrapping <div> elements. This implies that the game will be played as is.
NOTE: In both of these contexts JackyJS can scale your game responsively, that is, no matter what the user's browser size is, the game will proportionately scale with it. The scale option in the GAME.execute()
function is optional, and is FALSE by default. More on this later.
TIP: Even when placed within an arbitrary container, JackyJS can still go into full screen mode, with a simple call to the function GAME.fullScreen()
.
The Framework
JackyJS is more than just a game engine, it's a simple framework that ensures things go smoothly. Essentially the framework consists of init functions, separated into correspondingly named files, which require some user code to get things going. Further, JackyJS likes to keep files organized into neat-and-tidy folders, which allow you to share resources across multiple game projects. Simple.
The most important (and required) init files are the following:
GAME.initPreload()
This is where all assets are preloaded; this includes images, fonts, and sound files. Everything placed here automatically gets queued to the asset loader.
GAME.initPreload(function(){
GAME.Preloader.images.push('jackyjs/assets/backgrounds/forest.png');
GAME.Preloader.images.push('jackyjs/assets/sprites/main.png');
GAME.Preloader.images.push('jackyjs/assets/sprites/tiles.png');
GAME.Preloader.sounds.push('jackyjs/assets/sounds/gling.wav');
});
TIP: in JackyJS, "main.png" is a default Sprite filename; any sprites generated from this file don't need to be referenced in GAME.initAssets()
.
GAME.initAssets()
This is where all asset objects are initialized. An asset is like a resource that can be used over and over again when creating entities. For example, a Sprite entity can reference any Sprite asset.
GAME.initAssets(function(){
GAME.Background.asset('forest.png', {name:'forest', width:640, height:240});
GAME.Sprite.asset({name:'jacky', width:32, height:32, offsetX:0, offsetY:0});
GAME.Sprite.asset({name:'pressStart', width:128, height:32, offsetX:0, offsetY:2});
GAME.Sprite.asset('tiles.png', {name:'ground', width:16, height:16});
GAME.Sound.asset(['gling.wav'], {name:'gling'});
});
GAME.initEntities()
This is where all entities in the game are initialized. An "Entity" in JackyJS is a euphemism for "game object". Virtually everything in JackyJS is an entity, and have properties and methods.
GAME.initEntities(function(){
GAME.Background.create('forest');
GAME.Sprite.create('ground', {name:'ground', class:'block', solid:true, width:GAME.width});
var player = GAME.Sprite.create('jacky', {name:'player'});
var btnPressStart = GAME.Sprite.create('pressStart', {name:'btnPressStart', originX:0.5, originY:0.5});
player.onCreate(function(obj){
// your code here
});
player.onUpdate(function(obj){
// your code here
});
btnPressStart.onMousePress('LEFT', function(obj){
GAME.Sound.play('gling');
});
});
GAME.initRooms()
This is where all rooms are initialized and entities are instantiated. A "Room" is a euphemism for Screen, Stage, Scene, Level, etc.. It's where all the good stuff happens!
GAME.initRooms(function(){
var Intro = GAME.Room.create({name:'Intro'});
var Level1 = GAME.Room.create({name:'Level1'});
Intro.onCreate(function(obj){
obj.addSprite('pressStart', {x:GAME.width/2, y:GAME.height/2});
});
Level1.onCreate(function(obj){
obj.addBackground('forest');
obj.addSprite('ground', {x:0, y:GAME.height-16});
obj.addSprite('player', {x: 0, y: GAME.height-32});
});
});
See Classes > Room for more information.
NOTE: Without any code in the aforementioned FOUR global functions, no magic will happen. JackyJS has separated these init files into the /jackyjs/inits folder. There you will see individual game folders, which facilitate the ability to share resources across multiple game projects. You can use the /jackyjs/build/inits.php function to combine the contents of game folders into one file. This combined code should then be placed into a custom Javascript file, which should be included anywhere AFTER the minified JackyJS file in the <head> section of the webpage and BEFORE a call to your GAME.execute()
function.
Basic Example
In a nutshell, JackyJS works similar to the way most Javascript plugins do. The majority of its functions work in the following manner:
- Call a function.
- Pass an object literal of options.
- Pass an optional callback function.
GAME.find({class:'carrot'}).each(function(obj){
obj.fadeOut({to:0.5, time:2000}, function(obj){
GAME.log('NOTICE', 'Entity '+obj.name+' fade complete.');
});
});
The above code will:
- find all entities that have a class 'carrot',
- fade them to half their transparency value (over two seconds time),
- display a color-coded console message when done.
Simple.
NOTE: It is common to pass a reference to the calling object into a callback function via the obj parameter.
How It Works
JackyJS uses a simple game loop that cycles a global event(), update(), and render() function, 60 times per second. It employs Javascript's window.requestAnimationFrame()
, which basically waits for when the browser is ready to draw a frame. This ensures smooth motion graphics and animation. Under the hood, JackyJS leverages PixiJS's amazing rendering engine, which is capable of outputting massive amounts of sprites to screen. With that said, JackyJS is "loosely coupled" and thus does not extend any functions from PixiJS.
Execute
The entry point is the GAME.execute()
function. The game designer specifies basic attributes of the game by passing an object literal of options as its only parameter. Once this function is activated, internal engine logic starts the process of preparing everything before actually running the game.
The execute function is responsible for the following:
- registering your global events.
- overriding global properties with your properties.
- loading data from localStorage, if exists.
- overriding global sound presets with your presets.
- creating the canvas and determining context (standalone/container).
- setting up the splash and overlay screen (used for device rotation).
- determining device orientation, if applicable.
- initializing global event listeners.
- detecting ad blocker.
- and some other minor setup.
Once all that has completed execution, the GAME.onExecute
event is fired. See GAME.execute() for more details.
Preload
Once all that is done, the internal GAME.preload()
function runs. The preloader checks the GAME.initPreload()
function for any assets you may have assigned for preloading, and puts them into the queue. As the files are being preloaded, the customizable loader bar is displaying progress on the front-end. Once all assets have been successfully preloaded, the engine defers to the internal global GAME.init()
function, where all game related initializations take place.
Inits
This step takes care of initializing all internal inits, as well as your own. Basically every init function gets executed here; initAssets, initEntities, initRooms, etc... There is a special GAME.initCustom()
function that gets executed before all the other inits you may have defined. In the initCustom function, global constants, global variables, and global functions are defined; more on this later. Further, all sound initializations are loaded from any saved data, if applicable. Lastly, any defined Rooms are put into the pipeline.
Once all that has completed, the GAME.onInit
event is fired, and the GAME.start()
function is ready to actually start the game.
Start
At this stage, the game is basically ready to rock and roll. The first Room is determined, placed into the pipeline, and started. Thereafter, any onCreate event code defined for the first Room is executed, at which point all entities (Sprites, Backgrounds, Texts, etc..) get instantiated. Once those entities get instantiated, their respective onCreate code also gets executed.
Once the first Room has officially started, the GAME.onStart
event is fired. After that, the game actually starts rendering graphics to the screen, with a call to window.requestAnimationFrame
and looping the process ad-infinitum.
Loop
The game loop essentially repeats infinitely the following three things: check for events, update object states, and render graphics. In the event function, all active entities are cycled through, and any events that have been fired, are executed. In the update function, the state (position, size, color, etc..) of all active entities is refreshed. In the render function, a call to window.requestAnimationFrame
executes the game loop recursively. The magic has begun!
TIP: The game engine can be aborted at any time by calling the GAME.abort()
function. When this action is performed, the engine comes to a full stop, with no recovery.