浏览代码

Animations (easing part) manual improvements (#37)

* animation manuals fixes

* sorting fix

* Removed broken links

* Fixed part with the links to images

* insert Easing example

* Fix links for manual

* replace example

* Update animation.md

Review fixes
Alexey Gulev 6 年之前
父节点
当前提交
82c03c58e2

+ 1 - 0
docs/assets/easier/archive/archive_files.json

@@ -0,0 +1 @@
+{"content":[{"name":"game.projectc","size":2310,"pieces":[{"name":"game.projectc0","offset":0}]},{"name":"game.arci","size":3088,"pieces":[{"name":"game.arci0","offset":0}]},{"name":"game.arcd","size":113454,"pieces":[{"name":"game.arcd0","offset":0}]},{"name":"game.dmanifest","size":5772,"pieces":[{"name":"game.dmanifest0","offset":0}]},{"name":"game.public.der","size":162,"pieces":[{"name":"game.public.der0","offset":0}]}]}

二进制
docs/assets/easier/archive/game.arcd0


二进制
docs/assets/easier/archive/game.arci0


二进制
docs/assets/easier/archive/game.dmanifest0


+ 144 - 0
docs/assets/easier/archive/game.projectc0

@@ -0,0 +1,144 @@
+[project]
+title = easier
+version = 1.0
+write_log = 0
+compress_archive = 1
+
+[display]
+width = 640
+height = 512
+high_dpi = 0
+samples = 0
+fullscreen = 0
+update_frequency = 0
+vsync = 1
+display_profiles = /builtins/render/default.display_profilesc
+dynamic_orientation = 0
+
+[physics]
+type = 2D
+gravity_y = -10
+debug = 0
+debug_alpha = 0.9
+world_count = 4
+gravity_x = 0
+gravity_z = 0
+scale = 1
+debug_scale = 30
+max_collisions = 64
+max_contacts = 128
+contact_impulse_limit = 0
+ray_cast_limit_2d = 64
+ray_cast_limit_3d = 128
+trigger_overlap_capacity = 16
+
+[bootstrap]
+main_collection = /main/main.collectionc
+render = /builtins/render/default.renderc
+
+[graphics]
+default_texture_min_filter = linear
+default_texture_mag_filter = linear
+max_draw_calls = 1024
+max_characters = 8192
+max_debug_vertices = 10000
+texture_profiles = /builtins/graphics/default.texture_profiles
+
+[sound]
+gain = 1
+max_sound_data = 128
+max_sound_buffers = 32
+max_sound_sources = 16
+max_sound_instances = 256
+
+[resource]
+http_cache = 0
+max_resources = 1024
+
+[input]
+repeat_delay = 0.5
+repeat_interval = 0.2
+gamepads = /builtins/input/default.gamepadsc
+game_binding = /input/game.input_bindingc
+use_accelerometer = 1
+
+[sprite]
+max_count = 128
+subpixels = 1
+
+[spine]
+max_count = 128
+
+[model]
+max_count = 128
+
+[gui]
+max_count = 64
+max_particlefx_count = 64
+max_particle_count = 1024
+
+[collection]
+max_instances = 1024
+
+[collection_proxy]
+max_count = 8
+
+[collectionfactory]
+max_count = 128
+
+[factory]
+max_count = 128
+
+[ios]
+pre_renderered_icons = 0
+bundle_identifier = example.unnamed
+infoplist = /builtins/manifests/ios/Info.plist
+
+[android]
+version_code = 1
+package = com.example.todo
+manifest = /builtins/manifests/android/AndroidManifest.xml
+iap_provider = GooglePlay
+input_method = KeyEvent
+immersive_mode = 0
+debuggable = 0
+
+[osx]
+infoplist = /builtins/manifests/osx/Info.plist
+bundle_identifier = example.unnamed
+
+[windows]
+
+[html5]
+custom_heap_size = 0
+include_dev_tool = 0
+htmlfile = /builtins/manifests/web/engine_template.html
+archive_location_prefix = archive
+
+[particle_fx]
+max_count = 64
+max_particle_count = 1024
+
+[iap]
+auto_finish_transactions = 1
+
+[network]
+http_timeout = 0
+
+[library]
+
+[script]
+shared_state = 1
+
+[tracking]
+
+[label]
+max_count = 64
+subpixels = 1
+
+[profiler]
+track_cpu = 0
+
+[liveupdate]
+settings = /liveupdate.settings
+

二进制
docs/assets/easier/archive/game.public.der0


二进制
docs/assets/easier/defold_sound.swf


+ 652 - 0
docs/assets/easier/dmloader.js

@@ -0,0 +1,652 @@
+/* ********************************************************************* */
+/* Load and combine data that is split into archives                     */
+/* ********************************************************************* */
+
+var Combine = {
+    _targets: [],
+    _targetIndex: 0,
+    // target: build target
+    //  name: intended filepath of built object
+    //  size: expected size of built object.
+    //  data: combined data
+    //  downloaded: total amount of data downloaded
+    //  pieces: array of name, offset and data objects
+    //  numExpectedFiles: total number of files expected in description
+    //  lastRequestedPiece: index of last data file requested (strictly ascending)
+    //  totalLoadedPieces: counts the number of data files received
+
+    //MAX_CONCURRENT_XHR: 6,    // remove comment if throttling of XHR is desired.
+
+    isCompleted: false,       // status of process
+
+    _onCombineCompleted: [],    // signature: name, data.
+    _onAllTargetsBuilt:[],      // signature: void
+    _onDownloadProgress: [],    // signature: downloaded, total
+
+    _totalDownloadBytes: 0,
+    _archiveLocationFilter: function(path) { return "split" + path; },
+
+    addProgressListener: function(callback) {
+        if (typeof callback !== 'function') {
+            throw "Invalid callback registration";
+        }
+        this._onDownloadProgress.push(callback);
+    },
+
+    addCombineCompletedListener: function(callback) {
+        if (typeof callback !== 'function') {
+            throw "Invalid callback registration";
+        }
+        this._onCombineCompleted.push(callback);
+    },
+
+    addAllTargetsBuiltListener: function(callback) {
+        if (typeof callback !== 'function') {
+            throw "Invalid callback registration";
+        }
+        this._onAllTargetsBuilt.push(callback);
+    },
+
+    // descriptUrl: location of text file describing files to be preloaded
+    process: function(descriptUrl) {
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', descriptUrl);
+        xhr.responseType = 'text';
+        xhr.onload = function(evt) {
+            Combine.onReceiveDescription(xhr);
+        };
+        xhr.send(null);
+    },
+
+    cleanUp: function() {
+        this._targets =  [];
+        this._targetIndex = 0;
+        this.isCompleted = false;
+        this._onCombineCompleted = [];
+        this._onAllTargetsBuilt = [];
+        this._onDownloadProgress = [];
+
+        this._totalDownloadBytes = 0;
+    },
+
+    onReceiveDescription: function(xhr) {
+        var json = JSON.parse(xhr.responseText);
+        this._targets = json.content;
+        this._totalDownloadBytes = 0;
+
+        var targets = this._targets;
+        for(var i=0; i<targets.length; ++i) {
+            this._totalDownloadBytes += targets[i].size;
+        }
+        this.requestContent();
+    },
+
+    requestContent: function() {
+        var target = this._targets[this._targetIndex];
+        if (1 < target.pieces.length) {
+            target.data = new Uint8Array(target.size);
+        }
+        var limit = target.pieces.length;
+        if (typeof this.MAX_CONCURRENT_XHR !== 'undefined') {
+            limit = Math.min(limit, this.MAX_CONCURRENT_XHR);
+        }
+        for (var i=0; i<limit; ++i) {
+            this.requestPiece(target, i);
+        }
+    },
+
+    requestPiece: function(target, index) {
+        if (index <  target.lastRequestedPiece) {
+            throw "Request out of order";
+        }
+
+        target.lastRequestedPiece = index;
+        target.progress = {};
+
+        var item = target.pieces[index];
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', this._archiveLocationFilter('/' + item.name), true);
+        xhr.responseType = 'arraybuffer';
+        xhr.onprogress = function(evt) {
+           target.progress[item.name] = {total: 0, downloaded: 0};
+            if (evt.total && evt.lengthComputable) {
+                target.progress[item.name].total = evt.total;
+            }
+            if (evt.loaded && evt.lengthComputable) {
+                target.progress[item.name].downloaded = evt.loaded;
+                Combine.updateProgress(target);
+            }
+        };
+        xhr.onload = function(evt) {
+            item.data = new Uint8Array(xhr.response);
+            item.dataLength = item.data.length;
+            target.progress[item.name].total = item.dataLength;
+            target.progress[item.name].downloaded = item.dataLength;
+            Combine.copyData(target, item);
+            Combine.onPieceLoaded(target, item);
+            Combine.updateProgress(target);
+            item.data = undefined;
+        };
+        xhr.send(null);
+    },
+
+    updateProgress: function(target) {
+        var total_downloaded = 0;
+        for (var p in target.progress) {
+            total_downloaded += target.progress[p].downloaded;
+        }
+        for(i = 0; i<this._onDownloadProgress.length; ++i) {
+            this._onDownloadProgress[i](total_downloaded, this._totalDownloadBytes);
+        }
+    },
+
+    copyData: function(target, item) {
+        if (1 == target.pieces.length) {
+            target.data = item.data;
+        } else {
+            var start = item.offset;
+            var end = start + item.data.length;
+            if (0 > start) {
+                throw "Buffer underflow";
+            }
+            if (end > target.data.length) {
+                throw "Buffer overflow";
+            }
+            target.data.set(item.data, item.offset);
+        }
+    },
+
+    onPieceLoaded: function(target, item) {
+        if (typeof target.totalLoadedPieces === 'undefined') {
+            target.totalLoadedPieces = 0;
+        }
+        ++target.totalLoadedPieces;
+        if (target.totalLoadedPieces == target.pieces.length) {
+            this.finalizeTarget(target);
+            ++this._targetIndex;
+            for (var i=0; i<this._onCombineCompleted.length; ++i) {
+                this._onCombineCompleted[i](target.name, target.data);
+            }
+            if (this._targetIndex < this._targets.length) {
+                this.requestContent();
+            } else {
+                this.isCompleted = true;
+                for (i=0; i<this._onAllTargetsBuilt.length; ++i) {
+                    this._onAllTargetsBuilt[i]();
+                }
+            }
+        } else {
+            var next = target.lastRequestedPiece + 1;
+            if (next < target.pieces.length) {
+                this.requestPiece(target, next);
+            }
+        }
+    },
+
+    finalizeTarget: function(target) {
+        var actualSize = 0;
+        for (var i=0;i<target.pieces.length; ++i) {
+            actualSize += target.pieces[i].dataLength;
+        }
+        if (actualSize != target.size) {
+            throw "Unexpected data size";
+        }
+
+        if (1 < target.pieces.length) {
+            var output = target.data;
+            var pieces = target.pieces;
+            for (i=0; i<pieces.length; ++i) {
+                var item = pieces[i];
+                // Bounds check
+                var start = item.offset;
+                var end = start + item.dataLength;
+                if (0 < i) {
+                    var previous = pieces[i - 1];
+                    if (previous.offset + previous.dataLength > start) {
+                        throw "Segment underflow";
+                    }
+                }
+                if (pieces.length - 2 > i) {
+                    var next = pieces[i + 1];
+                    if (end > next.offset) {
+                        throw "Segment overflow";
+                    }
+                }
+            }
+        }
+    }
+};
+
+/* ********************************************************************* */
+/* Default splash and progress visualisation                             */
+/* ********************************************************************* */
+
+var Progress = {
+    progress_id: "defold-progress",
+    bar_id: "defold-progress-bar",
+
+    addProgress : function (canvas) {
+        /* Insert default progress bar below canvas */
+        canvas.insertAdjacentHTML('afterend', '<div id="' + Progress.progress_id + '" class="canvas-app-progress"><div id="' + Progress.bar_id + '" class="canvas-app-progress-bar" style="width: 0%;">0%</div></div>');
+        Progress.bar = document.getElementById(Progress.bar_id);
+        Progress.progress = document.getElementById(Progress.progress_id);
+    },
+
+    updateProgress: function (percentage, text) {
+        Progress.bar.style.width = percentage + "%";
+
+        text = (typeof text === 'undefined') ? Math.round(percentage) + "%" : text;
+        Progress.bar.innerText = text;
+    },
+
+    removeProgress: function () {
+        if (Progress.progress.parentElement !== null) {
+            Progress.progress.parentElement.removeChild(Progress.progress);
+
+            // Remove any background/splash image that was set in runApp().
+            // Workaround for Safari bug DEF-3061.
+            Module.canvas.style.background = "";
+            Module["on_game_start"]();
+        }
+    }
+};
+
+/* ********************************************************************* */
+/* Default input override                                                */
+/* ********************************************************************* */
+
+var CanvasInput = {
+    arrowKeysHandler : function(e) {
+        switch(e.keyCode) {
+            case 37: case 38: case 39:  case 40: // Arrow keys
+            case 32: e.preventDefault(); e.stopPropagation(); // Space
+            default: break; // do not block other keys
+        }
+    },
+
+    onFocusIn : function(e) {
+        window.addEventListener("keydown", CanvasInput.arrowKeysHandler, false);
+    },
+
+    onFocusOut: function(e) {
+        window.removeEventListener("keydown", CanvasInput.arrowKeysHandler, false);
+    },
+
+    addToCanvas : function(canvas) {
+        canvas.addEventListener("focus", CanvasInput.onFocusIn, false);
+        canvas.addEventListener("blur", CanvasInput.onFocusOut, false);
+        canvas.focus();
+        CanvasInput.onFocusIn();
+    }
+};
+
+/* ********************************************************************* */
+/* Module is Emscripten namespace                                        */
+/* ********************************************************************* */
+
+var Module = {
+    noInitialRun: true,
+
+    _filesToPreload: [],
+    _archiveLoaded: false,
+    _preLoadDone: false,
+    _waitingForArchive: false,
+
+    // Persistent storage
+    persistentStorage: true,
+    _syncInProgress: false,
+    _syncNeeded: false,
+    _syncInitial: false,
+    _syncMaxTries: 3,
+    _syncTries: 0,
+
+    print: function(text) { console.log(text); },
+    printErr: function(text) { console.error(text); },
+
+    setStatus: function(text) { console.log(text); },
+
+    isWASMSupported: (function() {
+        try {
+            if (typeof WebAssembly === "object"
+                && typeof WebAssembly.instantiate === "function") {
+                const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
+                if (module instanceof WebAssembly.Module)
+                    return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
+            }
+        } catch (e) {
+        }
+        return false;
+    })(),
+
+    prepareErrorObject: function (err, url, line, column, errObj) {
+        line = typeof line == "undefined" ? 0 : line;
+        column = typeof column == "undefined" ? 0 : column;
+        url = typeof url == "undefined" ? "" : url;
+        var errorLine = url + ":" + line + ":" + column;
+
+        var error = errObj || (typeof window.event != "undefined" ? window.event.error : "" ) || err || "Undefined Error";
+        var message = "";
+        var stack = "";
+        var backtrace = "";
+
+        if (typeof error == "object" && typeof error.stack != "undefined" && typeof error.message != "undefined") {
+            stack = String(error.stack);
+            message = String(error.message);
+        } else {
+            stack = String(error).split("\n");
+            message = stack.shift();
+            stack = stack.join("\n");
+        }
+        stack = stack || errorLine;
+
+        var callLine = /at (\S+:\d*$)/.exec(message);
+        if (callLine) {
+            message = message.replace(/(at \S+:\d*$)/, "");
+            stack = callLine[1] + "\n" + stack;
+        }
+
+        message = message.replace(/(abort\(.+\)) at .+/, "$1");
+        stack = stack.replace(/\?{1}\S+(:\d+:\d+)/g, "$1");
+        stack = stack.replace(/ *at (\S+)$/gm, "@$1");
+        stack = stack.replace(/ *at (\S+)(?: \[as \S+\])? +\((.+)\)/g, "$1@$2");
+        stack = stack.replace(/^((?:Object|Array)\.)/gm, "");
+        stack = stack.split("\n");
+
+        return { stack:stack, message:message };
+    },
+
+    hasWebGLSupport: function() {
+        var webgl_support = false;
+        try {
+            var canvas = document.createElement("canvas");
+            var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+            if (gl && gl instanceof WebGLRenderingContext) {
+                webgl_support = true;
+            }
+        } catch (error) {
+            console.log("An error occurred while detecting WebGL support: " + error);
+            webgl_support = false;
+        }
+
+        return webgl_support;
+    },
+
+    handleVisibilityChange: function () {
+        GLFW.onFocusChanged(document[Module.hiddenProperty] ? 0 : 1);
+    },
+
+    getHiddenProperty: function () {
+        if ('hidden' in document) return 'hidden';
+        var prefixes = ['webkit','moz','ms','o'];
+        for (var i = 0; i < prefixes.length; i++){
+            if ((prefixes[i] + 'Hidden') in document)
+                return prefixes[i] + 'Hidden';
+        }
+        return null;
+    },
+
+    setupVisibilityChangeListener: function() {
+        Module.hiddenProperty = Module.getHiddenProperty();
+        if( Module.hiddenProperty ) {
+            var eventName = Module.hiddenProperty.replace(/[H|h]idden/,'') + 'visibilitychange';
+            document.addEventListener(eventName, Module.handleVisibilityChange, false);
+        } else {
+            console.log("No document.hidden property found. The focus events won't be enabled.")
+        }
+    },
+
+    /**
+    * Module.runApp - Starts the application given a canvas element id
+    *
+    * 'extra_params' is an optional object that can have the following fields:
+    *
+    *     'splash_image':
+    *         Path to an image that should be used as a background image for
+    *         the canvas element.
+    *
+    *     'archive_location_filter':
+    *         Filter function that will run for each archive path.
+    *
+    *     'unsupported_webgl_callback':
+    *         Function that is called if WebGL is not supported.
+    *
+    *     'engine_arguments':
+    *         List of arguments (strings) that will be passed to the engine.
+    *
+    *     'persistent_storage':
+    *         Boolean toggling the usage of persistent storage.
+    *
+    *     'custom_heap_size':
+    *         Number of bytes specifying the memory heap size.
+    *
+    *     'disable_context_menu':
+    *         Disables the right-click context menu on the canvas element if true.
+    *
+    **/
+    runApp: function(app_canvas_id, extra_params) {
+        app_canvas_id = (typeof app_canvas_id === 'undefined') ?  'canvas' : app_canvas_id;
+
+        var params = {
+            splash_image: undefined,
+            archive_location_filter: function(path) { return 'split' + path; },
+            unsupported_webgl_callback: undefined,
+            engine_arguments: [],
+            persistent_storage: true,
+            custom_heap_size: undefined,
+            disable_context_menu: true
+        };
+
+        for (var k in extra_params) {
+            if (extra_params.hasOwnProperty(k)) {
+                params[k] = extra_params[k];
+            }
+        }
+
+        Module.canvas = document.getElementById(app_canvas_id);
+        if (typeof params["splash_image"] !== 'undefined') {
+            Module.canvas.style.background = 'no-repeat center url("' + params["splash_image"] + '")';
+        }
+        Module.arguments = params["engine_arguments"];
+        Module.persistentStorage = params["persistent_storage"];
+        Module["TOTAL_MEMORY"] = params["custom_heap_size"];
+        Module["on_game_start"] = params["game_start"];
+
+        if (Module.hasWebGLSupport()) {
+            // Override game keys
+            CanvasInput.addToCanvas(Module.canvas);
+
+            Module.setupVisibilityChangeListener();
+
+            // Add progress visuals
+            Progress.addProgress(Module.canvas);
+
+            // Add context menu hide-handler if requested
+            if (params["disable_context_menu"])
+            {
+                Module.canvas.oncontextmenu = function(e) {
+                    e.preventDefault();
+                };
+            }
+
+            // Load and assemble archive
+            Combine.addCombineCompletedListener(Module.onArchiveFileLoaded);
+            Combine.addAllTargetsBuiltListener(Module.onArchiveLoaded);
+            Combine.addProgressListener(Module.onArchiveLoadProgress);
+            Combine._archiveLocationFilter = params["archive_location_filter"];
+            Combine.process(Combine._archiveLocationFilter('/archive_files.json'));
+        } else {
+            Progress.addProgress(Module.canvas);
+            Progress.updateProgress(100, "Unable to start game, WebGL not supported");
+            Module.setStatus = function(text) {
+                if (text) Module.printErr('[missing WebGL] ' + text);
+            };
+
+            if (typeof params["unsupported_webgl_callback"] === "function") {
+                params["unsupported_webgl_callback"]();
+            }
+        }
+    },
+
+    onArchiveLoadProgress: function(downloaded, total) {
+        Progress.updateProgress(downloaded / total * 100);
+    },
+
+    onArchiveFileLoaded: function(name, data) {
+        Module._filesToPreload.push({path: name, data: data});
+    },
+
+    onArchiveLoaded: function() {
+        Combine.cleanUp();
+        Module._archiveLoaded = true;
+        Progress.updateProgress(100, "Starting...");
+
+        if (Module._waitingForArchive) {
+            Module._preloadAndCallMain();
+        }
+    },
+
+    toggleFullscreen: function() {
+        if (GLFW.isFullscreen) {
+            GLFW.cancelFullScreen();
+        } else {
+            GLFW.requestFullScreen();
+        }
+    },
+
+    preSync: function(done) {
+        // Initial persistent sync before main is called
+        FS.syncfs(true, function(err) {
+            if(err) {
+                Module._syncTries += 1;
+                console.error("FS syncfs error: " + err);
+                if (Module._syncMaxTries > Module._syncTries) {
+                    Module.preSync(done);
+                } else {
+                    Module._syncInitial = true;
+                    done();
+                }
+            } else {
+                Module._syncInitial = true;
+                if (done !== undefined) {
+                    done();
+                }
+            }
+        });
+    },
+
+    preloadAll: function() {
+        if (Module._preLoadDone) {
+            return;
+        }
+        Module._preLoadDone = true;
+        for (var i = 0; i < Module._filesToPreload.length; ++i) {
+            var item = Module._filesToPreload[i];
+            FS.createPreloadedFile("", item.path, item.data, true, true);
+        }
+    },
+
+    // Tries to do a MEM->IDB sync
+    // It will flag that another one is needed if there is already one sync running.
+    persistentSync: function() {
+
+        // Need to wait for the initial sync to finish since it
+        // will call close on all its file streams which will trigger
+        // new persistentSync for each.
+        if (Module._syncInitial) {
+            if (Module._syncInProgress) {
+                Module._syncNeeded = true;
+            } else {
+                Module._startSyncFS();
+            }
+        }
+    },
+
+    preInit: [function() {
+        /* Mount filesystem on preinit */
+        var dir = DMSYS.GetUserPersistentDataRoot();
+        FS.mkdir(dir);
+
+        // If IndexedDB is supported we mount the persistent data root as IDBFS,
+        // then try to do a IDB->MEM sync before we start the engine to get
+        // previously saved data before boot.
+        window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+        if (Module.persistentStorage && window.indexedDB) {
+            FS.mount(IDBFS, {}, dir);
+
+            // Patch FS.close so it will try to sync MEM->IDB
+            var _close = FS.close; FS.close = function(stream) { var r = _close(stream); Module.persistentSync(); return r; }
+
+            // Sync IDB->MEM before calling main()
+            Module.preSync(function() {
+                Module._preloadAndCallMain();
+            });
+        } else {
+            Module._preloadAndCallMain();
+        }
+    }],
+
+    preRun: [function() {
+        /* If archive is loaded, preload all its files */
+        if(Module._archiveLoaded) {
+            Module.preloadAll();
+        }
+    }],
+
+    postRun: [function() {
+        if(Module._archiveLoaded) {
+            Progress.removeProgress();
+        }
+    }],
+
+    _preloadAndCallMain: function() {
+        // If the archive isn't loaded,
+        // we will have to wait with calling main.
+        if (!Module._archiveLoaded) {
+            Module._waitingForArchive = true;
+        } else {
+
+            // Need to set heap size before calling main
+            TOTAL_MEMORY = Module["TOTAL_MEMORY"] || TOTAL_MEMORY;
+
+            Module.preloadAll();
+            Progress.removeProgress();
+            if (Module.callMain === undefined) {
+                Module.noInitialRun = false;
+            } else {
+                Module.callMain(Module.arguments);
+            }
+        }
+    },
+
+    // Wrap IDBFS syncfs call with logic to avoid multiple syncs
+    // running at the same time.
+    _startSyncFS: function() {
+        Module._syncInProgress = true;
+
+        if (Module._syncMaxTries > Module._syncTries) {
+            FS.syncfs(false, function(err) {
+                Module._syncInProgress = false;
+
+                if (err) {
+                    console.error("Module._startSyncFS error: " + err);
+                    Module._syncTries += 1;
+                }
+
+                if (Module._syncNeeded) {
+                    Module._syncNeeded = false;
+                    Module._startSyncFS();
+                }
+
+            });
+        }
+    },
+};
+
+window.onerror = function(err, url, line, column, errObj) {
+    var errorObject = Module.prepareErrorObject(err, url, line, column, errObj);
+    Module.ccall('JSWriteDump', 'null', ['string'], [JSON.stringify(errorObject.stack)]);
+    Module.setStatus('Exception thrown, see JavaScript console');
+    Module.setStatus = function(text) {
+        if (text) Module.printErr('[post-exception status] ' + text);
+    };
+};

二进制
docs/assets/easier/easier.wasm


文件差异内容过多而无法显示
+ 0 - 0
docs/assets/easier/easier_asmjs.js


文件差异内容过多而无法显示
+ 0 - 0
docs/assets/easier/easier_wasm.js


二进制
docs/assets/easier/preview.jpg


+ 99 - 15
docs/en/manuals/animation.md

@@ -329,20 +329,105 @@ The pingpong modes run the animation first forward, then backward. A set of corr
 
 
 Easing defines how the animated value changes over time. The images below describe the functions applied over time to create the easing.
 Easing defines how the animated value changes over time. The images below describe the functions applied over time to create the easing.
 
 
-The corresponding value to use when calling `go.animate()` are `go.EASING_LINEAR`, `go.EASING_INBACK`, `go.EASING_OUTBACK` and so forth.
-
-For `gui.animate()` the values are named `gui.EASING_LINEAR`, `gui.EASING_INBACK`, `gui.EASING_OUTBACK` and so forth.
-
-```linechart
-{
-  "labels": [1, "Tuesday", "Wednesday", "Thursday", "Friday"],
-  "series": [
-    [12, 9, 7, 8, 5],
-    [2, 1, 3.5, 7, 3],
-    [1, 3, 4, 5, 6]
-  ]
-}
-```
+The following are valid easing values for `go.animate()`:
+| | |
+|---|---|
+| go.EASING_LINEAR | |
+| go.EASING_INBACK | go.EASING_OUTBACK |
+| go.EASING_INOUTBACK | go.EASING_OUTINBACK |
+| go.EASING_INBOUNCE | go.EASING_OUTBOUNCE |
+| go.EASING_INOUTBOUNCE | go.EASING_OUTINBOUNCE |
+| go.EASING_INELASTIC | go.EASING_OUTELASTIC |
+| go.EASING_INOUTELASTIC | go.EASING_OUTINELASTIC |
+| go.EASING_INSINE | go.EASING_OUTSINE |
+| go.EASING_INOUTSINE | go.EASING_OUTINSINE |
+| go.EASING_INEXPO | go.EASING_OUTEXPO |
+| go.EASING_INOUTEXPO | go.EASING_OUTINEXPO |
+| go.EASING_INCIRC | go.EASING_OUTCIRC |
+| go.EASING_INOUTCIRC | go.EASING_OUTINCIRC |
+| go.EASING_INQUAD | go.EASING_OUTQUAD |
+| go.EASING_INOUTQUAD | go.EASING_OUTINQUAD |
+| go.EASING_INCUBIC | go.EASING_OUTCUBIC |
+| go.EASING_INOUTCUBIC | go.EASING_OUTINCUBIC |
+| go.EASING_INQUART | go.EASING_OUTQUART |
+| go.EASING_INOUTQUART | go.EASING_OUTINQUART |
+| go.EASING_INQUINT | go.EASING_OUTQUINT |
+| go.EASING_INOUTQUINT | go.EASING_OUTINQUINT |
+
+The following are valid easing values for `gui.animate()`:
+| | |
+|---|---|
+| gui.EASING_LINEAR | |
+| gui.EASING_INBACK | gui.EASING_OUTBACK |
+| gui.EASING_INOUTBACK | gui.EASING_OUTINBACK |
+| gui.EASING_INBOUNCE | gui.EASING_OUTBOUNCE |
+| gui.EASING_INOUTBOUNCE | gui.EASING_OUTINBOUNCE |
+| gui.EASING_INELASTIC | gui.EASING_OUTELASTIC |
+| gui.EASING_INOUTELASTIC | gui.EASING_OUTINELASTIC |
+| gui.EASING_INSINE | gui.EASING_OUTSINE |
+| gui.EASING_INOUTSINE | gui.EASING_OUTINSINE |
+| gui.EASING_INEXPO | gui.EASING_OUTEXPO |
+| gui.EASING_INOUTEXPO | gui.EASING_OUTINEXPO |
+| gui.EASING_INCIRC | gui.EASING_OUTCIRC |
+| gui.EASING_INOUTCIRC | gui.EASING_OUTINCIRC |
+| gui.EASING_INQUAD | gui.EASING_OUTQUAD |
+| gui.EASING_INOUTQUAD | gui.EASING_OUTINQUAD |
+| gui.EASING_INCUBIC | gui.EASING_OUTCUBIC |
+| gui.EASING_INOUTCUBIC | gui.EASING_OUTINCUBIC |
+| gui.EASING_INQUART | gui.EASING_OUTQUART |
+| gui.EASING_INOUTQUART | gui.EASING_OUTINQUART |
+| gui.EASING_INQUINT | gui.EASING_OUTQUINT |
+| gui.EASING_INOUTQUINT | gui.EASING_OUTINQUINT |
+
+<div id="game-container" class="game-container">
+    <img id="game-preview" src="//storage.googleapis.com/defold-doc/assets/easier/preview.jpg"/>
+    <canvas id="game-canvas" tabindex="1" width="640" height="512">
+    </canvas>
+    <button id="game-button">
+        SHOW EXAMPLE <span class="icon"></span>
+    </button>
+    <script src="//storage.googleapis.com/defold-doc/assets/easier/dmloader.js">
+    </script>
+    <script>
+        document.getElementById("game-button").onclick = function (e) {
+            var extra_params = {
+              archive_location_filter: function( path ) {
+                return ('//storage.googleapis.com/defold-doc/assets/easier/archive' + path + '');
+              },
+              splash_image: '//storage.googleapis.com/defold-doc/assets/easier/preview.jpg',
+              custom_heap_size: 268435456,
+              disable_context_menu: true,
+              game_start: function() {
+                  var e = document.getElementById("game-preview");
+                  e.parentElement.removeChild(e);
+              }
+            };
+            Module['onRuntimeInitialized'] = function() {
+              Module.runApp("game-canvas", extra_params);
+            };
+            Module['locateFile'] = function(path, scriptDirectory)
+            {
+              if (path == "dmengine.wasm" || path == "dmengine_release.wasm" || path == "dmengine_headless.wasm") {
+                path = "easier.wasm";
+              }
+              return scriptDirectory + path;
+            };
+            function load_engine() {
+              var engineJS = document.createElement('script');
+              engineJS.type = 'text/javascript';
+              if (Module['isWASMSupported']) {
+                  engineJS.src = '//storage.googleapis.com/defold-doc/assets/easier/easier_wasm.js';
+              } else {
+                  engineJS.src = '//storage.googleapis.com/defold-doc/assets/easier/easier_asmjs.js';
+              }
+              document.head.appendChild(engineJS);
+            }
+            load_engine();
+            document.getElementById("game-button").style.display = 'none';
+            document.getElementById("game-button").onclick = null;
+        };
+    </script>
+</div>
 
 
 ![Linear interpolation](images/properties/easing_linear.png){.inline}
 ![Linear interpolation](images/properties/easing_linear.png){.inline}
 ![In back](images/properties/easing_inback.png){.inline}
 ![In back](images/properties/easing_inback.png){.inline}
@@ -433,4 +518,3 @@ function init(self)
     go.animate(".", "position.y", go.PLAYBACK_ONCE_FORWARD, 100, go.EASING_OUTBOUNCE, 2, 0, done_bouncing)
     go.animate(".", "position.y", go.PLAYBACK_ONCE_FORWARD, 100, go.EASING_OUTBOUNCE, 2, 0, done_bouncing)
 end
 end
 ```
 ```
-

+ 5 - 2
docs/en/tutorials/car.md

@@ -90,9 +90,12 @@ Select the "car" game object, right-click and select <kbd>Add Component</kbd>, t
 Image
 Image
 : This requires an image source for the sprite. Create an atlas image file by marking "main" in the *Project Explorer* view, right-clicking and selecting <kbd>New ▸ Atlas File</kbd>. Name the new atlas file *sprites.atlas* and double click it to open it in the atlas editor. Save the following two image files to your computer and drag them into *main* in the *Project Explorer* view. Now you can mark the Atlas root node in the atlas editor, right click and select <kbd>Add Images</kbd>. Add the car and the tire image to the atlas and save. Now you can select *sprites.atlas* as the image source for the sprite component in the "car" game object in the "car" collection.
 : This requires an image source for the sprite. Create an atlas image file by marking "main" in the *Project Explorer* view, right-clicking and selecting <kbd>New ▸ Atlas File</kbd>. Name the new atlas file *sprites.atlas* and double click it to open it in the atlas editor. Save the following two image files to your computer and drag them into *main* in the *Project Explorer* view. Now you can mark the Atlas root node in the atlas editor, right click and select <kbd>Add Images</kbd>. Add the car and the tire image to the atlas and save. Now you can select *sprites.atlas* as the image source for the sprite component in the "car" game object in the "car" collection.
 
 
-![Car image](images/car/start_car.png) [Car image](images/car/start_car.png)
+Images for our game:
 
 
-![Tire image](images/car/start_tire.png) [Tire image](images/car/start_tire.png)
+![Car image](images/car/start_car.png)
+![Tire image](images/car/start_tire.png)
+
+Add these images to the atlas:
 
 
 ![Sprites atlas](images/car/start_sprites_atlas.png)
 ![Sprites atlas](images/car/start_sprites_atlas.png)
 
 

部分文件因为文件数量过多而无法显示