1 /* 2 *Copyright (c) 2009, TellurianRing.com 3 *All rights reserved. 4 * 5 *Redistribution and use in source and binary forms, with or without modification, 6 *are permitted provided that the following conditions are met: 7 * 8 * Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * Neither the name of the Organization (TellurianRing.com) nor the names of 14 * its contributors may be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 *WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 *DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 *ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 *(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 *LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 *ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 *(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 *SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 /** 29 * @class LoadingScene Loads a given set of assets. Assets include Graphics and Sounds. 30 * @example // Displays a single message as assets are loading. 31 * LoadingScene({ 32 * steps: { 33 * "Assets": [ 34 * Graphic({ url: "./images/ball.png" }), 35 * Sound({ url: "./sounds/bang.ogg" }), 36 * ... 37 * ] 38 * } 39 * }) 40 * // This example will show the following message: 41 * // "Loading - Assets [percent]% complete, overall [percent]% complete" 42 * @example // Having two steps for images and sounds. 43 * LoadingScene({ 44 * steps: { 45 * "Graphics": [ 46 * Graphic({ url: "./images/ball.png" }), 47 * ... 48 * ], 49 * "Sounds": [ 50 * Sound({ url: "./sounds/bang.ogg" }), 51 * ... 52 * ] 53 * } 54 * }) 55 * @example // You can also supply your own content. 56 * // Say you want to display your own background image as the assets are loading 57 * LoadingScene({ 58 * steps: { 59 * "Assets": [ 60 * Graphic({ url: "./images/ball.png" }), 61 * Sound({ url: "./sounds/bang.ogg" }), 62 * ... 63 * ] 64 * }, 65 * content: [ 66 * Graphic({ url: "./images/loading_bg.png" }) 67 * ] 68 * }) 69 * @param {Object} _details A JSON object with the following properties. 70 * <table cellpadding="0" cellspacing="1" border="0" class="constructor_details"> 71 * <tr><th>Property</th> <th>Required</th> <th>Default</th></tr> 72 * <tr><td>content</td> <td>no</td> <td></td></tr> 73 * <tr><td>steps</td> <td>no</td> <td></td></tr> 74 * </table> 75 */ 76 function LoadingScene(_details) { // {{{ 77 function _LoadingScene(_details) { // {{{ 78 79 // Private Members {{{ 80 var content = _details.content; 81 var current_step = 0; 82 var finished = false; 83 var step_loaded = 0; 84 var step_loading = 0; 85 var step_names = new Array(); 86 var step_totals = {}; 87 var steps = check(_details.steps, {}); 88 var that = this; 89 var total = 0; 90 var total_loaded = 0; 91 var total_loading = 0; 92 // }}} Private Members 93 94 // Public Members {{{ 95 /** 96 * Creates the default content for this LoadingScene. The default content 97 * is a Text object which displays the following message in the middle of 98 * the scene: 99 * "Loading - [step] [percent]% complete, overall [percent]% complete" 100 * @function 101 */ 102 this.createDefaultContent = function() { // {{{ 103 var scene_bounds = this.getScene().getBounds(); 104 var defaultContent = [ 105 Text({ 106 x: scene_bounds.w / 2, y: scene_bounds.h / 2, 107 align: Text.Align.center, font: Font({ size: "16px", weight: Font.Weights.bold }), 108 update: function(_run_time, _step, _step_percent, _total_percent, _finished) { 109 var text = "Loading - " + _step + " " + Math.round(_step_percent * 100) + "% complete, overall " + Math.round(_total_percent * 100) + "% complete"; 110 if(_finished) { 111 text = "Loaded!"; 112 } 113 this.setText(text); 114 } 115 }) 116 ]; 117 return defaultContent; 118 } // }}} createDefaultContent 119 120 this.draw = function(_context) { // {{{ 121 for(var ci in content) { 122 var component = content[ci]; 123 component.draw(_context); 124 } 125 } // }}} draw 126 127 /** 128 * @function called when all the assets have been loaded. Calls finish 129 * function of details if one is provided. This function can be used to 130 * set the scene on the stage after the assets have been loaded. 131 * @example 132 * var stage = Stage({ 133 * scene: Scene({ 134 * content: [ 135 * LoadingScene({ 136 * steps: { ... }, 137 * finished: function() { 138 * stage.unload(); stage.setScene(nextScene); stage.load(); 139 * } 140 * }) 141 * ] 142 * }) 143 * }); 144 */ 145 this.finish = function() { // {{{ 146 finished = true; 147 if(exists(this.details.finish)) { 148 details.finish(); 149 } 150 } // }}} finish 151 152 /** 153 * Loads any content provided then starts the loader thread to preload 154 * any assets provided in the steps. 155 * @function 156 */ 157 this.load = function(_scene, _parent) { // {{{ 158 this.loadBase(_scene, _parent); 159 if(!exists(content)) { 160 content = this.createDefaultContent(); 161 } 162 163 // Load content. 164 for(var ci in content) { 165 var component = content[ci]; 166 component.load(_scene, that); 167 } 168 169 // set up the info. 170 var stepCount = 0; 171 for(var si in steps) { 172 var step = steps[si]; 173 step_names[stepCount] = si; 174 var assetCount = 0; 175 for(var ai in step) { 176 var asset = step[ai]; 177 assetCount++; 178 total++; 179 } 180 step_totals[si] = assetCount; 181 stepCount++; 182 } 183 // start the loading thread 184 setTimeout(this.loadNextAsset, 30); 185 } // }}} load 186 187 188 /** 189 * Loads the next asset in the current step. 190 * @function 191 */ 192 this.loadNextAsset = function() { // {{{ 193 var step_name = step_names[current_step]; 194 var step = steps[step_name]; 195 // get next current asset and increment loading variables. 196 var asset = step[step_loading++]; total_loading++; 197 asset.details.onload = function() { 198 // increment loaded variables. 199 total_loaded++; step_loaded++; 200 if(step_loading < step_totals[step_name]) { 201 // if loading is less than total number of assets for current step 202 // we load the next one. 203 setTimeout(that.loadNextAsset, 30); 204 } else if (++current_step < step_names.length) { 205 // else if the next current_step is less than total number of steps 206 // start on the next step. 207 step_loaded = 0; 208 step_loading = 0; 209 setTimeout(that.loadNextAsset, 30); 210 } else { 211 // we're done. 212 that.finish(); 213 } 214 }; 215 asset.load(that.getScene(), that); 216 } // }}} loadNextAsset 217 218 /** 219 * Updates all content within this LoadingScene. This update function 220 * differs from the Scene object because it passes extra information to 221 * each content. It calls each component's update function with the 222 * following: 223 * <table cellpadding="0" cellspacing="1" border="0" class="constructor_details"> 224 * <tr><th>Property</th> <th>Type</th> <th>Description</th></tr> 225 * <tr><td>runtime</td> <td>Integer</td> <td>Current time in milliseconds since the scene was loaded.</td></tr> 226 * <tr><td>step</td> <td>String</td> <td>Current step name as defined in the _details object.</td></tr> 227 * <tr><td>step_percent</td> <td>Decimal</td> <td>Percent complete within the current step.</td></tr> 228 * <tr><td>total_percent</td> <td>Decimal</td> <td>Percent complete overall.</td></tr> 229 * <tr><td>finished</td> <td>Boolean</td> <td>Have all the assets been loaded.</td></tr> 230 * </table> 231 * @function 232 */ 233 this.update = function(_run_time) { // {{{ 234 var current_step_name = step_names[current_step]; 235 var step_total = step_totals[current_step_name]; 236 for(var ci in content) { 237 var component = content[ci]; 238 component.update(_run_time, current_step_name, step_loaded / step_total, total_loaded / total, finished); 239 } 240 } // }}} update 241 242 // }}} Public Members 243 } // }}} _LoadingScene 244 SceneContent(_details).extend(_LoadingScene); 245 var theLoadingScene = new _LoadingScene(_details); 246 return theLoadingScene; 247 } // }}} LoadingScene 248 // These properties are for jEdit - Programmer's Text Editor. 249 // Load this file in jEdit to see what they do. 250 // ::folding=explicit:mode=javascript:noTabs=true:collapseFolds=4:: 251