First commit for "Laureati Invaders", as downloaded from website

This commit is contained in:
giomba 2020-05-29 14:21:05 +02:00
parent 946cc4f772
commit ee0797240f
106 changed files with 15612 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -0,0 +1,57 @@
/**
GDevelop - DestroyOutside Behavior Extension
Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
*/
/**
* The destroyOutsideRuntimeBehavior represents a behavior allowing objects to be
* moved using the mouse.
*
* @class DestroyOutsideRuntimeBehavior
* @constructor
*/
gdjs.DestroyOutsideRuntimeBehavior = function(runtimeScene, behaviorData, owner)
{
gdjs.RuntimeBehavior.call(this, runtimeScene, behaviorData, owner);
this._extraBorder = behaviorData.extraBorder || 0;
};
gdjs.DestroyOutsideRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.registerBehavior("DestroyOutsideBehavior::DestroyOutside", gdjs.DestroyOutsideRuntimeBehavior);
gdjs.DestroyOutsideRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
// TODO: This would better be done using the object AABB (getAABB), as (`getCenterX`;`getCenterY`) point
// is not necessarily in the middle of the object (for sprites for example).
var ow = this.owner.getWidth();
var oh = this.owner.getHeight();
var ocx = this.owner.getDrawableX()+this.owner.getCenterX();
var ocy = this.owner.getDrawableY()+this.owner.getCenterY();
var layer = runtimeScene.getLayer(this.owner.getLayer());
var boundingCircleRadius = Math.sqrt(ow*ow+oh*oh)/2.0;
if ( ocx+boundingCircleRadius+this._extraBorder < layer.getCameraX()-layer.getCameraWidth()/2
|| ocx-boundingCircleRadius-this._extraBorder > layer.getCameraX()+layer.getCameraWidth()/2
|| ocy+boundingCircleRadius+this._extraBorder < layer.getCameraY()-layer.getCameraHeight()/2
|| ocy-boundingCircleRadius-this._extraBorder > layer.getCameraY()+layer.getCameraHeight()/2 ) {
//We are outside the camera area.
this.owner.deleteFromScene(runtimeScene);
}
};
/**
* Set an additional border to the camera viewport as a buffer before the object gets destroyed.
* @param {number} val Border in pixels.
*/
gdjs.DestroyOutsideRuntimeBehavior.prototype.setExtraBorder = function(val) {
this._extraBorder = val;
};
/**
* Get the additional border of the camera viewport buffer which triggers the destruction of an object.
* @return {number} The additional border around the camera viewport in pixels
*/
gdjs.DestroyOutsideRuntimeBehavior.prototype.getExtraBorder = function() {
return this._extraBorder;
};

View File

@ -0,0 +1,343 @@
gdjs.PanelSpriteRuntimeObjectPixiRenderer = function(
runtimeObject,
runtimeScene,
textureName,
tiled
) {
this._object = runtimeObject;
if (this._spritesContainer === undefined) {
var texture = runtimeScene
.getGame()
.getImageManager()
.getPIXITexture(textureName);
var StretchedSprite = !tiled ? PIXI.Sprite : PIXI.extras.TilingSprite;
this._spritesContainer = new PIXI.Container();
this._centerSprite = new StretchedSprite(new PIXI.Texture(texture));
this._borderSprites = [
new StretchedSprite(new PIXI.Texture(texture)), //Right
new PIXI.Sprite(texture), //Top-Right
new StretchedSprite(new PIXI.Texture(texture)), //Top
new PIXI.Sprite(texture), //Top-Left
new StretchedSprite(new PIXI.Texture(texture)), //Left
new PIXI.Sprite(texture), //Bottom-Left
new StretchedSprite(new PIXI.Texture(texture)), //Bottom
new PIXI.Sprite(texture), //Bottom-Right
];
}
this.setTexture(textureName, runtimeScene);
this._spritesContainer.removeChildren();
this._spritesContainer.addChild(this._centerSprite);
for (var i = 0; i < this._borderSprites.length; ++i) {
this._spritesContainer.addChild(this._borderSprites[i]);
}
this._alpha = this._spritesContainer.alpha;
runtimeScene
.getLayer('')
.getRenderer()
.addRendererObject(this._spritesContainer, runtimeObject.getZOrder());
};
gdjs.PanelSpriteRuntimeObjectRenderer =
gdjs.PanelSpriteRuntimeObjectPixiRenderer; //Register the class to let the engine use it.
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.getRendererObject = function() {
return this._spritesContainer;
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.ensureUpToDate = function() {
if (this._spritesContainer.visible && this._wasRendered) {
// Update the alpha of the container to make sure that it's applied.
// If not done, the alpha will be back to full opaque when changing the color
// of the object.
this._spritesContainer.alpha = this._alpha;
this._spritesContainer.cacheAsBitmap = true;
}
this._wasRendered = true;
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.updateOpacity = function() {
//TODO: Workaround a not working property in PIXI.js:
this._spritesContainer.alpha = this._spritesContainer.visible
? this._object.opacity / 255
: 0;
this._alpha = this._spritesContainer.alpha;
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.updateAngle = function() {
this._spritesContainer.rotation = gdjs.toRad(this._object.angle);
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.updatePosition = function() {
this._spritesContainer.position.x = this._object.x + this._object._width / 2;
this._spritesContainer.position.y = this._object.y + this._object._height / 2;
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype._updateLocalPositions = function() {
var obj = this._object;
this._centerSprite.position.x = obj._lBorder;
this._centerSprite.position.y = obj._tBorder;
//Right
this._borderSprites[0].position.x = obj._width - obj._rBorder;
this._borderSprites[0].position.y = obj._tBorder;
//Top-right
this._borderSprites[1].position.x = obj._width - this._borderSprites[1].width;
this._borderSprites[1].position.y = 0;
//Top
this._borderSprites[2].position.x = obj._lBorder;
this._borderSprites[2].position.y = 0;
//Top-Left
this._borderSprites[3].position.x = 0;
this._borderSprites[3].position.y = 0;
//Left
this._borderSprites[4].position.x = 0;
this._borderSprites[4].position.y = obj._tBorder;
//Bottom-Left
this._borderSprites[5].position.x = 0;
this._borderSprites[5].position.y =
obj._height - this._borderSprites[5].height;
//Bottom
this._borderSprites[6].position.x = obj._lBorder;
this._borderSprites[6].position.y = obj._height - obj._bBorder;
//Bottom-Right
this._borderSprites[7].position.x = obj._width - this._borderSprites[7].width;
this._borderSprites[7].position.y =
obj._height - this._borderSprites[7].height;
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype._updateSpritesAndTexturesSize = function() {
var obj = this._object;
this._centerSprite.width = Math.max(
obj._width - obj._rBorder - obj._lBorder,
0
);
this._centerSprite.height = Math.max(
obj._height - obj._tBorder - obj._bBorder,
0
);
//Right
this._borderSprites[0].width = obj._rBorder;
this._borderSprites[0].height = Math.max(
obj._height - obj._tBorder - obj._bBorder,
0
);
//Top
this._borderSprites[2].height = obj._tBorder;
this._borderSprites[2].width = Math.max(
obj._width - obj._rBorder - obj._lBorder,
0
);
//Left
this._borderSprites[4].width = obj._lBorder;
this._borderSprites[4].height = Math.max(
obj._height - obj._tBorder - obj._bBorder,
0
);
//Bottom
this._borderSprites[6].height = obj._bBorder;
this._borderSprites[6].width = Math.max(
obj._width - obj._rBorder - obj._lBorder,
0
);
this._wasRendered = true;
this._spritesContainer.cacheAsBitmap = false;
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.setTexture = function(
textureName,
runtimeScene
) {
var obj = this._object;
var texture = runtimeScene
.getGame()
.getImageManager()
.getPIXITexture(textureName);
function makeInsideTexture(rect) {
//TODO
if (rect.width < 0) rect.width = 0;
if (rect.height < 0) rect.height = 0;
if (rect.x < 0) rect.x = 0;
if (rect.y < 0) rect.y = 0;
if (rect.x > texture.width) rect.x = texture.width;
if (rect.y > texture.height) rect.y = texture.height;
if (rect.x + rect.width > texture.width)
rect.width = texture.width - rect.x;
if (rect.y + rect.height > texture.height)
rect.height = texture.height - rect.y;
return rect;
}
this._centerSprite.texture = new PIXI.Texture(
texture,
makeInsideTexture(
new PIXI.Rectangle(
obj._lBorder,
obj._tBorder,
texture.width - obj._lBorder - obj._rBorder,
texture.height - obj._tBorder - obj._bBorder
)
)
);
//Top, Bottom, Right, Left borders:
this._borderSprites[0].texture = new PIXI.Texture(
texture,
makeInsideTexture(
new PIXI.Rectangle(
texture.width - obj._rBorder,
obj._tBorder,
obj._rBorder,
texture.height - obj._tBorder - obj._bBorder
)
)
);
this._borderSprites[2].texture = new PIXI.Texture(
texture,
makeInsideTexture(
new PIXI.Rectangle(
obj._lBorder,
0,
texture.width - obj._lBorder - obj._rBorder,
obj._tBorder
)
)
);
this._borderSprites[4].texture = new PIXI.Texture(
texture,
makeInsideTexture(
new PIXI.Rectangle(
0,
obj._tBorder,
obj._lBorder,
texture.height - obj._tBorder - obj._bBorder
)
)
);
this._borderSprites[6].texture = new PIXI.Texture(
texture,
makeInsideTexture(
new PIXI.Rectangle(
obj._lBorder,
texture.height - obj._bBorder,
texture.width - obj._lBorder - obj._rBorder,
obj._bBorder
)
)
);
this._borderSprites[1].texture = new PIXI.Texture(
texture,
makeInsideTexture(
new PIXI.Rectangle(
this._borderSprites[1].width - obj._rBorder,
0,
obj._rBorder,
obj._tBorder
)
)
);
this._borderSprites[3].texture = new PIXI.Texture(
texture,
makeInsideTexture(new PIXI.Rectangle(0, 0, obj._lBorder, obj._tBorder))
);
this._borderSprites[5].texture = new PIXI.Texture(
texture,
makeInsideTexture(
new PIXI.Rectangle(
0,
this._borderSprites[5].height - obj._bBorder,
obj._lBorder,
obj._bBorder
)
)
);
this._borderSprites[7].texture = new PIXI.Texture(
texture,
makeInsideTexture(
new PIXI.Rectangle(
this._borderSprites[7].width - obj._rBorder,
this._borderSprites[7].height - obj._bBorder,
obj._rBorder,
obj._bBorder
)
)
);
this._updateSpritesAndTexturesSize();
this._updateLocalPositions();
this.updatePosition();
this._spritesContainer.pivot.x = this._object._width / 2;
this._spritesContainer.pivot.y = this._object._height / 2;
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.updateWidth = function() {
this._spritesContainer.pivot.x = this._object._width / 2;
this._updateSpritesAndTexturesSize();
this._updateLocalPositions();
this.updatePosition();
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.updateHeight = function() {
this._spritesContainer.pivot.y = this._object._height / 2;
this._updateSpritesAndTexturesSize();
this._updateLocalPositions();
this.updatePosition();
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.setColor = function(
rgbColor
) {
var colors = rgbColor.split(';');
if (colors.length < 3) return;
this._centerSprite.tint =
'0x' +
gdjs.rgbToHex(
parseInt(colors[0], 10),
parseInt(colors[1], 10),
parseInt(colors[2], 10)
);
for (
var borderCounter = 0;
borderCounter < this._borderSprites.length;
borderCounter++
) {
this._borderSprites[borderCounter].tint =
'0x' +
gdjs.rgbToHex(
parseInt(colors[0], 10),
parseInt(colors[1], 10),
parseInt(colors[2], 10)
);
}
this._spritesContainer.cacheAsBitmap = false;
};
gdjs.PanelSpriteRuntimeObjectPixiRenderer.prototype.getColor = function() {
var rgb = PIXI.utils.hex2rgb(this._centerSprite.tint);
return (
Math.floor(rgb[0] * 255) +
';' +
Math.floor(rgb[1] * 255) +
';' +
Math.floor(rgb[2] * 255)
);
};

View File

@ -0,0 +1,222 @@
/*
* GDevelop JS Platform
* 2013 Florian Rival (Florian.Rival@gmail.com)
*/
/**
* @typedef {Object} PanelSpriteObjectDataType
* @property {number} rightMargin The right margin
* @property {number} leftMargin The left margin
* @property {number} topMargin The top margin
* @property {number} bottomMargin The bottom margin
* @property {boolean} [tiled] Are the central part and borders tiled?
* @property {number} width The object width
* @property {number} height The object height
* @property {string} texture The name of the resource containing the texture to use
*
* @typedef {ObjectData & PanelSpriteObjectDataType} PanelSpriteObjectData
*/
/**
* The PanelSpriteRuntimeObject displays a tiled texture.
*
* @class PanelSpriteRuntimeObject
* @extends RuntimeObject
* @memberof gdjs
* @param {gdjs.RuntimeScene} runtimeScene The {@link gdjs.RuntimeScene} the object belongs to
* @param {PanelSpriteObjectData} panelSpriteObjectData The initial properties of the object
*/
gdjs.PanelSpriteRuntimeObject = function(runtimeScene, panelSpriteObjectData) {
gdjs.RuntimeObject.call(this, runtimeScene, panelSpriteObjectData);
/** @type {number} */
this._rBorder = panelSpriteObjectData.rightMargin;
/** @type {number} */
this._lBorder = panelSpriteObjectData.leftMargin;
/** @type {number} */
this._tBorder = panelSpriteObjectData.topMargin;
/** @type {number} */
this._bBorder = panelSpriteObjectData.bottomMargin;
/** @type {boolean} */
this._tiled = panelSpriteObjectData.tiled;
/** @type {number} */
this._width = panelSpriteObjectData.width;
/** @type {number} */
this._height = panelSpriteObjectData.height;
/** @type {number} */
this.opacity = 255;
if (this._renderer) {
gdjs.PanelSpriteRuntimeObjectRenderer.call(
this._renderer,
this,
runtimeScene,
panelSpriteObjectData.texture,
panelSpriteObjectData.tiled
);
} else {
/** @type {gdjs.PanelSpriteRuntimeObjectRenderer} */
this._renderer = new gdjs.PanelSpriteRuntimeObjectRenderer(
this,
runtimeScene,
panelSpriteObjectData.texture,
panelSpriteObjectData.tiled
);
}
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
};
gdjs.PanelSpriteRuntimeObject.prototype = Object.create(
gdjs.RuntimeObject.prototype
);
gdjs.registerObject("PanelSpriteObject::PanelSprite", gdjs.PanelSpriteRuntimeObject);
gdjs.PanelSpriteRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();
};
gdjs.PanelSpriteRuntimeObject.prototype.onDestroyFromScene = function(
runtimeScene
) {
gdjs.RuntimeObject.prototype.onDestroyFromScene.call(this, runtimeScene);
if (this._renderer.onDestroy) {
this._renderer.onDestroy();
}
};
gdjs.PanelSpriteRuntimeObject.prototype.update = function() {
this._renderer.ensureUpToDate();
};
/**
* Initialize the extra parameters that could be set for an instance.
*/
gdjs.PanelSpriteRuntimeObject.prototype.extraInitializationFromInitialInstance = function(
initialInstanceData
) {
if (initialInstanceData.customSize) {
this.setWidth(initialInstanceData.width);
this.setHeight(initialInstanceData.height);
}
};
/**
* Set the x position of the panel sprite.
* @param {number} x The new x position in pixels.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setX = function(x) {
gdjs.RuntimeObject.prototype.setX.call(this, x);
this._renderer.updatePosition();
};
/**
* Set the y position of the panel sprite.
* @param {number} y The new y position in pixels.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setY = function(y) {
gdjs.RuntimeObject.prototype.setY.call(this, y);
this._renderer.updatePosition();
};
/**
* Set the texture of the panel sprite.
* @param {string} textureName The name of the texture.
* @param {gdjs.RuntimeScene} runtimeScene The scene the object lives in.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setTexture = function(
textureName,
runtimeScene
) {
this._renderer.setTexture(textureName, runtimeScene);
};
/**
* Set the angle of the panel sprite.
* @param {number} angle The new angle in degrees.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setAngle = function(angle) {
gdjs.RuntimeObject.prototype.setAngle.call(this, angle);
this._renderer.updateAngle();
};
/**
* Get the width of the panel sprite in pixels
* @return {number} The width in pixels
*/
gdjs.PanelSpriteRuntimeObject.prototype.getWidth = function() {
return this._width;
};
/**
* Get the height of the panel sprite in pixels
* @return {number} The height in pixels
*/
gdjs.PanelSpriteRuntimeObject.prototype.getHeight = function() {
return this._height;
};
/**
* Set the width of the panel sprite.
* @param {number} width The new width in pixels.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setWidth = function(width) {
this._width = width;
this._renderer.updateWidth();
};
/**
* Set the height of the panel sprite.
* @param {number} height The new height in pixels.
*/
gdjs.PanelSpriteRuntimeObject.prototype.setHeight = function(height) {
this._height = height;
this._renderer.updateHeight();
};
/**
* Change the transparency of the object.
* @param {number} opacity The new opacity, between 0 (transparent) and 255 (opaque).
*/
gdjs.PanelSpriteRuntimeObject.prototype.setOpacity = function(opacity) {
if (opacity < 0) opacity = 0;
if (opacity > 255) opacity = 255;
this.opacity = opacity;
this._renderer.updateOpacity();
};
/**
* Get the transparency of the object.
* @return {number} The opacity, between 0 (transparent) and 255 (opaque).
*/
gdjs.PanelSpriteRuntimeObject.prototype.getOpacity = function() {
return this.opacity;
};
/**
* Change the tint of the panel sprite object.
*
* @param {string} rgbColor The color, in RGB format ("128;200;255").
*/
gdjs.PanelSpriteRuntimeObject.prototype.setColor = function(rgbColor) {
this._renderer.setColor(rgbColor);
};
/**
* Get the tint of the panel sprite object.
*
* @returns {string} rgbColor The color, in RGB format ("128;200;255").
*/
gdjs.PanelSpriteRuntimeObject.prototype.getColor = function() {
return this._renderer.getColor();
};

View File

@ -0,0 +1,39 @@
/**
GDevelop - SystemInfo Extension
Copyright (c) 2016 Florian Rival (Florian.Rival@gmail.com)
*/
/**
* @memberof gdjs.evtTools
* @class linkedObjects
* @static
* @private
*/
gdjs.evtTools.systemInfo = {};
gdjs.evtTools.systemInfo.isMobile = function() {
if (typeof cc !== "undefined" && cc.sys) {
return cc.sys.isMobile;
} else if (typeof Cocoon !== "undefined" && Cocoon.App) {
return true;
} else if (typeof window !== "undefined" && window.cordova) {
return true;
} else if (typeof window !== "undefined") {
// Try to detect mobile device browsers.
if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) {
return true;
}
}
return false;
};
/**
* Check if the the device supports WebGL.
* @param {gdjs.RuntimeScene} runtimeScene
* @returns {boolean} true if WebGL is supported
*/
gdjs.evtTools.systemInfo.isWebGLSupported = function(runtimeScene) {
return runtimeScene.getGame().getRenderer().isWebGLSupported();
};

View File

@ -0,0 +1,166 @@
gdjs.TextRuntimeObjectPixiRenderer = function(runtimeObject, runtimeScene)
{
this._object = runtimeObject;
this._fontManager = runtimeScene.getGame().getFontManager();
if ( this._text === undefined ) this._text = new PIXI.Text(" ", {align:"left"});
this._text.anchor.x = 0.5;
this._text.anchor.y = 0.5;
runtimeScene.getLayer("").getRenderer().addRendererObject(this._text, runtimeObject.getZOrder());
this._text.text = runtimeObject._str.length === 0 ? " " : runtimeObject._str;
this._justCreated = true; //Work around a PIXI.js bug. See updateTime method.
this.updateStyle();
this.updatePosition();
};
gdjs.TextRuntimeObjectRenderer = gdjs.TextRuntimeObjectPixiRenderer; //Register the class to let the engine use it.
gdjs.TextRuntimeObjectPixiRenderer.prototype.getRendererObject = function() {
return this._text;
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.ensureUpToDate = function() {
if (this._justCreated) { //Work around a PIXI.js bug:
this._text.updateText();
this.updatePosition(); //Width seems not to be correct when text is not rendered yet.
this._justCreated = false;
}
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.updateStyle = function() {
var fontName = "\"" + this._fontManager.getFontFamily(this._object._fontName) + "\"";
var style = this._text.style;
style.fontStyle = this._object._italic ? 'italic' : 'normal';
style.fontWeight = this._object._bold ? 'bold' : 'normal';
style.fontSize = this._object._characterSize;
style.fontFamily = fontName;
if (this._object._useGradient){
style.fill = this._getGradientHex();
} else {
style.fill = this._getColorHex();
}
if (this._object._gradientType === 'LINEAR_VERTICAL'){
style.fillGradientType = PIXI.TEXT_GRADIENT.LINEAR_VERTICAL;
} else {
style.fillGradientType = PIXI.TEXT_GRADIENT.LINEAR_HORIZONTAL;
}
style.align = this._object._textAlign;
style.wordWrap = this._object._wrapping;
style.wordWrapWidth = this._object._wrappingWidth;
style.breakWords = true;
style.stroke = gdjs.rgbToHexNumber(
this._object._outlineColor[0],
this._object._outlineColor[1],
this._object._outlineColor[2]
);
style.strokeThickness = this._object._outlineThickness;
style.dropShadow = this._object._shadow;
style.dropShadowColor = gdjs.rgbToHexNumber(
this._object._shadowColor[0],
this._object._shadowColor[1],
this._object._shadowColor[2]
);
style.dropShadowBlur = this._object._shadowBlur;
style.dropShadowAngle = this._object._shadowAngle;
style.dropShadowDistance = this._object._shadowDistance;
style.padding = this._object._padding;
// Prevent spikey outlines by adding a miter limit
style.miterLimit = 3;
this.updatePosition();
// Manually ask the PIXI object to re-render as we changed a style property
// see http://www.html5gamedevs.com/topic/16924-change-text-style-post-render/
this._text.dirty = true;
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.updatePosition = function() {
this._text.position.x = this._object.x+this._text.width/2;
this._text.position.y = this._object.y+this._text.height/2;
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.updateAngle = function() {
this._text.rotation = gdjs.toRad(this._object.angle);
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.updateOpacity = function() {
this._text.alpha = this._object.opacity / 255;
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.updateString = function() {
this._text.text = this._object._str.length === 0 ? " " : this._object._str;
this._text.updateText(); //Work around a PIXI.js bug.
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.getWidth = function() {
return this._text.width;
};
gdjs.TextRuntimeObjectPixiRenderer.prototype.getHeight = function() {
return this._text.height;
};
gdjs.TextRuntimeObjectPixiRenderer.prototype._getColorHex = function() {
return gdjs.rgbToHexNumber(
this._object._color[0],
this._object._color[1],
this._object._color[2]
);
}
gdjs.TextRuntimeObjectPixiRenderer.prototype._getGradientHex = function() {
var gradient = [];
for (var colorIndex = 0; colorIndex < this._object._gradient.length; colorIndex++){
gradient.push(
'#' + gdjs.rgbToHex(
this._object._gradient[colorIndex][0],
this._object._gradient[colorIndex][1],
this._object._gradient[colorIndex][2]
)
);
}
return gradient;
}
/**
* Get y-scale of the text.
*/
gdjs.TextRuntimeObjectPixiRenderer.prototype.getScaleX = function() {
return this._text.scale.x;
};
/**
* Get x-scale of the text.
*/
gdjs.TextRuntimeObjectPixiRenderer.prototype.getScaleY = function() {
return this._text.scale.y;
};
/**
* Set the text object scale.
* @param {number} newScale The new scale for the text object.
*/
gdjs.TextRuntimeObjectPixiRenderer.prototype.setScale = function(newScale) {
this._text.scale.x = newScale;
this._text.scale.y = newScale;
};
/**
* Set the text object x-scale.
* @param {number} newScale The new x-scale for the text object.
*/
gdjs.TextRuntimeObjectPixiRenderer.prototype.setScaleX = function(newScale) {
this._text.scale.x = newScale;
};
/**
* Set the text object y-scale.
* @param {number} newScale The new y-scale for the text object.
*/
gdjs.TextRuntimeObjectPixiRenderer.prototype.setScaleY = function(newScale) {
this._text.scale.y = newScale;
};

View File

@ -0,0 +1,513 @@
/*
* GDevelop JS Platform
* 2013-2016 Florian Rival (Florian.Rival@gmail.com)
*/
/**
* @typedef {Object} TextObjectDataType Base parameters for gdjs.TextRuntimeObject
* @property {number} characterSize The size of the characters
* @property {string} font The font name
* @property {boolean} bold Is Bold?
* @property {boolean} italic Is Italic?
* @property {boolean} underlined Is Underlined?
* @property {Object} color The text color in an RGB representation
* @property {number} color.r The Red level from 0 to 255
* @property {number} color.g The Green level from 0 to 255
* @property {number} color.b The Blue level from 0 to 255
* @property {string} string The text of the object
*
* @typedef {ObjectData & TextObjectDataType} TextObjectData
*/
/**
* Displays a text.
*
* @memberof gdjs
* @class TextRuntimeObject
* @extends RuntimeObject
* @param {gdjs.RuntimeScene} runtimeScene The {@link gdjs.RuntimeScene} the object belongs to
* @param {TextObjectData} textObjectData The initial properties of the object
*/
gdjs.TextRuntimeObject = function(runtimeScene, textObjectData)
{
gdjs.RuntimeObject.call(this, runtimeScene, textObjectData);
/** @type {number} */
this._characterSize = Math.max(1, textObjectData.characterSize);
/** @type {string} */
this._fontName = textObjectData.font;
/** @type {boolean} */
this._bold = textObjectData.bold;
/** @type {boolean} */
this._italic = textObjectData.italic;
/** @type {boolean} */
this._underlined = textObjectData.underlined;
/** @type {Array<number>} */
this._color = [textObjectData.color.r, textObjectData.color.g, textObjectData.color.b];
/** @type {boolean} */
this._useGradient = false;
/** @type {Array} */
this._gradient = [];
/** @type {string} */
this._gradientType = '';
/** @type {number} */
this.opacity = 255;
/** @type {string} */
this._textAlign = 'left';
/** @type {boolean} */
this._wrapping = false;
/** @type {number} */
this._wrappingWidth = 1;
/** @type {number} */
this._outlineThickness = 0;
/** @type {Array<number>} */
this._outlineColor = [255,255,255];
/** @type {boolean} */
this._shadow = false;
/** @type {Array<number>} */
this._shadowColor = [0,0,0];
/** @type {number} */
this._shadowDistance = 1;
/** @type {number} */
this._shadowBlur = 1;
/** @type {number} */
this._shadowAngle = 0;
/** @type {number} */
this._padding = 5;
/** @type {number} */
this._scaleX = 1;
/** @type {number} */
this._scaleY = 1;
/** @type {string} */
this._str = textObjectData.string;
if (this._renderer)
gdjs.TextRuntimeObjectRenderer.call(this._renderer, this, runtimeScene);
else
/** @type {gdjs.TextRuntimeObjectRenderer} */
this._renderer = new gdjs.TextRuntimeObjectRenderer(this, runtimeScene);
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
this.onCreated();
};
gdjs.TextRuntimeObject.prototype = Object.create( gdjs.RuntimeObject.prototype );
gdjs.registerObject("TextObject::Text", gdjs.TextRuntimeObject);
gdjs.TextRuntimeObject.prototype.getRendererObject = function() {
return this._renderer.getRendererObject();
};
gdjs.TextRuntimeObject.prototype.update = function() {
this._renderer.ensureUpToDate();
};
/**
* Initialize the extra parameters that could be set for an instance.
* @private
*/
gdjs.TextRuntimeObject.prototype.extraInitializationFromInitialInstance = function(initialInstanceData) {
if ( initialInstanceData.customSize ) {
this.setWrapping(true);
this.setWrappingWidth(initialInstanceData.width);
}
};
/**
* Update the rendered object position.
* @private
*/
gdjs.TextRuntimeObject.prototype._updateTextPosition = function() {
this.hitBoxesDirty = true;
this._renderer.updatePosition();
};
/**
* Set object position on X axis.
*/
gdjs.TextRuntimeObject.prototype.setX = function(x) {
gdjs.RuntimeObject.prototype.setX.call(this, x);
this._updateTextPosition();
};
/**
* Set object position on Y axis.
*/
gdjs.TextRuntimeObject.prototype.setY = function(y) {
gdjs.RuntimeObject.prototype.setY.call(this, y);
this._updateTextPosition();
};
/**
* Set the angle of the object.
* @param {number} angle The new angle of the object
*/
gdjs.TextRuntimeObject.prototype.setAngle = function(angle) {
gdjs.RuntimeObject.prototype.setAngle.call(this, angle);
this._renderer.updateAngle();
};
/**
* Set object opacity.
*/
gdjs.TextRuntimeObject.prototype.setOpacity = function(opacity) {
if ( opacity < 0 ) opacity = 0;
if ( opacity > 255 ) opacity = 255;
this.opacity = opacity;
this._renderer.updateOpacity();
};
/**
* Get object opacity.
*/
gdjs.TextRuntimeObject.prototype.getOpacity = function() {
return this.opacity;
};
/**
* Get the string displayed by the object.
*/
gdjs.TextRuntimeObject.prototype.getString = function() {
return this._str;
};
/**
* Set the string displayed by the object.
* @param {string} str The new text
*/
gdjs.TextRuntimeObject.prototype.setString = function(str) {
if ( str === this._str ) return;
this._str = str;
this._renderer.updateString();
this._updateTextPosition();
};
/**
* Get the font size of the characters of the object.
*/
gdjs.TextRuntimeObject.prototype.getCharacterSize = function() {
return this._characterSize;
};
/**
* Set the font size for characters of the object.
* @param {number} newSize The new font size for the text.
*/
gdjs.TextRuntimeObject.prototype.setCharacterSize = function(newSize) {
if (newSize <= 1) newSize = 1;
this._characterSize = newSize;
this._renderer.updateStyle();
};
/**
* Return true if the text is bold.
*/
gdjs.TextRuntimeObject.prototype.isBold = function() {
return this._bold;
};
/**
* Set bold for the object text.
* @param enable {boolean} true to have a bold text, false otherwise.
*/
gdjs.TextRuntimeObject.prototype.setBold = function(enable) {
this._bold = enable;
this._renderer.updateStyle();
};
/**
* Return true if the text is italic.
*/
gdjs.TextRuntimeObject.prototype.isItalic = function() {
return this._italic;
};
/**
* Set italic for the object text.
* @param enable {boolean} true to have an italic text, false otherwise.
*/
gdjs.TextRuntimeObject.prototype.setItalic = function(enable) {
this._italic = enable;
this._renderer.updateStyle();
};
/**
* Get width of the text.
*/
gdjs.TextRuntimeObject.prototype.getWidth = function() {
return this._renderer.getWidth();
};
/**
* Get height of the text.
*/
gdjs.TextRuntimeObject.prototype.getHeight = function() {
return this._renderer.getHeight();
};
/**
* Get scale of the text.
*/
gdjs.TextRuntimeObject.prototype.getScale = function() {
return (Math.abs(this._scaleX)+Math.abs(this._scaleY))/2.0;
};
/**
* Get y-scale of the text.
*/
gdjs.TextRuntimeObject.prototype.getScaleX = function() {
return this._renderer.getScaleX();
};
/**
* Get x-scale of the text.
*/
gdjs.TextRuntimeObject.prototype.getScaleY = function() {
return this._renderer.getScaleY();
};
/**
* Set the text object scale.
* @param {number} newScale The new scale for the text object.
*/
gdjs.TextRuntimeObject.prototype.setScale = function(newScale) {
this._scaleX = newScale;
this._scaleY = newScale;
this._renderer.setScale(newScale);
};
/**
* Set the text object x-scale.
* @param {number} newScale The new x-scale for the text object.
*/
gdjs.TextRuntimeObject.prototype.setScaleX = function(newScale) {
this._scaleX = newScale;
this._renderer.setScaleX(newScale);
};
/**
* Set the text object y-scale.
* @param {number} newScale The new y-scale for the text object.
*/
gdjs.TextRuntimeObject.prototype.setScaleY = function(newScale) {
this._scaleY = newScale;
this._renderer.setScaleY(newScale);
};
/**
* Change the text color.
* @param {String} color color as a "R;G;B" string, for example: "255;0;0"
*/
gdjs.TextRuntimeObject.prototype.setColor = function(str) {
var color = str.split(";");
if ( color.length < 3 ) return;
this._color[0] = parseInt(color[0], 10);
this._color[1] = parseInt(color[1], 10);
this._color[2] = parseInt(color[2], 10);
this._useGradient = false;
this._renderer.updateStyle();
};
/**
* Get the text color.
* @return {String} The color as a "R;G;B" string, for example: "255;0;0"
*/
gdjs.TextRuntimeObject.prototype.getColor = function(str) {
return this._color[0] + ";" + this._color[1] + ";" + this._color[2];
};
/**
* Set the text alignment for multiline text objects.
* @param {string} alignment The text alignment.
*/
gdjs.TextRuntimeObject.prototype.setTextAlignment = function(alignment) {
this._textAlign = alignment;
this._renderer.updateStyle();
};
/**
* Get the text alignment of text object.
* @return {string} The text alignment.
*/
gdjs.TextRuntimeObject.prototype.getTextAlignment = function() {
return this._textAlign;
};
/**
* Return true if word wrapping is enabled for the text.
*/
gdjs.TextRuntimeObject.prototype.isWrapping = function() {
return this._wrapping;
};
/**
* Set word wrapping for the object text.
* @param {boolean} enable true to enable word wrapping, false to disable it.
*/
gdjs.TextRuntimeObject.prototype.setWrapping = function(enable) {
this._wrapping = enable;
this._renderer.updateStyle();
};
/**
* Get the word wrapping width for the text object.
*/
gdjs.TextRuntimeObject.prototype.getWrappingWidth = function() {
return this._wrappingWidth;
};
/**
* Set the word wrapping width for the text object.
* @param {number} width The new width to set.
*/
gdjs.TextRuntimeObject.prototype.setWrappingWidth = function(width) {
if (width <= 1) width = 1;
this._wrappingWidth = width;
this._renderer.updateStyle();
};
/**
* Set the outline for the text object.
* @param {string} str color as a "R;G;B" string, for example: "255;0;0"
* @param {number} thickness thickness of the outline (0 = disabled)
*/
gdjs.TextRuntimeObject.prototype.setOutline = function(str, thickness) {
var color = str.split(";");
if ( color.length < 3 ) return;
this._outlineColor[0] = parseInt(color[0], 10);
this._outlineColor[1] = parseInt(color[1], 10);
this._outlineColor[2] = parseInt(color[2], 10);
this._outlineThickness = thickness;
this._renderer.updateStyle();
};
/**
* Set the shadow for the text object.
* @param {string} str color as a "R;G;B" string, for example: "255;0;0"
* @param {number} distance distance between the shadow and the text, in pixels.
* @param {number} blur amout of shadow blur, in pixels.
* @param {number} angle shadow offset direction, in degrees.
*/
gdjs.TextRuntimeObject.prototype.setShadow = function(str, distance, blur, angle) {
var color = str.split(";");
if ( color.length < 3 ) return;
this._shadowColor[0] = parseInt(color[0], 10);
this._shadowColor[1] = parseInt(color[1], 10);
this._shadowColor[2] = parseInt(color[2], 10);
this._shadowDistance = distance;
this._shadowBlur = blur;
this._shadowAngle = angle;
this._shadow = true;
this._renderer.updateStyle();
};
/**
* Set the gradient for the text object.
* @param {string} strFirstColor color as a "R;G;B" string, for example: "255;0;0"
* @param {string} strSecondColor color as a "R;G;B" string, for example: "255;0;0"
* @param {string} strThirdColor color as a "R;G;B" string, for example: "255;0;0"
* @param {string} strFourthColor color as a "R;G;B" string, for example: "255;0;0"
* @param {string} strGradientType gradient type
*/
gdjs.TextRuntimeObject.prototype.setGradient = function(strGradientType, strFirstColor, strSecondColor, strThirdColor, strFourthColor) {
var colorFirst = strFirstColor.split(";");
var colorSecond = strSecondColor.split(";");
var colorThird = strThirdColor.split(";");
var colorFourth = strFourthColor.split(";");
this._gradient = [];
if (colorFirst.length == 3){
this._gradient.push([
parseInt(colorFirst[0], 10),
parseInt(colorFirst[1], 10),
parseInt(colorFirst[2], 10)
]);
}
if (colorSecond.length == 3){
this._gradient.push([
parseInt(colorSecond[0], 10),
parseInt(colorSecond[1], 10),
parseInt(colorSecond[2], 10)
]);
}
if (colorThird.length == 3){
this._gradient.push([
parseInt(colorThird[0], 10),
parseInt(colorThird[1], 10),
parseInt(colorThird[2], 10)
]);
}
if (colorFourth.length == 3){
this._gradient.push([
parseInt(colorFourth[0], 10),
parseInt(colorFourth[1], 10),
parseInt(colorFourth[2], 10)
]);
}
this._gradientType = strGradientType;
this._useGradient = (this._gradient.length > 1) ? true : false;
this._renderer.updateStyle();
};
/**
* Show the shadow of the text object.
* @param {boolean} enable true to show the shadow, false to hide it
*/
gdjs.TextRuntimeObject.prototype.showShadow = function(enable) {
this._shadow = enable;
this._renderer.updateStyle();
};
/**
* Get padding of the text object.
* @return {number} number of pixels around the text before it gets cropped
*/
gdjs.TextRuntimeObject.prototype.getPadding = function() {
return this._padding;
};
/**
* Set padding of the text object.
* @param {number} value number of pixels around the text before it gets cropped
*/
gdjs.TextRuntimeObject.prototype.setPadding = function(value) {
this._padding = value;
this._renderer.updateStyle();
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,121 @@
gdjs.Start_32GameCode = {};
gdjs.Start_32GameCode.GDSfondoObjects1= [];
gdjs.Start_32GameCode.GDSfondoObjects2= [];
gdjs.Start_32GameCode.GDTitoloGiocoObjects1= [];
gdjs.Start_32GameCode.GDTitoloGiocoObjects2= [];
gdjs.Start_32GameCode.GDNewObjectObjects1= [];
gdjs.Start_32GameCode.GDNewObjectObjects2= [];
gdjs.Start_32GameCode.GDNewObject2Objects1= [];
gdjs.Start_32GameCode.GDNewObject2Objects2= [];
gdjs.Start_32GameCode.GDOptionsObjects1= [];
gdjs.Start_32GameCode.GDOptionsObjects2= [];
gdjs.Start_32GameCode.GDCreditsObjects1= [];
gdjs.Start_32GameCode.GDCreditsObjects2= [];
gdjs.Start_32GameCode.GDPlayObjects1= [];
gdjs.Start_32GameCode.GDPlayObjects2= [];
gdjs.Start_32GameCode.conditionTrue_0 = {val:false};
gdjs.Start_32GameCode.condition0IsTrue_0 = {val:false};
gdjs.Start_32GameCode.condition1IsTrue_0 = {val:false};
gdjs.Start_32GameCode.condition2IsTrue_0 = {val:false};
gdjs.Start_32GameCode.mapOfGDgdjs_46Start_9532GameCode_46GDPlayObjects1Objects = Hashtable.newFrom({"Play": gdjs.Start_32GameCode.GDPlayObjects1});gdjs.Start_32GameCode.mapOfGDgdjs_46Start_9532GameCode_46GDOptionsObjects1Objects = Hashtable.newFrom({"Options": gdjs.Start_32GameCode.GDOptionsObjects1});gdjs.Start_32GameCode.mapOfGDgdjs_46Start_9532GameCode_46GDCreditsObjects1Objects = Hashtable.newFrom({"Credits": gdjs.Start_32GameCode.GDCreditsObjects1});gdjs.Start_32GameCode.eventsList0x5b6e18 = function(runtimeScene) {
{
gdjs.Start_32GameCode.GDPlayObjects1.createFrom(runtimeScene.getObjects("Play"));
gdjs.Start_32GameCode.condition0IsTrue_0.val = false;
gdjs.Start_32GameCode.condition1IsTrue_0.val = false;
{
gdjs.Start_32GameCode.condition0IsTrue_0.val = gdjs.evtTools.input.cursorOnObject(gdjs.Start_32GameCode.mapOfGDgdjs_46Start_9532GameCode_46GDPlayObjects1Objects, runtimeScene, true, false);
}if ( gdjs.Start_32GameCode.condition0IsTrue_0.val ) {
{
gdjs.Start_32GameCode.condition1IsTrue_0.val = gdjs.evtTools.input.isMouseButtonPressed(runtimeScene, "Left");
}}
if (gdjs.Start_32GameCode.condition1IsTrue_0.val) {
{gdjs.evtTools.runtimeScene.replaceScene(runtimeScene, "Phase1", false);
}}
}
{
gdjs.Start_32GameCode.GDOptionsObjects1.createFrom(runtimeScene.getObjects("Options"));
gdjs.Start_32GameCode.condition0IsTrue_0.val = false;
gdjs.Start_32GameCode.condition1IsTrue_0.val = false;
{
gdjs.Start_32GameCode.condition0IsTrue_0.val = gdjs.evtTools.input.cursorOnObject(gdjs.Start_32GameCode.mapOfGDgdjs_46Start_9532GameCode_46GDOptionsObjects1Objects, runtimeScene, true, false);
}if ( gdjs.Start_32GameCode.condition0IsTrue_0.val ) {
{
gdjs.Start_32GameCode.condition1IsTrue_0.val = gdjs.evtTools.input.isMouseButtonPressed(runtimeScene, "Left");
}}
if (gdjs.Start_32GameCode.condition1IsTrue_0.val) {
{gdjs.evtTools.runtimeScene.replaceScene(runtimeScene, "Options", false);
}}
}
{
gdjs.Start_32GameCode.GDCreditsObjects1.createFrom(runtimeScene.getObjects("Credits"));
gdjs.Start_32GameCode.condition0IsTrue_0.val = false;
gdjs.Start_32GameCode.condition1IsTrue_0.val = false;
{
gdjs.Start_32GameCode.condition0IsTrue_0.val = gdjs.evtTools.input.cursorOnObject(gdjs.Start_32GameCode.mapOfGDgdjs_46Start_9532GameCode_46GDCreditsObjects1Objects, runtimeScene, true, false);
}if ( gdjs.Start_32GameCode.condition0IsTrue_0.val ) {
{
gdjs.Start_32GameCode.condition1IsTrue_0.val = gdjs.evtTools.input.isMouseButtonPressed(runtimeScene, "Left");
}}
if (gdjs.Start_32GameCode.condition1IsTrue_0.val) {
{gdjs.evtTools.runtimeScene.replaceScene(runtimeScene, "Credits", false);
}}
}
{
gdjs.Start_32GameCode.condition0IsTrue_0.val = false;
{
gdjs.Start_32GameCode.condition0IsTrue_0.val = gdjs.evtTools.runtimeScene.sceneJustBegins(runtimeScene);
}if (gdjs.Start_32GameCode.condition0IsTrue_0.val) {
{gdjs.evtTools.sound.playSound(runtimeScene, "Festa-di-Laurea-piena-da-convertire.ogg", false, 100, 1);
}}
}
}; //End of gdjs.Start_32GameCode.eventsList0x5b6e18
gdjs.Start_32GameCode.func = function(runtimeScene) {
runtimeScene.getOnceTriggers().startNewFrame();
gdjs.Start_32GameCode.GDSfondoObjects1.length = 0;
gdjs.Start_32GameCode.GDSfondoObjects2.length = 0;
gdjs.Start_32GameCode.GDTitoloGiocoObjects1.length = 0;
gdjs.Start_32GameCode.GDTitoloGiocoObjects2.length = 0;
gdjs.Start_32GameCode.GDNewObjectObjects1.length = 0;
gdjs.Start_32GameCode.GDNewObjectObjects2.length = 0;
gdjs.Start_32GameCode.GDNewObject2Objects1.length = 0;
gdjs.Start_32GameCode.GDNewObject2Objects2.length = 0;
gdjs.Start_32GameCode.GDOptionsObjects1.length = 0;
gdjs.Start_32GameCode.GDOptionsObjects2.length = 0;
gdjs.Start_32GameCode.GDCreditsObjects1.length = 0;
gdjs.Start_32GameCode.GDCreditsObjects2.length = 0;
gdjs.Start_32GameCode.GDPlayObjects1.length = 0;
gdjs.Start_32GameCode.GDPlayObjects2.length = 0;
gdjs.Start_32GameCode.eventsList0x5b6e18(runtimeScene);
return;
}
gdjs['Start_32GameCode'] = gdjs.Start_32GameCode;

View File

@ -0,0 +1,111 @@
gdjs.TitleCode = {};
gdjs.TitleCode.GDBackgroundObjects1= [];
gdjs.TitleCode.GDBackgroundObjects2= [];
gdjs.TitleCode.GDTitleObjects1= [];
gdjs.TitleCode.GDTitleObjects2= [];
gdjs.TitleCode.GDInstruction1Objects1= [];
gdjs.TitleCode.GDInstruction1Objects2= [];
gdjs.TitleCode.GDInstruction2Objects1= [];
gdjs.TitleCode.GDInstruction2Objects2= [];
gdjs.TitleCode.GDNewObject3Objects1= [];
gdjs.TitleCode.GDNewObject3Objects2= [];
gdjs.TitleCode.GDNewObjectObjects1= [];
gdjs.TitleCode.GDNewObjectObjects2= [];
gdjs.TitleCode.GDGiocaAncoraObjects1= [];
gdjs.TitleCode.GDGiocaAncoraObjects2= [];
gdjs.TitleCode.conditionTrue_0 = {val:false};
gdjs.TitleCode.condition0IsTrue_0 = {val:false};
gdjs.TitleCode.condition1IsTrue_0 = {val:false};
gdjs.TitleCode.condition2IsTrue_0 = {val:false};
gdjs.TitleCode.mapOfGDgdjs_46TitleCode_46GDGiocaAncoraObjects1Objects = Hashtable.newFrom({"GiocaAncora": gdjs.TitleCode.GDGiocaAncoraObjects1});gdjs.TitleCode.eventsList0xb12b54 = function(runtimeScene) {
{
gdjs.TitleCode.GDGiocaAncoraObjects1.createFrom(runtimeScene.getObjects("GiocaAncora"));
gdjs.TitleCode.condition0IsTrue_0.val = false;
gdjs.TitleCode.condition1IsTrue_0.val = false;
{
gdjs.TitleCode.condition0IsTrue_0.val = gdjs.evtTools.input.cursorOnObject(gdjs.TitleCode.mapOfGDgdjs_46TitleCode_46GDGiocaAncoraObjects1Objects, runtimeScene, true, false);
}if ( gdjs.TitleCode.condition0IsTrue_0.val ) {
{
gdjs.TitleCode.condition1IsTrue_0.val = gdjs.evtTools.input.isMouseButtonPressed(runtimeScene, "Left");
}}
if (gdjs.TitleCode.condition1IsTrue_0.val) {
{gdjs.evtTools.runtimeScene.replaceScene(runtimeScene, "Phase1", true);
}}
}
}; //End of gdjs.TitleCode.eventsList0xb12b54
gdjs.TitleCode.eventsList0x5b6e18 = function(runtimeScene) {
{
gdjs.TitleCode.condition0IsTrue_0.val = false;
{
gdjs.TitleCode.condition0IsTrue_0.val = gdjs.evtTools.runtimeScene.sceneJustBegins(runtimeScene);
}if (gdjs.TitleCode.condition0IsTrue_0.val) {
{gdjs.evtTools.window.setFullScreen(runtimeScene, true, true);
}{gdjs.evtTools.runtimeScene.resetTimer(runtimeScene, "");
}{runtimeScene.getGame().getVariables().getFromIndex(0).setNumber(0);
}{gdjs.evtTools.sound.playSound(runtimeScene, "Lose-da-converitre-in-ogg.ogg", false, 100, 1);
}}
}
{
}
{
gdjs.TitleCode.condition0IsTrue_0.val = false;
{
gdjs.TitleCode.condition0IsTrue_0.val = gdjs.evtTools.runtimeScene.timerElapsedTime(runtimeScene, 2, "");
}if (gdjs.TitleCode.condition0IsTrue_0.val) {
{ //Subevents
gdjs.TitleCode.eventsList0xb12b54(runtimeScene);} //End of subevents
}
}
}; //End of gdjs.TitleCode.eventsList0x5b6e18
gdjs.TitleCode.func = function(runtimeScene) {
runtimeScene.getOnceTriggers().startNewFrame();
gdjs.TitleCode.GDBackgroundObjects1.length = 0;
gdjs.TitleCode.GDBackgroundObjects2.length = 0;
gdjs.TitleCode.GDTitleObjects1.length = 0;
gdjs.TitleCode.GDTitleObjects2.length = 0;
gdjs.TitleCode.GDInstruction1Objects1.length = 0;
gdjs.TitleCode.GDInstruction1Objects2.length = 0;
gdjs.TitleCode.GDInstruction2Objects1.length = 0;
gdjs.TitleCode.GDInstruction2Objects2.length = 0;
gdjs.TitleCode.GDNewObject3Objects1.length = 0;
gdjs.TitleCode.GDNewObject3Objects2.length = 0;
gdjs.TitleCode.GDNewObjectObjects1.length = 0;
gdjs.TitleCode.GDNewObjectObjects2.length = 0;
gdjs.TitleCode.GDGiocaAncoraObjects1.length = 0;
gdjs.TitleCode.GDGiocaAncoraObjects2.length = 0;
gdjs.TitleCode.eventsList0x5b6e18(runtimeScene);
return;
}
gdjs['TitleCode'] = gdjs.TitleCode;

View File

@ -0,0 +1,71 @@
gdjs.WinPageCode = {};
gdjs.WinPageCode.GDSfondoObjects1= [];
gdjs.WinPageCode.GDSfondoObjects2= [];
gdjs.WinPageCode.GDNewObjectObjects1= [];
gdjs.WinPageCode.GDNewObjectObjects2= [];
gdjs.WinPageCode.GDNewObject2Objects1= [];
gdjs.WinPageCode.GDNewObject2Objects2= [];
gdjs.WinPageCode.GDGiocaAncoraObjects1= [];
gdjs.WinPageCode.GDGiocaAncoraObjects2= [];
gdjs.WinPageCode.conditionTrue_0 = {val:false};
gdjs.WinPageCode.condition0IsTrue_0 = {val:false};
gdjs.WinPageCode.condition1IsTrue_0 = {val:false};
gdjs.WinPageCode.condition2IsTrue_0 = {val:false};
gdjs.WinPageCode.mapOfGDgdjs_46WinPageCode_46GDGiocaAncoraObjects1Objects = Hashtable.newFrom({"GiocaAncora": gdjs.WinPageCode.GDGiocaAncoraObjects1});gdjs.WinPageCode.eventsList0x5b6e18 = function(runtimeScene) {
{
gdjs.WinPageCode.GDGiocaAncoraObjects1.createFrom(runtimeScene.getObjects("GiocaAncora"));
gdjs.WinPageCode.condition0IsTrue_0.val = false;
gdjs.WinPageCode.condition1IsTrue_0.val = false;
{
gdjs.WinPageCode.condition0IsTrue_0.val = gdjs.evtTools.input.cursorOnObject(gdjs.WinPageCode.mapOfGDgdjs_46WinPageCode_46GDGiocaAncoraObjects1Objects, runtimeScene, true, false);
}if ( gdjs.WinPageCode.condition0IsTrue_0.val ) {
{
gdjs.WinPageCode.condition1IsTrue_0.val = gdjs.evtTools.input.isMouseButtonPressed(runtimeScene, "Left");
}}
if (gdjs.WinPageCode.condition1IsTrue_0.val) {
{gdjs.evtTools.runtimeScene.replaceScene(runtimeScene, "Phase1", false);
}}
}
{
gdjs.WinPageCode.condition0IsTrue_0.val = false;
{
gdjs.WinPageCode.condition0IsTrue_0.val = gdjs.evtTools.runtimeScene.sceneJustBegins(runtimeScene);
}if (gdjs.WinPageCode.condition0IsTrue_0.val) {
{gdjs.evtTools.sound.playSound(runtimeScene, "Win-da-convertire-in-OGG.ogg", false, 100, 1);
}}
}
}; //End of gdjs.WinPageCode.eventsList0x5b6e18
gdjs.WinPageCode.func = function(runtimeScene) {
runtimeScene.getOnceTriggers().startNewFrame();
gdjs.WinPageCode.GDSfondoObjects1.length = 0;
gdjs.WinPageCode.GDSfondoObjects2.length = 0;
gdjs.WinPageCode.GDNewObjectObjects1.length = 0;
gdjs.WinPageCode.GDNewObjectObjects2.length = 0;
gdjs.WinPageCode.GDNewObject2Objects1.length = 0;
gdjs.WinPageCode.GDNewObject2Objects2.length = 0;
gdjs.WinPageCode.GDGiocaAncoraObjects1.length = 0;
gdjs.WinPageCode.GDGiocaAncoraObjects2.length = 0;
gdjs.WinPageCode.eventsList0x5b6e18(runtimeScene);
return;
}
gdjs['WinPageCode'] = gdjs.WinPageCode;

View File

@ -0,0 +1,54 @@
gdjs.OptionsCode = {};
gdjs.OptionsCode.GDNewObjectObjects1= [];
gdjs.OptionsCode.GDNewObjectObjects2= [];
gdjs.OptionsCode.GDComandiGiocoObjects1= [];
gdjs.OptionsCode.GDComandiGiocoObjects2= [];
gdjs.OptionsCode.GDHomeObjects1= [];
gdjs.OptionsCode.GDHomeObjects2= [];
gdjs.OptionsCode.conditionTrue_0 = {val:false};
gdjs.OptionsCode.condition0IsTrue_0 = {val:false};
gdjs.OptionsCode.condition1IsTrue_0 = {val:false};
gdjs.OptionsCode.condition2IsTrue_0 = {val:false};
gdjs.OptionsCode.mapOfGDgdjs_46OptionsCode_46GDHomeObjects1Objects = Hashtable.newFrom({"Home": gdjs.OptionsCode.GDHomeObjects1});gdjs.OptionsCode.eventsList0x5b6e18 = function(runtimeScene) {
{
gdjs.OptionsCode.GDHomeObjects1.createFrom(runtimeScene.getObjects("Home"));
gdjs.OptionsCode.condition0IsTrue_0.val = false;
gdjs.OptionsCode.condition1IsTrue_0.val = false;
{
gdjs.OptionsCode.condition0IsTrue_0.val = gdjs.evtTools.input.cursorOnObject(gdjs.OptionsCode.mapOfGDgdjs_46OptionsCode_46GDHomeObjects1Objects, runtimeScene, true, false);
}if ( gdjs.OptionsCode.condition0IsTrue_0.val ) {
{
gdjs.OptionsCode.condition1IsTrue_0.val = gdjs.evtTools.input.isMouseButtonPressed(runtimeScene, "Left");
}}
if (gdjs.OptionsCode.condition1IsTrue_0.val) {
{gdjs.evtTools.runtimeScene.replaceScene(runtimeScene, "Start Game", false);
}}
}
}; //End of gdjs.OptionsCode.eventsList0x5b6e18
gdjs.OptionsCode.func = function(runtimeScene) {
runtimeScene.getOnceTriggers().startNewFrame();
gdjs.OptionsCode.GDNewObjectObjects1.length = 0;
gdjs.OptionsCode.GDNewObjectObjects2.length = 0;
gdjs.OptionsCode.GDComandiGiocoObjects1.length = 0;
gdjs.OptionsCode.GDComandiGiocoObjects2.length = 0;
gdjs.OptionsCode.GDHomeObjects1.length = 0;
gdjs.OptionsCode.GDHomeObjects2.length = 0;
gdjs.OptionsCode.eventsList0x5b6e18(runtimeScene);
return;
}
gdjs['OptionsCode'] = gdjs.OptionsCode;

View File

@ -0,0 +1,58 @@
gdjs.CreditsCode = {};
gdjs.CreditsCode.GDNewObjectObjects1= [];
gdjs.CreditsCode.GDNewObjectObjects2= [];
gdjs.CreditsCode.GDNewObject2Objects1= [];
gdjs.CreditsCode.GDNewObject2Objects2= [];
gdjs.CreditsCode.GDNewObject3Objects1= [];
gdjs.CreditsCode.GDNewObject3Objects2= [];
gdjs.CreditsCode.GDNewObject4Objects1= [];
gdjs.CreditsCode.GDNewObject4Objects2= [];
gdjs.CreditsCode.conditionTrue_0 = {val:false};
gdjs.CreditsCode.condition0IsTrue_0 = {val:false};
gdjs.CreditsCode.condition1IsTrue_0 = {val:false};
gdjs.CreditsCode.condition2IsTrue_0 = {val:false};
gdjs.CreditsCode.mapOfGDgdjs_46CreditsCode_46GDNewObject2Objects1Objects = Hashtable.newFrom({"NewObject2": gdjs.CreditsCode.GDNewObject2Objects1});gdjs.CreditsCode.eventsList0x5b6e18 = function(runtimeScene) {
{
gdjs.CreditsCode.GDNewObject2Objects1.createFrom(runtimeScene.getObjects("NewObject2"));
gdjs.CreditsCode.condition0IsTrue_0.val = false;
gdjs.CreditsCode.condition1IsTrue_0.val = false;
{
gdjs.CreditsCode.condition0IsTrue_0.val = gdjs.evtTools.input.cursorOnObject(gdjs.CreditsCode.mapOfGDgdjs_46CreditsCode_46GDNewObject2Objects1Objects, runtimeScene, true, false);
}if ( gdjs.CreditsCode.condition0IsTrue_0.val ) {
{
gdjs.CreditsCode.condition1IsTrue_0.val = gdjs.evtTools.input.isMouseButtonPressed(runtimeScene, "Left");
}}
if (gdjs.CreditsCode.condition1IsTrue_0.val) {
{gdjs.evtTools.runtimeScene.replaceScene(runtimeScene, "Start Game", false);
}}
}
}; //End of gdjs.CreditsCode.eventsList0x5b6e18
gdjs.CreditsCode.func = function(runtimeScene) {
runtimeScene.getOnceTriggers().startNewFrame();
gdjs.CreditsCode.GDNewObjectObjects1.length = 0;
gdjs.CreditsCode.GDNewObjectObjects2.length = 0;
gdjs.CreditsCode.GDNewObject2Objects1.length = 0;
gdjs.CreditsCode.GDNewObject2Objects2.length = 0;
gdjs.CreditsCode.GDNewObject3Objects1.length = 0;
gdjs.CreditsCode.GDNewObject3Objects2.length = 0;
gdjs.CreditsCode.GDNewObject4Objects1.length = 0;
gdjs.CreditsCode.GDNewObject4Objects2.length = 0;
gdjs.CreditsCode.eventsList0x5b6e18(runtimeScene);
return;
}
gdjs['CreditsCode'] = gdjs.CreditsCode;

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,201 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* @memberof gdjs.evtTools
* @class camera
* @private
*/
gdjs.evtTools.camera = gdjs.evtTools.camera || {};
gdjs.evtTools.camera.setCameraX = function(runtimeScene, x, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
runtimeScene.getLayer(layer).setCameraX(x, cameraId);
}
gdjs.evtTools.camera.setCameraY = function(runtimeScene, y, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
runtimeScene.getLayer(layer).setCameraY(y, cameraId);
}
gdjs.evtTools.camera.getCameraX = function(runtimeScene, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
return runtimeScene.getLayer(layer).getCameraX();
}
gdjs.evtTools.camera.getCameraY = function(runtimeScene, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
return runtimeScene.getLayer(layer).getCameraY();
}
gdjs.evtTools.camera.getCameraWidth = function(runtimeScene, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
return runtimeScene.getLayer(layer).getCameraWidth();
}
gdjs.evtTools.camera.getCameraHeight = function(runtimeScene, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
return runtimeScene.getLayer(layer).getCameraHeight();
}
gdjs.evtTools.camera.showLayer = function(runtimeScene, layer) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
return runtimeScene.getLayer(layer).show(true);
}
gdjs.evtTools.camera.hideLayer = function(runtimeScene, layer) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
return runtimeScene.getLayer(layer).show(false);
}
gdjs.evtTools.camera.layerIsVisible = function(runtimeScene, layer) {
return runtimeScene.hasLayer(layer) && runtimeScene.getLayer(layer).isVisible();
}
gdjs.evtTools.camera.setCameraRotation = function(runtimeScene, rotation, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
return runtimeScene.getLayer(layer).setCameraRotation(rotation, cameraId);
}
gdjs.evtTools.camera.getCameraRotation = function(runtimeScene, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return 0; }
return runtimeScene.getLayer(layer).getCameraRotation(cameraId);
}
gdjs.evtTools.camera.setCameraZoom = function(runtimeScene, newZoom, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
return runtimeScene.getLayer(layer).setCameraZoom(newZoom, cameraId);
}
gdjs.evtTools.camera.centerCamera = function(runtimeScene, object, anticipateMove, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) || object == null ) { return; }
var layer = runtimeScene.getLayer(layer);
var xOffset = 0; var yOffset = 0;
if ( anticipateMove && !object.hasNoForces() ) {
var objectAverageForce = object.getAverageForce();
var elapsedTimeInSeconds = object.getElapsedTime(runtimeScene) / 1000;
xOffset = objectAverageForce.getX() * elapsedTimeInSeconds;
yOffset = objectAverageForce.getY() * elapsedTimeInSeconds;
}
layer.setCameraX(object.getDrawableX()+object.getCenterX(), cameraId);
layer.setCameraY(object.getDrawableY()+object.getCenterY(), cameraId);
}
gdjs.evtTools.camera.centerCameraWithinLimits = function(runtimeScene, object, left, top, right, bottom, anticipateMove, layer, cameraId) {
if ( !runtimeScene.hasLayer(layer) || object == null ) { return; }
var layer = runtimeScene.getLayer(layer);
var xOffset = 0; var yOffset = 0;
if ( anticipateMove && !object.hasNoForces() ) {
var objectAverageForce = object.getAverageForce();
var elapsedTimeInSeconds = object.getElapsedTime(runtimeScene) / 1000;
xOffset = objectAverageForce.getX() * elapsedTimeInSeconds;
yOffset = objectAverageForce.getY() * elapsedTimeInSeconds;
}
var newX = object.getDrawableX()+object.getCenterX()+xOffset;
if ( newX < left +layer.getCameraWidth(cameraId)/2 ) newX = left+layer.getCameraWidth(cameraId)/2;
if ( newX > right-layer.getCameraWidth(cameraId)/2 ) newX = right-layer.getCameraWidth(cameraId)/2;
var newY = object.getDrawableY()+object.getCenterY()+yOffset;
if ( newY < top +layer.getCameraHeight(cameraId)/2 ) newY = top+layer.getCameraHeight(cameraId)/2;
if ( newY > bottom-layer.getCameraHeight(cameraId)/2 ) newY = bottom-layer.getCameraHeight(cameraId)/2;
layer.setCameraX(newX, cameraId);
layer.setCameraY(newY, cameraId);
}
/**
* Update a layer effect parameter (with a number).
* @param {gdjs.RuntimeScene} runtimeScene The scene
* @param {string} layer The name of the layer
* @param {string} effect The name of the effect
* @param {string} parameter The parameter to update
* @param {number} value The new value
*/
gdjs.evtTools.camera.setLayerEffectDoubleParameter = function(runtimeScene, layer, effect, parameter, value) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
return runtimeScene.getLayer(layer).setEffectDoubleParameter(effect, parameter, value);
}
/**
* Update a layer effect parameter (with a string).
* @param {gdjs.RuntimeScene} runtimeScene The scene
* @param {string} layer The name of the layer
* @param {string} effect The name of the effect
* @param {string} parameter The parameter to update
* @param {string} value The new value
*/
gdjs.evtTools.camera.setLayerEffectStringParameter = function(runtimeScene, layer, effect, parameter, value) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
return runtimeScene.getLayer(layer).setEffectStringParameter(effect, parameter, value);
}
/**
* Enable or disable a layer effect parameter (boolean).
* @param {gdjs.RuntimeScene} runtimeScene The scene
* @param {string} layer The name of the layer
* @param {string} effect The name of the effect
* @param {string} parameter The parameter to update
* @param {boolean} value The new value
*/
gdjs.evtTools.camera.setLayerEffectBooleanParameter = function(runtimeScene, layer, effect, parameter, value) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
return runtimeScene.getLayer(layer).setEffectBooleanParameter(effect, parameter, value);
}
/**
* Enable, or disable, an effect of a layer.
* @param {gdjs.RuntimeScene} runtimeScene The scene
* @param {string} layer The name of the layer
* @param {string} effect The name of the effect
* @param {boolean} enabled true to enable, false to disable.
*/
gdjs.evtTools.camera.enableLayerEffect = function(runtimeScene, layer, effect, enabled) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
runtimeScene.getLayer(layer).enableEffect(effect, enabled);
}
/**
* Check if an effect is enabled.
* @param {gdjs.RuntimeScene} runtimeScene The scene
* @param {string} layer The name of the layer
* @param {string} effect The name of the effect
* @return {boolean} true if the effect is enabled, false otherwise.
*/
gdjs.evtTools.camera.layerEffectEnabled = function(runtimeScene, layer, effect) {
if ( !runtimeScene.hasLayer(layer) ) { return true; }
return runtimeScene.getLayer(layer).isEffectEnabled(effect);
}
gdjs.evtTools.camera.setLayerTimeScale = function(runtimeScene, layer, timeScale) {
if ( !runtimeScene.hasLayer(layer) ) { return; }
return runtimeScene.getLayer(layer).setTimeScale(timeScale);
}
gdjs.evtTools.camera.getLayerTimeScale = function(runtimeScene, layer) {
if ( !runtimeScene.hasLayer(layer) ) { return 1; }
return runtimeScene.getLayer(layer).getTimeScale();
}

View File

@ -0,0 +1,196 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* @memberof gdjs.evtTools
* @class common
* @static
* @private
*/
gdjs.evtTools.common = gdjs.evtTools.common || {};
/**
* Get the value of a variable. Equivalent of variable.getAsNumber().
* @private
*/
gdjs.evtTools.common.getVariableNumber = function(variable) {
return variable.getAsNumber();
};
/**
* Get the string of a variable. Equivalent of variable.getAsString().
* @private
*/
gdjs.evtTools.common.getVariableString = function(variable) {
return variable.getAsString();
};
/**
* @private
*/
gdjs.evtTools.common.sceneVariableExists = function(
runtimeScene,
variableName
) {
return runtimeScene.getVariables().has(variableName);
};
/**
* @private
*/
gdjs.evtTools.common.globalVariableExists = function(
runtimeScene,
variableName
) {
return runtimeScene
.getGame()
.getVariables()
.has(variableName);
};
/**
* @private
*/
gdjs.evtTools.common.variableChildExists = function(variable, childName) {
return variable.hasChild(childName);
};
/**
* @private
*/
gdjs.evtTools.common.variableRemoveChild = function(variable, childName) {
return variable.removeChild(childName);
};
/**
* @private
*/
gdjs.evtTools.common.variableClearChildren = function(variable) {
variable.clearChildren();
};
/**
* @private
*/
gdjs.evtTools.common.getVariableChildCount = function(variable) {
if (variable.isStructure() == false) return 0;
return Object.keys(variable.getAllChildren()).length;
};
/**
* Convert a string to a float.
* @private
*/
gdjs.evtTools.common.toNumber = function(str) {
return parseFloat(str);
};
/**
* Convert a number to a string.
* @private
*/
gdjs.evtTools.common.toString = function(num) {
//Using String literal is fastest than using toString according to
//http://jsperf.com/number-to-string/2 and http://jsben.ch/#/ghQYR
return '' + num;
};
/**
* Negate the boolean.
* @private
*/
gdjs.evtTools.common.logicalNegation = function(bool) {
return !bool;
};
gdjs.evtTools.common.clamp = function(x, min, max) {
return Math.min(Math.max(x, min), max);
};
gdjs.evtTools.common.acosh = function(arg) {
// http://kevin.vanzonneveld.net
// + original by: Onno Marsman
return Math.log(arg + Math.sqrt(arg * arg - 1));
};
gdjs.evtTools.common.asinh = function(arg) {
// http://kevin.vanzonneveld.net
// + original by: Onno Marsman
return Math.log(arg + Math.sqrt(arg * arg + 1));
};
gdjs.evtTools.common.atanh = function(arg) {
// http://kevin.vanzonneveld.net
// + original by: Onno Marsman
return 0.5 * Math.log((1 + arg) / (1 - arg));
};
gdjs.evtTools.common.cosh = function(arg) {
return (Math.exp(arg) + Math.exp(-arg)) / 2;
};
gdjs.evtTools.common.sinh = function(arg) {
return (Math.exp(arg) - Math.exp(-arg)) / 2;
};
gdjs.evtTools.common.tanh = function(arg) {
return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg));
};
gdjs.evtTools.common.cot = function(arg) {
return 1 / Math.tan(arg);
};
gdjs.evtTools.common.csc = function(arg) {
return 1 / Math.sin(arg);
};
gdjs.evtTools.common.sec = function(arg) {
return 1 / Math.cos(arg);
};
gdjs.evtTools.common.log10 = function(arg) {
return Math.log(arg) / Math.LN10;
};
gdjs.evtTools.common.log2 = function(arg) {
return Math.log(arg) / Math.LN2;
};
gdjs.evtTools.common.sign = function(arg) {
if (arg === 0) return 0;
return arg > 0 ? +1 : -1;
};
gdjs.evtTools.common.cbrt = function(x) {
return Math.pow(x, 1 / 3);
};
gdjs.evtTools.common.nthroot = function(x, n) {
return Math.pow(x, 1 / n);
};
gdjs.evtTools.common.mod = function(x, y) {
return x - y * Math.floor(x / y);
};
gdjs.evtTools.common.angleDifference = function(angle1, angle2) {
return (
gdjs.evtTools.common.mod(
gdjs.evtTools.common.mod(angle1 - angle2, 360.0) + 180.0,
360.0
) - 180.0
);
};
gdjs.evtTools.common.lerp = function(a, b, x) {
return a + (b - a) * x;
};
gdjs.evtTools.common.trunc = function(x) {
return x | 0;
};

View File

@ -0,0 +1,284 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Tools related to input ( Keyboard, mouse ), for events generated code.
*
* @memberof gdjs.evtTools
* @class input
* @static
* @private
*/
gdjs.evtTools.input = gdjs.evtTools.input || {};
/**
* Return true if the specified key is pressed
*
* @private
*/
gdjs.evtTools.input.isKeyPressed = function(runtimeScene, key) {
if (gdjs.evtTools.input.keysNameToCode.hasOwnProperty(key)) {
return runtimeScene.getGame().getInputManager().isKeyPressed(gdjs.evtTools.input.keysNameToCode[key]);
}
return false;
};
/**
* Return true if the specified key was just released
*
* @private
*/
gdjs.evtTools.input.wasKeyReleased = function(runtimeScene, key) {
if (gdjs.evtTools.input.keysNameToCode.hasOwnProperty(key)) {
return runtimeScene.getGame().getInputManager().wasKeyReleased(gdjs.evtTools.input.keysNameToCode[key]);
}
return false;
};
/**
* Return the name of the last key pressed in the game
* @private
*/
gdjs.evtTools.input.lastPressedKey = function(runtimeScene) {
//Ensure _keysCodeToName is constructed
if (gdjs.evtTools.input._keysCodeToName === undefined) {
gdjs.evtTools.input._keysCodeToName = {};
var keysNameToCode = gdjs.evtTools.input.keysNameToCode;
for(var p in keysNameToCode) {
if (keysNameToCode.hasOwnProperty(p)) {
gdjs.evtTools.input._keysCodeToName[keysNameToCode[p]] = p;
}
}
}
var keyCode = runtimeScene.getGame().getInputManager().getLastPressedKey();
if (gdjs.evtTools.input._keysCodeToName.hasOwnProperty(keyCode)) {
return gdjs.evtTools.input._keysCodeToName[keyCode];
}
return "";
};
/**
* Hashmap associated each name of a key to its keyCode.
* @memberof gdjs.evtTools
*/
gdjs.evtTools.input.keysNameToCode = {
"a": 65,
"b": 66,
"c": 67,
"d": 68,
"e": 69,
"f": 70,
"g": 71,
"h": 72,
"i": 73,
"j": 74,
"k": 75,
"l": 76,
"m": 77,
"n": 78,
"o": 79,
"p": 80,
"q": 81,
"r": 82,
"s": 83,
"t": 84,
"u": 85,
"v": 86,
"w": 87,
"x": 88,
"y": 89,
"z": 90,
"Num0": 48,
"Num1": 49,
"Num2": 50,
"Num3": 51,
"Num4": 52,
"Num5": 53,
"Num6": 54,
"Num7": 55,
"Num8": 56,
"Num9": 57,
"Numpad0": 96,
"Numpad1": 97,
"Numpad2": 98,
"Numpad3": 99,
"Numpad4": 100,
"Numpad5": 101,
"Numpad6": 102,
"Numpad7": 103,
"Numpad8": 104,
"Numpad9": 105,
"RControl": 17,
"RShift": 16,
"RAlt": 18,
"LControl": 17,
"LShift": 16,
"LAlt": 18,
"LSystem": 91,
"RSystem": 91,
/*"Menu": sf::Keyboard::Menu ,
"LBracket": sf::Keyboard::LBracket ,
"RBracket": sf::Keyboard::RBracket ,
"SemiColon": sf::Keyboard::SemiColon ,
"Comma": sf::Keyboard::Comma ,
"Period": sf::Keyboard::Period ,
"Quote": sf::Keyboard::Quote ,
"Slash": sf::Keyboard::Slash ,
"BackSlash": sf::Keyboard::BackSlash ,
"Tilde": sf::Keyboard::Tilde ,
"Equal": sf::Keyboard::Equal ,
"Dash": sf::Keyboard::Dash,*/
"Space": 32,
"Return": 13,
"Back": 8,
"Tab": 9,
"PageUp": 33,
"PageDown": 34,
"End": 35,
"Home": 36,
"Delete": 46,
"Insert": 45,
"Escape": 27,
"Add": 107,
"Subtract": 109,
"Multiply": 106,
"Divide": 111,
"Left": 37,
"Up": 38,
"Right": 39,
"Down": 40,
"F1": 112,
"F2": 113,
"F3": 114,
"F4": 115,
"F5": 116,
"F6": 117,
"F7": 118,
"F8": 119,
"F9": 120,
"F10": 121,
"F11": 122,
"F12": 123,
"Pause": 19
};
gdjs.evtTools.input.anyKeyPressed = function(runtimeScene) {
return runtimeScene.getGame().getInputManager().anyKeyPressed();
};
gdjs.evtTools.input.isMouseButtonPressed = function(runtimeScene, button) {
if ( button === "Left" ) return runtimeScene.getGame().getInputManager().isMouseButtonPressed(0);
if ( button === "Right" ) return runtimeScene.getGame().getInputManager().isMouseButtonPressed(1);
if ( button === "Middle" ) return runtimeScene.getGame().getInputManager().isMouseButtonPressed(2);
return false;
};
gdjs.evtTools.input.isMouseButtonReleased = function(runtimeScene, button) {
if ( button === "Left" ) return runtimeScene.getGame().getInputManager().isMouseButtonReleased(0);
if ( button === "Right" ) return runtimeScene.getGame().getInputManager().isMouseButtonReleased(1);
if ( button === "Middle" ) return runtimeScene.getGame().getInputManager().isMouseButtonReleased(2);
return false;
};
gdjs.evtTools.input.hideCursor = function(runtimeScene) {
runtimeScene.getRenderer().hideCursor();
};
gdjs.evtTools.input.showCursor = function(runtimeScene) {
runtimeScene.getRenderer().showCursor();
};
gdjs.evtTools.input.getMouseWheelDelta = function(runtimeScene) {
return runtimeScene.getGame().getInputManager().getMouseWheelDelta();
};
gdjs.evtTools.input.isScrollingUp = function(runtimeScene) {
return runtimeScene.getGame().getInputManager().isScrollingUp();
};
gdjs.evtTools.input.isScrollingDown = function(runtimeScene) {
return runtimeScene.getGame().getInputManager().isScrollingDown();
};
gdjs.evtTools.input.getMouseX = function(runtimeScene, layer, camera) {
return runtimeScene.getLayer(layer).convertCoords(
runtimeScene.getGame().getInputManager().getMouseX(),
runtimeScene.getGame().getInputManager().getMouseY())[0];
};
gdjs.evtTools.input.getMouseY = function(runtimeScene, layer, camera) {
return runtimeScene.getLayer(layer).convertCoords(
runtimeScene.getGame().getInputManager().getMouseX(),
runtimeScene.getGame().getInputManager().getMouseY())[1];
};
gdjs.evtTools.input._cursorIsOnObject = function(obj, runtimeScene) {
return obj.cursorOnObject(runtimeScene);
};
gdjs.evtTools.input.cursorOnObject = function(objectsLists, runtimeScene, accurate, inverted) {
return gdjs.evtTools.object.pickObjectsIf(gdjs.evtTools.input._cursorIsOnObject,
objectsLists, inverted, runtimeScene);
};
gdjs.evtTools.input.getTouchX = function(runtimeScene, identifier, layer, camera) {
return runtimeScene.getLayer(layer).convertCoords(
runtimeScene.getGame().getInputManager().getTouchX(identifier),
runtimeScene.getGame().getInputManager().getTouchY(identifier))[0];
};
gdjs.evtTools.input.getTouchY = function(runtimeScene, identifier, layer, camera) {
return runtimeScene.getLayer(layer).convertCoords(
runtimeScene.getGame().getInputManager().getTouchX(identifier),
runtimeScene.getGame().getInputManager().getTouchY(identifier))[1];
};
gdjs.evtTools.input.getLastTouchId = function() {
return gdjs.evtTools.input.lastTouchId || 0;
};
gdjs.evtTools.input.getLastEndedTouchId = function() {
return gdjs.evtTools.input.lastEndedTouchId || 0;
};
gdjs.evtTools.input.popStartedTouch = function(runtimeScene) {
var startedTouchId = runtimeScene.getGame().getInputManager().popStartedTouch();
if (startedTouchId !== undefined) {
gdjs.evtTools.input.lastTouchId = startedTouchId;
return true;
}
return false;
};
gdjs.evtTools.input.popEndedTouch = function(runtimeScene) {
var endedTouchId = runtimeScene.getGame().getInputManager().popEndedTouch();
if (endedTouchId !== undefined) {
gdjs.evtTools.input.lastEndedTouchId = endedTouchId;
return true;
}
return false;
};
gdjs.evtTools.input.touchSimulateMouse = function(runtimeScene, enable) {
runtimeScene.getGame().getInputManager().touchSimulateMouse(enable);
};

View File

@ -0,0 +1,127 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* @memberof gdjs.evtTools
* @namespace network
*/
gdjs.evtTools.network = gdjs.evtTools.network || {};
gdjs.evtTools.network.sendHttpRequest = function(host, uri, body, method, contentType, responseVar)
{
try {
var xhr;
if (typeof XMLHttpRequest !== 'undefined')
xhr = new XMLHttpRequest();
else {
var versions = ["MSXML2.XmlHttp.5.0",
"MSXML2.XmlHttp.4.0",
"MSXML2.XmlHttp.3.0",
"MSXML2.XmlHttp.2.0",
"Microsoft.XmlHttp"]
for(var i = 0, len = versions.length; i < len; i++) {
try {
xhr = new ActiveXObject(versions[i]);
break;
}
catch(e){}
} // end for
}
if ( xhr === undefined ) return;
xhr.open(method, host+uri, false);
xhr.setRequestHeader( "Content-Type", contentType === "" ? "application/x-www-form-urlencoded" : contentType );
xhr.send(body);
responseVar.setString(xhr.responseText);
}
catch(e){}
};
/**
* Convert a variable to JSON.
* TODO: Move to gdjs.Variable static
* @param {gdjs.Variable} variable The variable to convert to JSON
* @returns {string} The JSON string representing the variable
*/
gdjs.evtTools.network.variableStructureToJSON = function(variable)
{
if ( !variable.isStructure() ) {
if ( variable.isNumber() )
return JSON.stringify(variable.getAsNumber());
else
return JSON.stringify(variable.getAsString());
}
var str = "{";
var firstChild = true;
var children = variable.getAllChildren();
for(var p in children) {
if (children.hasOwnProperty(p)) {
if ( !firstChild ) str += ",";
str += JSON.stringify(p) + ": " + gdjs.evtTools.network.variableStructureToJSON(children[p]);
firstChild = false;
}
}
str += "}";
return str;
};
gdjs.evtTools.network.objectVariableStructureToJSON = function(object, variable)
{
return gdjs.evtTools.network.variableStructureToJSON(variable);
}
gdjs.evtTools.network._objectToVariable = function(obj, variable)
{
if(!isNaN(obj)) { //Number
variable.setNumber(obj);
}
else if (typeof obj == 'string' || obj instanceof String) {
variable.setString(obj);
}
else if ( Array.isArray(obj) ) {
for(var i = 0;i<obj.length;++i) {
gdjs.evtTools.network._objectToVariable(obj[i], variable.getChild(i.toString()));
}
}
else {
for(var p in obj) {
if (obj.hasOwnProperty(p)) {
gdjs.evtTools.network._objectToVariable(obj[p], variable.getChild(p));
}
}
}
}
/**
* Parse the given JSON and fill the content of the variable with it
* TODO: Move to gdjs.Variable static
* @param {string} jsonStr The JSON string
* @param {gdjs.Variable} variable The variable where to put the parsed JSON
* @returns {boolean} true if JSON was properly parsed
*/
gdjs.evtTools.network.jsonToVariableStructure = function(jsonStr, variable)
{
if ( jsonStr.length === 0 ) return false;
try {
var obj = JSON.parse(jsonStr);
gdjs.evtTools.network._objectToVariable(obj, variable);
return true;
} catch(e) {
//Do nothing iF JSON was not properly parsed;
return false;
}
}
gdjs.evtTools.network.jsonToObjectVariableStructure = function(jsonStr, object, variable)
{
gdjs.evtTools.network.jsonToVariableStructure(jsonStr, variable);
}

View File

@ -0,0 +1,437 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Tools related to objects, for events generated code.
* @memberof gdjs.evtTools
* @namespace object
*/
gdjs.evtTools.object = gdjs.evtTools.object || {};
/**
* Keep only the specified object in the lists of picked objects.
*
* @param {Hashtable} objectsLists The lists of objects to trim
* @param {gdjs.RuntimeObject} runtimeObject The object to keep in the lists
*/
gdjs.evtTools.object.pickOnly = function(objectsLists, runtimeObject) {
for (var listName in objectsLists.items) {
if (objectsLists.items.hasOwnProperty(listName)) {
var list = objectsLists.items[listName];
if (list.indexOf(runtimeObject) === -1) {
list.length = 0; //Be sure not to lose the reference to the original array
} else {
list.length = 0; //Be sure not to lose the reference to the original array
list.push(runtimeObject);
}
}
}
};
/**
* A predicate to be passed to `gdjs.evtTools.object.twoListsTest`.
* @callback gdjsTwoListsTestPredicate
* @param {gdjs.RuntimeObject} object1 First object
* @param {gdjs.RuntimeObject} object2 Second object
* @param {*} extraArg An optional extra argument
* @return {boolean} true if the pair satisfy the predicate (for example,there is a collision), meaning that the objects will be picked, false otherwise (no collision).
*/
/**
* Do a test on two tables of objects so as to pick only the pair of objects for which the test is true.
*
* Note that the predicate method is not called stricly for each pair: When considering a pair of objects, if
* these objects have already been marked as picked, the predicate method won't be called again.
*
* Cost (Worst case, predicate being always false):
* Cost(Setting property 'picked' of NbObjList1+NbObjList2 objects to false)
* + Cost(predicate)*NbObjList1*NbObjList2
* + Cost(Testing NbObjList1+NbObjList2 booleans)
* + Cost(Removing NbObjList1+NbObjList2 objects from all the lists)
*
* Cost (Best case, predicate being always true):
* Cost(Setting property 'picked' of NbObjList1+NbObjList2 objects to false)
* + Cost(predicate)*(NbObjList1+NbObjList2)
* + Cost(Testing NbObjList1+NbObjList2 booleans)
*
*
* @param {gdjsTwoListsTestPredicate} predicate The predicate function is called with the two objects to compare, and an optional argument `extraArg`
* @param {Hashtable} objectsLists1 e.g. Hashtable.newFrom({ A: objects1 });
* @param {Hashtable} objectsLists2 e.g. Hashtable.newFrom({ B: objects2 });
* @param {boolean} inverted If `inverted` == true, only the objects of the first table are filtered.
* @param {*} extraArg (optional) This argument should be used to avoid declaring the predicate as a closure that would be created and destroyed at each call to twoListsTest (potentially multiple time per frame).
*/
gdjs.evtTools.object.twoListsTest = function(predicate, objectsLists1, objectsLists2, inverted, extraArg) {
var isTrue = false;
var objects1Lists = gdjs.staticArray(gdjs.evtTools.object.twoListsTest);
objectsLists1.values(objects1Lists);
var objects2Lists = gdjs.staticArray2(gdjs.evtTools.object.twoListsTest);
objectsLists2.values(objects2Lists);
for(var i = 0, leni = objects1Lists.length;i<leni;++i) {
var arr = objects1Lists[i];
for(var k = 0, lenk = arr.length;k<lenk;++k) {
arr[k].pick = false;
}
}
for(var i = 0, leni = objects2Lists.length;i<leni;++i) {
var arr = objects2Lists[i];
for(var k = 0, lenk = arr.length;k<lenk;++k) {
arr[k].pick = false;
}
}
//Launch the function for each object of the first list with each object
//of the second list.
for(var i = 0, leni = objects1Lists.length;i<leni;++i) {
var arr1 = objects1Lists[i];
for(var k = 0, lenk = arr1.length;k<lenk;++k) {
var atLeastOneObject = false;
for(var j = 0, lenj = objects2Lists.length;j<lenj;++j) {
var arr2 = objects2Lists[j];
for(var l = 0, lenl = arr2.length;l<lenl;++l) {
if (arr1[k].pick && arr2[l].pick) continue; //Avoid unnecessary costly call to predicate.
if (arr1[k].id !== arr2[l].id && predicate(arr1[k], arr2[l], extraArg)) {
if ( !inverted ) {
isTrue = true;
//Pick the objects
arr1[k].pick = true;
arr2[l].pick = true;
}
atLeastOneObject = true;
}
}
}
if ( !atLeastOneObject && inverted ) {
//For example, the object is not overlapping any other object.
isTrue = true;
arr1[k].pick = true;
}
}
}
//Trim not picked objects from lists.
for(var i = 0, leni = objects1Lists.length;i<leni;++i) {
var arr = objects1Lists[i];
var finalSize = 0;
for(var k = 0, lenk = arr.length;k<lenk;++k) {
var obj = arr[k];
if ( arr[k].pick ) {
arr[finalSize] = obj;
finalSize++;
}
}
arr.length = finalSize;
}
if ( !inverted ) {
for(var i = 0, leni = objects2Lists.length;i<leni;++i) {
var arr = objects2Lists[i];
var finalSize = 0;
for(var k = 0, lenk = arr.length;k<lenk;++k) {
var obj = arr[k];
if ( arr[k].pick ) {
arr[finalSize] = obj;
finalSize++;
}
}
arr.length = finalSize;
}
}
return isTrue;
}
/**
* Filter objects to keep only the one that fullfil the predicate
*
* Objects that do not fullfil the predicate are removed from objects lists.
*
* @param {Function} predicate The function applied to each object: must return true if the object fulfill the predicate.
* @param {Hashtable} objectsLists The lists of objects to trim
* @param {boolean} negatePredicate If set to true, the result of the predicate is negated.
* @param {*} extraArg Argument passed to the predicate (along with the object). Useful for avoiding relying on temporary closures.
* @return {boolean} true if at least one object fulfill the predicate.
*/
gdjs.evtTools.object.pickObjectsIf = function(predicate, objectsLists, negatePredicate, extraArg) {
var isTrue = false;
var lists = gdjs.staticArray(gdjs.evtTools.object.pickObjectsIf);
objectsLists.values(lists);
//Create a boolean for each object
for(var i = 0, leni = lists.length;i<leni;++i) {
var arr = lists[i];
for(var k = 0, lenk = arr.length;k<lenk;++k) {
arr[k].pick = false;
}
}
//Pick only objects that are fulfilling the predicate
for(var i = 0, leni = lists.length;i<leni;++i) {
var arr = lists[i];
for(var k = 0, lenk = arr.length;k<lenk;++k) {
if (negatePredicate ^ predicate(arr[k], extraArg)) {
isTrue = true;
arr[k].pick = true; //Pick the objects
}
}
}
//Trim not picked objects from lists.
for(var i = 0, leni = lists.length;i<leni;++i) {
var arr = lists[i];
var finalSize = 0;
for(var k = 0, lenk = arr.length;k<lenk;++k) {
var obj = arr[k];
if ( arr[k].pick ) {
arr[finalSize] = obj;
finalSize++;
}
}
arr.length = finalSize;
}
return isTrue;
};
gdjs.evtTools.object.hitBoxesCollisionTest = function(objectsLists1, objectsLists2, inverted, runtimeScene, ignoreTouchingEdges) {
return gdjs.evtTools.object.twoListsTest(gdjs.RuntimeObject.collisionTest,
objectsLists1, objectsLists2, inverted, ignoreTouchingEdges);
};
gdjs.evtTools.object._distanceBetweenObjects = function(obj1, obj2, distance) {
return obj1.getSqDistanceToObject(obj2) <= distance;
};
gdjs.evtTools.object.distanceTest = function(objectsLists1, objectsLists2, distance, inverted) {
return gdjs.evtTools.object.twoListsTest(gdjs.evtTools.object._distanceBetweenObjects,
objectsLists1, objectsLists2, inverted, distance*distance);
};
gdjs.evtTools.object._movesToward = function(obj1, obj2, tolerance) {
if ( obj1.hasNoForces() ) return false;
var objAngle = Math.atan2(obj2.getDrawableY()+obj2.getCenterY() - (obj1.getDrawableY()+obj1.getCenterY()),
obj2.getDrawableX()+obj2.getCenterX() - (obj1.getDrawableX()+obj1.getCenterX()));
objAngle *= 180/3.14159;
return Math.abs(gdjs.evtTools.common.angleDifference(obj1.getAverageForce().getAngle(), objAngle)) <= tolerance/2;
};
gdjs.evtTools.object.movesTowardTest = function(objectsLists1, objectsLists2, tolerance, inverted) {
return gdjs.evtTools.object.twoListsTest(gdjs.evtTools.object._movesToward,
objectsLists1, objectsLists2, inverted, tolerance);
};
gdjs.evtTools.object._turnedToward = function(obj1, obj2, tolerance) {
var objAngle = Math.atan2(obj2.getDrawableY()+obj2.getCenterY() - (obj1.getDrawableY()+obj1.getCenterY()),
obj2.getDrawableX()+obj2.getCenterX() - (obj1.getDrawableX()+obj1.getCenterX()));
objAngle *= 180/3.14159;
return Math.abs(gdjs.evtTools.common.angleDifference(obj1.getAngle(), objAngle)) <= tolerance/2;
};
gdjs.evtTools.object.turnedTowardTest = function(objectsLists1, objectsLists2, tolerance, inverted) {
return gdjs.evtTools.object.twoListsTest(gdjs.evtTools.object._turnedToward,
objectsLists1, objectsLists2, inverted, tolerance);
};
gdjs.evtTools.object.pickAllObjects = function(objectsContext, objectsLists) {
for (var name in objectsLists.items) {
if (objectsLists.items.hasOwnProperty(name)) {
var allObjects = objectsContext.getObjects(name);
var objectsList = objectsLists.items[name];
objectsList.length = 0;
objectsList.push.apply(objectsList, allObjects);
}
}
return true;
};
gdjs.evtTools.object.pickRandomObject = function(runtimeScene, objectsLists) {
// Compute one many objects we have
var objectsCount = 0;
for (var listName in objectsLists.items) {
if (objectsLists.items.hasOwnProperty(listName)) {
var list = objectsLists.items[listName];
objectsCount += list.length;
}
}
if (objectsCount === 0)
return false;
// Pick one random object
var index = Math.floor(Math.random()*objectsCount);
if (index >= objectsCount) index = objectsCount-1; //Should never happen.
// Find the object
var startIndex = 0;
var theChosenOne = null;
for (var listName in objectsLists.items) {
if (objectsLists.items.hasOwnProperty(listName)) {
var list = objectsLists.items[listName];
if (index - startIndex < list.length) {
theChosenOne = list[index - startIndex];
break;
}
startIndex += list.length;
}
}
gdjs.evtTools.object.pickOnly(objectsLists, theChosenOne);
return true;
};
gdjs.evtTools.object.pickNearestObject = function(objectsLists, x, y, inverted) {
var bestObject = null;
var best = 0;
var first = true;
var lists = gdjs.staticArray(gdjs.evtTools.object.pickNearestObject);
objectsLists.values(lists);
for(var i = 0, len = lists.length;i<len;++i) {
var list = lists[i];
for(var j = 0;j < list.length;++j) {
var object = list[j];
var distance = object.getSqDistanceTo(x, y);
if( first || (distance < best ^ inverted)) {
best = distance;
bestObject = object;
}
first = false;
}
}
if (!bestObject)
return false;
gdjs.evtTools.object.pickOnly(objectsLists, bestObject);
return true;
};
gdjs.evtTools.object.raycastObject = function(objectsLists, x, y, angle, dist, varX, varY, inverted) {
return gdjs.evtTools.object.raycastObjectToPosition(
objectsLists,
x, y,
x + dist*Math.cos(angle*Math.PI/180.0),
y + dist*Math.sin(angle*Math.PI/180.0),
varX, varY, inverted);
};
gdjs.evtTools.object.raycastObjectToPosition = function(objectsLists, x, y, endX, endY, varX, varY, inverted) {
var matchObject = null;
var testSqDist = inverted ? 0 : (endX - x)*(endX - x) + (endY - y)*(endY - y);
var resultX = 0;
var resultY = 0;
var lists = gdjs.staticArray(gdjs.evtTools.object.raycastObjectToPosition);
objectsLists.values(lists);
for (var i = 0; i < lists.length; i++) {
var list = lists[i];
for (var j = 0; j < list.length; j++) {
var object = list[j];
var result = object.raycastTest(x, y, endX, endY, !inverted);
if( result.collision ) {
if ( !inverted && (result.closeSqDist <= testSqDist) ) {
testSqDist = result.closeSqDist;
matchObject = object;
resultX = result.closeX;
resultY = result.closeY;
}
else if ( inverted && (result.farSqDist >= testSqDist) ) {
testSqDist = result.farSqDist;
matchObject = object;
resultX = result.farX;
resultY = result.farY;
}
}
}
}
if ( !matchObject )
return false;
gdjs.evtTools.object.pickOnly(objectsLists, matchObject);
varX.setNumber(resultX);
varY.setNumber(resultY);
return true;
};
/**
* Do the work of creating a new object
* @private
*/
gdjs.evtTools.object.doCreateObjectOnScene = function(objectsContext, objectName, objectsLists, x, y, layer) {
// objectsContext will either be the gdjs.RuntimeScene or, in an events function, the
// eventsFunctionContext. We can't directly use runtimeScene because the object name could
// be different than the real object name (this is the case in a function. The eventsFunctionContext
// will take care of this in createObject).
var obj = objectsContext.createObject(objectName);
if ( obj !== null ) {
//Do some extra setup
obj.setPosition(x,y);
obj.setLayer(layer);
//Let the new object be picked by next actions/conditions.
if ( objectsLists.containsKey(objectName) ) {
objectsLists.get(objectName).push(obj);
}
}
};
/**
* Allows events to create a new object on a scene.
* @private
*/
gdjs.evtTools.object.createObjectOnScene = function(objectsContext, objectsLists, x, y, layer) {
gdjs.evtTools.object.doCreateObjectOnScene(objectsContext, objectsLists.firstKey(), objectsLists, x, y, layer);
};
/**
* Allows events to create a new object on a scene.
* @private
*/
gdjs.evtTools.object.createObjectFromGroupOnScene = function(objectsContext, objectsLists, objectName, x, y, layer) {
gdjs.evtTools.object.doCreateObjectOnScene(objectsContext, objectName, objectsLists, x, y, layer);
};
/**
* Allows events to get the number of objects picked.
* @private
*/
gdjs.evtTools.object.pickedObjectsCount = function(objectsLists) {
var size = 0;
var lists = gdjs.staticArray(gdjs.evtTools.object.pickedObjectsCount);
objectsLists.values(lists);
for(var i = 0, len = lists.length;i<len;++i) {
size += lists[i].length;
}
return size;
};

View File

@ -0,0 +1,163 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Tools related to runtime scene, for events generated code.
* @memberof gdjs.evtTools
* @class runtimeScene
* @static
* @private
*/
gdjs.evtTools.runtimeScene = gdjs.evtTools.runtimeScene || {};
gdjs.evtTools.runtimeScene.sceneJustBegins = function(runtimeScene) {
return runtimeScene.getTimeManager().isFirstFrame();
};
gdjs.evtTools.runtimeScene.sceneJustResumed = function(runtimeScene) {
return runtimeScene.sceneJustResumed();
};
gdjs.evtTools.runtimeScene.getSceneName = function(runtimeScene) {
return runtimeScene.getName();
};
gdjs.evtTools.runtimeScene.setBackgroundColor = function(runtimeScene, rgbColor) {
var colors = rgbColor.split(";");
if ( colors.length < 3 ) return;
runtimeScene.setBackgroundColor(parseInt(colors[0]),
parseInt(colors[1]),
parseInt(colors[2]));
};
gdjs.evtTools.runtimeScene.getElapsedTimeInSeconds = function(runtimeScene) {
return runtimeScene.getTimeManager().getElapsedTime() / 1000;
};
gdjs.evtTools.runtimeScene.setTimeScale = function(runtimeScene, timeScale) {
return runtimeScene.getTimeManager().setTimeScale(timeScale);
};
gdjs.evtTools.runtimeScene.getTimeScale = function(runtimeScene) {
return runtimeScene.getTimeManager().getTimeScale();
};
gdjs.evtTools.runtimeScene.timerElapsedTime = function(runtimeScene, timeInSeconds, timerName) {
var timeManager = runtimeScene.getTimeManager();
if ( !timeManager.hasTimer(timerName) ) {
timeManager.addTimer(timerName);
return false;
}
return timeManager.getTimer(timerName).getTime() / 1000 >= timeInSeconds;
};
gdjs.evtTools.runtimeScene.timerPaused = function(runtimeScene, timerName) {
var timeManager = runtimeScene.getTimeManager();
if ( !timeManager.hasTimer(timerName) ) return false;
return timeManager.getTimer(timerName).isPaused();
};
gdjs.evtTools.runtimeScene.resetTimer = function(runtimeScene, timerName) {
var timeManager = runtimeScene.getTimeManager();
if ( !timeManager.hasTimer(timerName) )
timeManager.addTimer(timerName);
else
timeManager.getTimer(timerName).reset();
};
gdjs.evtTools.runtimeScene.pauseTimer = function(runtimeScene, timerName) {
var timeManager = runtimeScene.getTimeManager();
if ( !timeManager.hasTimer(timerName) ) timeManager.addTimer(timerName);
timeManager.getTimer(timerName).setPaused(true);
};
gdjs.evtTools.runtimeScene.unpauseTimer = function(runtimeScene, timerName) {
var timeManager = runtimeScene.getTimeManager();
if ( !timeManager.hasTimer(timerName) ) timeManager.addTimer(timerName);
return timeManager.getTimer(timerName).setPaused(false);
};
gdjs.evtTools.runtimeScene.removeTimer = function(runtimeScene, timerName) {
var timeManager = runtimeScene.getTimeManager();
timeManager.removeTimer(timerName);
};
gdjs.evtTools.runtimeScene.getTimerElapsedTimeInSeconds = function(runtimeScene, timerName) {
var timeManager = runtimeScene.getTimeManager();
if (!timeManager.hasTimer(timerName)) return 0;
return timeManager.getTimer(timerName).getTime() / 1000;
};
gdjs.evtTools.runtimeScene.getTimeFromStartInSeconds = function(runtimeScene) {
return runtimeScene.getTimeManager().getTimeFromStart() / 1000;
};
gdjs.evtTools.runtimeScene.getTime = function(runtimeScene, what) {
if ( what === "timestamp" ) {
return Date.now();
}
var now = new Date();
if ( what === "hour" )
return now.getHours();
else if ( what === "min" )
return now.getMinutes();
else if ( what === "sec" )
return now.getSeconds();
else if ( what === "mday" )
return now.getDate();
else if ( what === "mon" )
return now.getMonth();
else if ( what === "year" )
return now.getFullYear() - 1900; //Conform to the C way of returning years.
else if ( what === "wday" )
return now.getDay();
else if ( what === "yday" ) {
var start = new Date(now.getFullYear(), 0, 0);
var diff = now - start;
var oneDay = 1000 * 60 * 60 * 24;
return Math.floor(diff / oneDay);
}
return 0;
};
gdjs.evtTools.runtimeScene.replaceScene = function(runtimeScene, newSceneName, clearOthers) {
if (!runtimeScene.getGame().getSceneData(newSceneName)) return;
runtimeScene.requestChange(clearOthers ?
gdjs.RuntimeScene.CLEAR_SCENES :
gdjs.RuntimeScene.REPLACE_SCENE, newSceneName);
};
gdjs.evtTools.runtimeScene.pushScene = function(runtimeScene, newSceneName) {
if (!runtimeScene.getGame().getSceneData(newSceneName)) return;
runtimeScene.requestChange(gdjs.RuntimeScene.PUSH_SCENE, newSceneName);
};
gdjs.evtTools.runtimeScene.popScene = function(runtimeScene) {
runtimeScene.requestChange(gdjs.RuntimeScene.POP_SCENE);
};
gdjs.evtTools.runtimeScene.stopGame = function(runtimeScene) {
runtimeScene.requestChange(gdjs.RuntimeScene.STOP_GAME);
};
gdjs.evtTools.runtimeScene.createObjectsFromExternalLayout = function(scene, externalLayout, xPos, yPos) {
var externalLayoutData = scene.getGame().getExternalLayoutData(externalLayout);
if ( externalLayoutData === null ) return;
scene.createObjectsFrom(externalLayoutData.instances, xPos, yPos);
};

View File

@ -0,0 +1,163 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Class used by events to interact with the soundManager.
*
* @memberof gdjs.evtTools
* @class sound
* @static
* @private
*/
gdjs.evtTools.sound = gdjs.evtTools.sound || {};
gdjs.evtTools.sound.getGlobalVolume = function(runtimeScene) {
return runtimeScene.getSoundManager().getGlobalVolume();
};
gdjs.evtTools.sound.setGlobalVolume = function(runtimeScene, globalVolume) {
runtimeScene.getSoundManager().setGlobalVolume(globalVolume);
};
//Sounds:
gdjs.evtTools.sound.playSound = function(runtimeScene, soundFile, loop, volume, pitch) {
runtimeScene.getSoundManager().playSound(soundFile, loop, volume, pitch);
};
gdjs.evtTools.sound.playSoundOnChannel = function(runtimeScene, soundFile, channel, loop, volume, pitch) {
runtimeScene.getSoundManager().playSoundOnChannel(soundFile, channel, loop, volume, pitch);
};
gdjs.evtTools.sound.stopSoundOnChannel = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
sound && sound.stop();
};
gdjs.evtTools.sound.pauseSoundOnChannel = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
sound && sound.pause();
};
gdjs.evtTools.sound.continueSoundOnChannel = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
if (sound && !sound.playing()) sound.play();
};
gdjs.evtTools.sound.isSoundOnChannelPlaying = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
return sound ? sound.playing() : false;
};
gdjs.evtTools.sound.isSoundOnChannelPaused = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
return sound ? sound.paused() : false;
};
gdjs.evtTools.sound.isSoundOnChannelStopped = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
return sound ? sound.stopped() : true;
};
gdjs.evtTools.sound.getSoundOnChannelVolume = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
return sound ? sound.volume() * 100 : 100;
};
gdjs.evtTools.sound.setSoundOnChannelVolume = function(runtimeScene, channel, volume) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
sound && sound.volume(volume / 100);
};
gdjs.evtTools.sound.getSoundOnChannelPlayingOffset = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
return sound ? sound.seek() : 0;
};
gdjs.evtTools.sound.setSoundOnChannelPlayingOffset = function(runtimeScene, channel, playingOffset) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
sound && sound.seek(playingOffset);
};
gdjs.evtTools.sound.getSoundOnChannelPitch = function(runtimeScene, channel) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
return sound ? sound.getRate() : 1;
};
gdjs.evtTools.sound.setSoundOnChannelPitch = function(runtimeScene, channel, pitch) {
var sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
sound && sound.setRate(pitch);
};
//Musics:
gdjs.evtTools.sound.playMusic = function(runtimeScene, soundFile, loop, volume, pitch) {
runtimeScene.getSoundManager().playMusic(soundFile, loop, volume, pitch);
};
gdjs.evtTools.sound.playMusicOnChannel = function(runtimeScene, soundFile, channel, loop, volume, pitch) {
runtimeScene.getSoundManager().playMusicOnChannel(soundFile, channel, loop, volume, pitch);
};
gdjs.evtTools.sound.stopMusicOnChannel = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
music && music.stop();
};
gdjs.evtTools.sound.pauseMusicOnChannel = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
music && music.pause();
};
gdjs.evtTools.sound.continueMusicOnChannel = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
if (music && !music.playing()) music.play();
};
gdjs.evtTools.sound.isMusicOnChannelPlaying = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
return music ? music.playing() : false;
};
gdjs.evtTools.sound.isMusicOnChannelPaused = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
return music ? music.paused() : false;
};
gdjs.evtTools.sound.isMusicOnChannelStopped = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
return music ? music.stopped() : true;
};
gdjs.evtTools.sound.getMusicOnChannelVolume = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
return music ? music.volume() * 100 : 100;
};
gdjs.evtTools.sound.setMusicOnChannelVolume = function(runtimeScene, channel, volume) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
music && music.volume(volume / 100);
};
gdjs.evtTools.sound.getMusicOnChannelPlayingOffset = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
return music ? music.seek() : 0;
};
gdjs.evtTools.sound.setMusicOnChannelPlayingOffset = function(runtimeScene, channel, playingOffset) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
music && music.seek(playingOffset);
};
gdjs.evtTools.sound.getMusicOnChannelPitch = function(runtimeScene, channel) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
return music ? music.getRate() : 1;
};
gdjs.evtTools.sound.setMusicOnChannelPitch = function(runtimeScene, channel, pitch) {
var music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
music && music.setRate(pitch);
};

View File

@ -0,0 +1,254 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Tools related to storage, for events generated code.
*
* @memberof gdjs.evtTools
* @namespace storage
* @private
*/
gdjs.evtTools.storage = gdjs.evtTools.storage || {
loadedFiles: new Hashtable(),
localStorage: typeof cc !== 'undefined' ? cc.sys.localStorage : localStorage,
fileUtils: null //Disabled for now
};
/**
* Load into memory a JSON object stored in the local storage object
* provided by the browser.
* The JSON object is named GDJS_filename in the localStorage object.
*
* @param filename {String} The name of the JSON object
*/
gdjs.evtTools.storage.loadJSONFileFromStorage = function(filename) {
if ( gdjs.evtTools.storage.loadedFiles.containsKey(filename) )
return; //Already loaded.
var rawStr = null;
if (gdjs.evtTools.storage.fileUtils) {
var fileUtils = gdjs.evtTools.storage.fileUtils;
var fullPath = jsb.fileUtils.getWritablePath() + filename;
if (jsb.fileUtils.isFileExist(fullPath)) {
rawStr = jsb.fileUtils.getStringFromFile(fullPath);
} else {
console.log('File "' + filename + '" does not exist.');
}
} else {
var localStorage = gdjs.evtTools.storage.localStorage;
rawStr = localStorage.getItem("GDJS_"+filename);
}
try {
if ( rawStr !== null )
gdjs.evtTools.storage.loadedFiles.put(filename, JSON.parse(rawStr));
else
gdjs.evtTools.storage.loadedFiles.put(filename, {});
}
catch(e) {
console.log('Unable to load data from "' + filename + '"!');
gdjs.evtTools.storage.loadedFiles.put(filename, {});
}
};
/**
* Unload from memory a JSON object, which is then stored in the local storage
* object provided by the browser.
* The JSON object is named GDJS_filename in the localStorage object.
*
* @param filename {String} The name of the JSON object
*/
gdjs.evtTools.storage.unloadJSONFile = function(filename) {
if ( !gdjs.evtTools.storage.loadedFiles.containsKey(filename) )
return; //Not loaded.
var jsonObject = gdjs.evtTools.storage.loadedFiles.get(filename);
var rawStr = JSON.stringify(jsonObject);
if (gdjs.evtTools.storage.fileUtils) {
var fileUtils = gdjs.evtTools.storage.fileUtils;
var fullPath = jsb.fileUtils.getWritablePath() + filename;
if (!jsb.fileUtils.writeToFile(rawStr, fullPath)) {
console.log('Unable to save data to file "' + filename + '"!');
}
} else {
var localStorage = gdjs.evtTools.storage.localStorage;
try {
localStorage.setItem("GDJS_"+filename, rawStr);
} catch(e) {
//TODO: Handle storage error.
console.log('Unable to save data to localStorage for "' + filename + '"!');
}
}
gdjs.evtTools.storage.loadedFiles.remove(filename);
};
gdjs.evtTools.storage.clearJSONFile = function(filename) {
var notPermanentlyLoaded = false;
if ( !gdjs.evtTools.storage.loadedFiles.containsKey(filename) ) {
notPermanentlyLoaded = true;
gdjs.evtTools.storage.loadJSONFileFromStorage(filename);
}
var JSONobject = gdjs.evtTools.storage.loadedFiles.get(filename);
for ( var p in JSONobject ) {
if ( JSONobject.hasOwnProperty(p) )
delete JSONobject[p];
}
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return true;
};
gdjs.evtTools.storage.elementExistsInJSONFile = function(filename, element) {
var notPermanentlyLoaded = false;
if ( !gdjs.evtTools.storage.loadedFiles.containsKey(filename) ) {
notPermanentlyLoaded = true;
gdjs.evtTools.storage.loadJSONFileFromStorage(filename);
}
var elemArray = element.split("/");
var currentElem = gdjs.evtTools.storage.loadedFiles.get(filename);
for (var i =0;i<elemArray.length;++i) {
if ( !currentElem[elemArray[i]] ) {
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return false;
}
currentElem = currentElem[elemArray[i]];
}
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return true;
};
gdjs.evtTools.storage.deleteElementFromJSONFile = function(filename, element) {
var notPermanentlyLoaded = false;
if ( !gdjs.evtTools.storage.loadedFiles.containsKey(filename) ) {
notPermanentlyLoaded = true;
gdjs.evtTools.storage.loadJSONFileFromStorage(filename);
}
var elemArray = element.split("/");
var currentElem = gdjs.evtTools.storage.loadedFiles.get(filename);
for (var i =0;i<elemArray.length;++i) {
if ( !currentElem[elemArray[i]] ) {
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return false;
}
if ( i == elemArray.length-1)
delete currentElem[elemArray[i]];
else
currentElem = currentElem[elemArray[i]];
}
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return true;
};
gdjs.evtTools.storage.writeNumberInJSONFile = function(filename, element, val) {
var notPermanentlyLoaded = false;
if ( !gdjs.evtTools.storage.loadedFiles.containsKey(filename) ) {
notPermanentlyLoaded = true;
gdjs.evtTools.storage.loadJSONFileFromStorage(filename);
}
var elemArray = element.split("/");
var currentElem = gdjs.evtTools.storage.loadedFiles.get(filename);
for (var i =0;i<elemArray.length;++i) {
if ( !currentElem[elemArray[i]] ) currentElem[elemArray[i]] = {};
if ( i == elemArray.length-1)
currentElem[elemArray[i]].value = val;
else
currentElem = currentElem[elemArray[i]];
}
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return true;
};
gdjs.evtTools.storage.writeStringInJSONFile = function(filename, element, str) {
var notPermanentlyLoaded = false;
if ( !gdjs.evtTools.storage.loadedFiles.containsKey(filename) ) {
notPermanentlyLoaded = true;
gdjs.evtTools.storage.loadJSONFileFromStorage(filename);
}
var elemArray = element.split("/");
var currentElem = gdjs.evtTools.storage.loadedFiles.get(filename);
for (var i =0;i<elemArray.length;++i) {
if ( !currentElem[elemArray[i]] ) currentElem[elemArray[i]] = {};
if ( i == elemArray.length-1)
currentElem[elemArray[i]].str = str;
else
currentElem = currentElem[elemArray[i]];
}
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return true;
};
gdjs.evtTools.storage.readNumberFromJSONFile = function(filename, element, runtimeScene, variable) {
var notPermanentlyLoaded = false;
if ( !gdjs.evtTools.storage.loadedFiles.containsKey(filename) ) {
notPermanentlyLoaded = true;
gdjs.evtTools.storage.loadJSONFileFromStorage(filename);
}
var elemArray = element.split("/");
var currentElem = gdjs.evtTools.storage.loadedFiles.get(filename);
for (var i =0;i<elemArray.length;++i) {
if ( !currentElem[elemArray[i]] ) {
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return false;
}
if ( i == elemArray.length-1 && typeof currentElem[elemArray[i]].value !== "undefined")
variable.setNumber(currentElem[elemArray[i]].value);
else
currentElem = currentElem[elemArray[i]];
}
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return true;
};
gdjs.evtTools.storage.readStringFromJSONFile = function(filename, element, runtimeScene, variable) {
var notPermanentlyLoaded = false;
if ( !gdjs.evtTools.storage.loadedFiles.containsKey(filename) ) {
notPermanentlyLoaded = true;
gdjs.evtTools.storage.loadJSONFileFromStorage(filename);
}
var elemArray = element.split("/");
var currentElem = gdjs.evtTools.storage.loadedFiles.get(filename);
for (var i =0;i<elemArray.length;++i) {
if ( !currentElem[elemArray[i]] ) {
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return false;
}
if ( i == elemArray.length-1 && typeof currentElem[elemArray[i]].str !== "undefined")
variable.setString(currentElem[elemArray[i]].str);
else
currentElem = currentElem[elemArray[i]];
}
if ( notPermanentlyLoaded ) gdjs.evtTools.storage.unloadJSONFile(filename);
return true;
};

View File

@ -0,0 +1,120 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Tools related to strings manipulation, for events generated code.
*
* @memberof gdjs.evtTools
* @namespace string
* @private
*/
gdjs.evtTools.string = gdjs.evtTools.string || {};
/**
* Return a string containing a new line character.
* @private
*/
gdjs.evtTools.string.newLine = function() {
return "\n";
};
/**
* Return a character from its codepoint.
* @private
*/
gdjs.evtTools.string.fromCodePoint = function(codePoint) {
return String.fromCodePoint(codePoint);
};
/**
* Return the uppercased version of the string.
* @private
*/
gdjs.evtTools.string.toUpperCase = function(str) {
return str.toUpperCase();
};
/**
* Return the lowercased version of the string.
* @private
*/
gdjs.evtTools.string.toLowerCase = function(str) {
return str.toLowerCase()
};
/**
* Return a new string containing the substring of the original string.
* @private
*/
gdjs.evtTools.string.subStr = function(str, start, len) {
if ( start < str.length && start >= 0 )
return str.substr(start, len);
return "";
};
/**
* Return a new string containing the character at the specified position.
* @private
*/
gdjs.evtTools.string.strAt = function(str, start) {
if ( start < str.length && start >= 0 )
return str.substr(start, 1);
return "";
};
/**
* Return the string repeated.
* @private
*/
gdjs.evtTools.string.strRepeat = function(str, count) {
var result = "";
for ( var i = 0; i < count; i++ )
result += str;
return result;
}
/**
* Return the length of the string
* @private
*/
gdjs.evtTools.string.strLen = function(str) {
return str.length;
};
/**
* Search in a string
* @private
*/
gdjs.evtTools.string.strFind = function(str, what) {
return str.indexOf(what);
};
/**
* Reverse search in a string
* @private
*/
gdjs.evtTools.string.strRFind = function(str, what) {
return str.lastIndexOf(what);
};
/**
* Search in a string, starting from a specified position.
* @private
*/
gdjs.evtTools.string.strFindFrom = function(str, what, pos) {
return str.indexOf(what, pos);
};
/**
* Reverse search in a string, starting from a specified position.
* @private
*/
gdjs.evtTools.string.strRFindFrom = function(str, what, pos) {
return str.lastIndexOf(what, pos);
};

View File

@ -0,0 +1,80 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Tools related to window, for events generated code.
* @memberof gdjs.evtTools
* @class window
* @static
* @private
*/
gdjs.evtTools.window = gdjs.evtTools.window || {};
gdjs.evtTools.window.setMargins = function(runtimeScene, top, right, bottom, left) {
runtimeScene.getGame().getRenderer().setMargins(top, right, bottom, left);
};
gdjs.evtTools.window.setFullScreen = function(runtimeScene, enable, keepAspectRatio) {
runtimeScene.getGame().getRenderer().keepAspectRatio(keepAspectRatio);
runtimeScene.getGame().getRenderer().setFullScreen(enable);
};
gdjs.evtTools.window.setWindowSize = function(runtimeScene, width, height, updateGameResolution) {
runtimeScene.getGame().getRenderer().setWindowSize(width, height);
if (updateGameResolution) {
runtimeScene.getGame().setGameResolutionSize(width, height);
}
};
gdjs.evtTools.window.centerWindow = function(runtimeScene) {
runtimeScene.getGame().getRenderer().centerWindow();
};
gdjs.evtTools.window.setGameResolutionSize = function(runtimeScene, width, height) {
runtimeScene.getGame().setGameResolutionSize(width, height);
};
gdjs.evtTools.window.setGameResolutionResizeMode = function(runtimeScene, resizeMode) {
runtimeScene.getGame().setGameResolutionResizeMode(resizeMode);
};
gdjs.evtTools.window.setAdaptGameResolutionAtRuntime = function(runtimeScene, enable) {
runtimeScene.getGame().setAdaptGameResolutionAtRuntime(enable);
};
gdjs.evtTools.window.setWindowTitle = function(runtimeScene, title) {
runtimeScene.getGame().getRenderer().setWindowTitle(title);
};
gdjs.evtTools.window.getWindowTitle = function(runtimeScene) {
runtimeScene.getGame().getRenderer().getWindowTitle();
};
gdjs.evtTools.window.getWindowInnerWidth = function() {
if (gdjs.RuntimeGameRenderer && gdjs.RuntimeGameRenderer.getWindowInnerWidth)
return gdjs.RuntimeGameRenderer.getWindowInnerWidth();
return (typeof window !== "undefined") ? window.innerWidth : 800;
};
gdjs.evtTools.window.getWindowInnerHeight = function() {
if (gdjs.RuntimeGameRenderer && gdjs.RuntimeGameRenderer.getWindowInnerHeight)
return gdjs.RuntimeGameRenderer.getWindowInnerHeight();
return (typeof window !== "undefined") ? window.innerHeight : 800;
};
gdjs.evtTools.window.getGameResolutionWidth = function(runtimeScene) {
return runtimeScene.getGame().getGameResolutionWidth();
};
gdjs.evtTools.window.getGameResolutionHeight = function(runtimeScene) {
return runtimeScene.getGame().getGameResolutionHeight();
};
gdjs.evtTools.window.openURL = function(url, runtimeScene) {
return runtimeScene.getGame().getRenderer().openURL(url);
};

View File

@ -0,0 +1,128 @@
/*
* GDevelop JS Platform
* Copyright 2013-present Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* FontFaceObserverFontManager loads fonts (using fontfaceobserver library)
* from the game resources (see `loadFonts`), and allow to access to
* the font families of the loaded fonts during the game (see `getFontFamily`).
*
* "@font-face" declarations must be have been added separately in the index.html
* (or any CSS file).
*
* @class FontFaceObserverFontManager
* @memberof gdjs
* @param {Object} resources The resources data of the game.
*/
gdjs.FontFaceObserverFontManager = function(resources)
{
this._resources = resources;
this._loadedFontFamily = {}; // Associate font resource names to the loaded font family
this._loadedFonts = {}; // Associate font resource names to the resources, for faster access
};
gdjs.FontManager = gdjs.FontFaceObserverFontManager; //Register the class to let the engine use it.
/**
* Return the font family associated to the specified font resource name.
* The font resource must have been loaded before. If that's not the case,
* a font family will be returned but without guarantee of it being loaded (to
* keep compatibility with GDevelop 5.0-beta56 and previous).
*
* @param {string} resourceName The name of the resource to get.
* @returns {string} The font family to be used for this font resource,
* or "Arial" if `resourceName` is empty.
*/
gdjs.FontFaceObserverFontManager.prototype.getFontFamily = function(resourceName) {
if (this._loadedFontFamily[resourceName]) {
return this._loadedFontFamily[resourceName];
}
return resourceName ?
gdjs.FontFaceObserverFontManager._getFontFamilyFromFilename(resourceName) :
'Arial';
}
/**
* Return the font file associated to the specified font resource name.
* The font resource must have been loaded before. If that's not the case,
* the resource name will be returned (to
* keep compatibility with GDevelop 5.0-beta56 and previous).
*
* Should only be useful for renderers running on a non HTML5/non browser environment.
*
* @param {string} resourceName The name of the resource to get.
* @returns {string} The file of the font resource.
*/
gdjs.FontFaceObserverFontManager.prototype.getFontFile = function(resourceName) {
if (this._loadedFonts[resourceName]) {
return this._loadedFonts[resourceName].file || '';
}
return resourceName;
}
/**
* Return the font family for a given filename.
* Should be kept in sync with the declaration of "@font-face" during exports.
*
* @private
* @param {string} filename The filename of the font
* @returns {string} The font family to be used for this font resource.
*/
gdjs.FontFaceObserverFontManager._getFontFamilyFromFilename = function(filename) {
return "gdjs_font_" + filename;
}
/**
* Load the specified resources, so that fonts are loaded and can then be
* used by using the font family returned by getFontFamily.
* @param onProgress Callback called each time a new file is loaded.
* @param onComplete Callback called when loading is done.
* @param resources The resources to be loaded. If not specified, will load the resources
* specified in the FontFaceObserverFontManager constructor.
*/
gdjs.FontFaceObserverFontManager.prototype.loadFonts = function(onProgress, onComplete, resources) {
resources = resources || this._resources;
//Construct the list of files to be loaded.
//For one loaded file, it can have one or more resources
//that use it.
var filesResources = {};
for(var i = 0, len = resources.length;i<len;++i) {
var res = resources[i];
if ( res.file && res.kind === "font" ) {
filesResources[res.file] = filesResources[res.file] ? filesResources[res.file].concat(res) : [res];
}
}
var totalCount = Object.keys(filesResources).length;
if (totalCount === 0)
return onComplete(totalCount); //Nothing to load.
var loadingCount = 0;
var that = this;
var onFontLoaded = function(fontFamily, resources) {
resources.forEach(function(resource) {
that._loadedFontFamily[resource.name] = fontFamily;
that._loadedFonts[resource.name] = resource;
});
loadingCount++;
onProgress(loadingCount, totalCount);
if (loadingCount === totalCount) onComplete(totalCount);
}
Object.keys(filesResources).forEach(function(file) {
var fontFamily = gdjs.FontFaceObserverFontManager._getFontFamilyFromFilename(file);
var resources = filesResources[file];
new FontFaceObserver(fontFamily).load().then(function() {
onFontLoaded(fontFamily, resources);
}, function() {
console.error("Error loading font resource \"" + resources[0].name + "\" (file: " + file + ")");
onFontLoaded(fontFamily, resources);
});
});
}

View File

@ -0,0 +1,16 @@
(function() {
var module; //Define an undefined module variable to avoid fontfaceobserver thinking it's used in an environment using require.
/* Font Face Observer v2.0.13 - © Bram Stein. License: BSD-3-Clause */(function(){'use strict';var f,g=[];function l(a){g.push(a);1==g.length&&f()}function m(){for(;g.length;)g[0](),g.shift()}f=function(){setTimeout(m)};function n(a){this.a=p;this.b=void 0;this.f=[];var b=this;try{a(function(a){q(b,a)},function(a){r(b,a)})}catch(c){r(b,c)}}var p=2;function t(a){return new n(function(b,c){c(a)})}function u(a){return new n(function(b){b(a)})}function q(a,b){if(a.a==p){if(b==a)throw new TypeError;var c=!1;try{var d=b&&b.then;if(null!=b&&"object"==typeof b&&"function"==typeof d){d.call(b,function(b){c||q(a,b);c=!0},function(b){c||r(a,b);c=!0});return}}catch(e){c||r(a,e);return}a.a=0;a.b=b;v(a)}}
function r(a,b){if(a.a==p){if(b==a)throw new TypeError;a.a=1;a.b=b;v(a)}}function v(a){l(function(){if(a.a!=p)for(;a.f.length;){var b=a.f.shift(),c=b[0],d=b[1],e=b[2],b=b[3];try{0==a.a?"function"==typeof c?e(c.call(void 0,a.b)):e(a.b):1==a.a&&("function"==typeof d?e(d.call(void 0,a.b)):b(a.b))}catch(h){b(h)}}})}n.prototype.g=function(a){return this.c(void 0,a)};n.prototype.c=function(a,b){var c=this;return new n(function(d,e){c.f.push([a,b,d,e]);v(c)})};
function w(a){return new n(function(b,c){function d(c){return function(d){h[c]=d;e+=1;e==a.length&&b(h)}}var e=0,h=[];0==a.length&&b(h);for(var k=0;k<a.length;k+=1)u(a[k]).c(d(k),c)})}function x(a){return new n(function(b,c){for(var d=0;d<a.length;d+=1)u(a[d]).c(b,c)})};window.Promise||(window.Promise=n,window.Promise.resolve=u,window.Promise.reject=t,window.Promise.race=x,window.Promise.all=w,window.Promise.prototype.then=n.prototype.c,window.Promise.prototype["catch"]=n.prototype.g);}());
(function(){function l(a,b){document.addEventListener?a.addEventListener("scroll",b,!1):a.attachEvent("scroll",b)}function m(a){document.body?a():document.addEventListener?document.addEventListener("DOMContentLoaded",function c(){document.removeEventListener("DOMContentLoaded",c);a()}):document.attachEvent("onreadystatechange",function k(){if("interactive"==document.readyState||"complete"==document.readyState)document.detachEvent("onreadystatechange",k),a()})};function r(a){this.a=document.createElement("div");this.a.setAttribute("aria-hidden","true");this.a.appendChild(document.createTextNode(a));this.b=document.createElement("span");this.c=document.createElement("span");this.h=document.createElement("span");this.f=document.createElement("span");this.g=-1;this.b.style.cssText="max-width:none;display:inline-block;position:absolute;height:100%;width:100%;overflow:scroll;font-size:16px;";this.c.style.cssText="max-width:none;display:inline-block;position:absolute;height:100%;width:100%;overflow:scroll;font-size:16px;";
this.f.style.cssText="max-width:none;display:inline-block;position:absolute;height:100%;width:100%;overflow:scroll;font-size:16px;";this.h.style.cssText="display:inline-block;width:200%;height:200%;font-size:16px;max-width:none;";this.b.appendChild(this.h);this.c.appendChild(this.f);this.a.appendChild(this.b);this.a.appendChild(this.c)}
function t(a,b){a.a.style.cssText="max-width:none;min-width:20px;min-height:20px;display:inline-block;overflow:hidden;position:absolute;width:auto;margin:0;padding:0;top:-999px;white-space:nowrap;font-synthesis:none;font:"+b+";"}function y(a){var b=a.a.offsetWidth,c=b+100;a.f.style.width=c+"px";a.c.scrollLeft=c;a.b.scrollLeft=a.b.scrollWidth+100;return a.g!==b?(a.g=b,!0):!1}function z(a,b){function c(){var a=k;y(a)&&a.a.parentNode&&b(a.g)}var k=a;l(a.b,c);l(a.c,c);y(a)};function A(a,b){var c=b||{};this.family=a;this.style=c.style||"normal";this.weight=c.weight||"normal";this.stretch=c.stretch||"normal"}var B=null,C=null,E=null,F=null;function G(){if(null===C)if(J()&&/Apple/.test(window.navigator.vendor)){var a=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))(?:\.([0-9]+))/.exec(window.navigator.userAgent);C=!!a&&603>parseInt(a[1],10)}else C=!1;return C}function J(){null===F&&(F=!!document.fonts);return F}
function K(){if(null===E){var a=document.createElement("div");try{a.style.font="condensed 100px sans-serif"}catch(b){}E=""!==a.style.font}return E}function L(a,b){return[a.style,a.weight,K()?a.stretch:"","100px",b].join(" ")}
A.prototype.load=function(a,b){var c=this,k=a||"BESbswy",q=0,D=b||3E3,H=(new Date).getTime();return new Promise(function(a,b){if(J()&&!G()){var M=new Promise(function(a,b){function e(){(new Date).getTime()-H>=D?b():document.fonts.load(L(c,'"'+c.family+'"'),k).then(function(c){1<=c.length?a():setTimeout(e,25)},function(){b()})}e()}),N=new Promise(function(a,c){q=setTimeout(c,D)});Promise.race([N,M]).then(function(){clearTimeout(q);a(c)},function(){b(c)})}else m(function(){function u(){var b;if(b=-1!=
f&&-1!=g||-1!=f&&-1!=h||-1!=g&&-1!=h)(b=f!=g&&f!=h&&g!=h)||(null===B&&(b=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(window.navigator.userAgent),B=!!b&&(536>parseInt(b[1],10)||536===parseInt(b[1],10)&&11>=parseInt(b[2],10))),b=B&&(f==v&&g==v&&h==v||f==w&&g==w&&h==w||f==x&&g==x&&h==x)),b=!b;b&&(d.parentNode&&d.parentNode.removeChild(d),clearTimeout(q),a(c))}function I(){if((new Date).getTime()-H>=D)d.parentNode&&d.parentNode.removeChild(d),b(c);else{var a=document.hidden;if(!0===a||void 0===a)f=e.a.offsetWidth,
g=n.a.offsetWidth,h=p.a.offsetWidth,u();q=setTimeout(I,50)}}var e=new r(k),n=new r(k),p=new r(k),f=-1,g=-1,h=-1,v=-1,w=-1,x=-1,d=document.createElement("div");d.dir="ltr";t(e,L(c,"sans-serif"));t(n,L(c,"serif"));t(p,L(c,"monospace"));d.appendChild(e.a);d.appendChild(n.a);d.appendChild(p.a);document.body.appendChild(d);v=e.a.offsetWidth;w=n.a.offsetWidth;x=p.a.offsetWidth;I();z(e,function(a){f=a;u()});t(e,L(c,'"'+c.family+'",sans-serif'));z(n,function(a){g=a;u()});t(n,L(c,'"'+c.family+'",serif'));
z(p,function(a){h=a;u()});t(p,L(c,'"'+c.family+'",monospace'))})})};"object"===typeof module?module.exports=A:(window.FontFaceObserver=A,window.FontFaceObserver.prototype.load=A.prototype.load);}());
})()

View File

@ -0,0 +1,135 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* A vector used to move objects.
*
* @memberof gdjs
* @class Force
* @param {number} x The initial x component
* @param {number} y The initial y component
* @param {number} multiplier The multiplier (0 for a force that disappear on next frame, 1 for a permanent force)
*/
gdjs.Force = function(x,y, multiplier)
{
this._x = x || 0;
this._y = y || 0;
this._angle = Math.atan2(y,x)*180/Math.PI;
this._length = Math.sqrt(x*x+y*y);
this._dirty = false;
this._multiplier = multiplier;
}
/**
* Returns the X component of the force.
*/
gdjs.Force.prototype.getX = function() {
return this._x;
}
/**
* Returns the Y component of the force.
*/
gdjs.Force.prototype.getY = function() {
return this._y;
}
/**
* Set the x component of the force.
* @param {number} x The new X component
*/
gdjs.Force.prototype.setX = function(x) {
this._x = x;
this._dirty = true;
}
/**
* Set the y component of the force.
* @param {number} y The new Y component
*/
gdjs.Force.prototype.setY = function(y) {
this._y = y;
this._dirty = true;
}
/**
* Set the angle of the force.
* @param {number} angle The new angle
*/
gdjs.Force.prototype.setAngle = function(angle) {
if ( this._dirty ) {
this._length = Math.sqrt(this._x*this._x+this._y*this._y);
this._dirty = false;
}
this._angle = angle;
var angleInRadians = angle/180*Math.PI;
this._x = Math.cos(angleInRadians)*this._length;
this._y = Math.sin(angleInRadians)*this._length;
}
/**
* Set the length of the force.
* @param {number} len The length
*/
gdjs.Force.prototype.setLength = function(len) {
if ( this._dirty ) {
this._angle = Math.atan2(this._y, this._x)*180/Math.PI;
this._dirty = false;
}
this._length = len;
var angleInRadians = this._angle/180*Math.PI;
this._x = Math.cos(angleInRadians)*this._length;
this._y = Math.sin(angleInRadians)*this._length;
}
/**
* Get the angle of the force
*/
gdjs.Force.prototype.getAngle = function() {
if ( this._dirty ) {
this._angle = Math.atan2(this._y, this._x)*180/Math.PI;
this._length = Math.sqrt(this._x*this._x+this._y*this._y);
this._dirty = false;
}
return this._angle;
}
/**
* Get the length of the force
*/
gdjs.Force.prototype.getLength = function() {
if ( this._dirty ) {
this._angle = Math.atan2(this._y, this._x)*180/Math.PI;
this._length = Math.sqrt(this._x*this._x+this._y*this._y);
this._dirty = false;
}
return this._length;
};
/**
* Return 1 (true) if the force is permanent, 0 (false) if it is instant.
* @returns {number}
*/
gdjs.Force.prototype.getMultiplier = function() {
return this._multiplier;
};
/**
* Set if the force multiplier.
* @param {number} multiplier The new value
*/
gdjs.Force.prototype.setMultiplier = function(multiplier) {
this._multiplier = multiplier;
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,379 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* The `gdjs` namespace contains all classes and objects of the game engine.
* @namespace
*/
window.gdjs = {
objectsTypes: new Hashtable(),
behaviorsTypes: new Hashtable(),
/**
* Contains functions used by events (this is a convention only, functions can actually
* by anywhere).
* @namespace
* @memberOf gdjs
*/
evtTools: {},
callbacksFirstRuntimeSceneLoaded: [],
callbacksRuntimeSceneLoaded: [],
callbacksRuntimeScenePreEvents: [],
callbacksRuntimeScenePostEvents: [],
callbacksRuntimeScenePaused: [],
callbacksRuntimeSceneResumed: [],
callbacksRuntimeSceneUnloading: [],
callbacksRuntimeSceneUnloaded: [],
callbacksObjectDeletedFromScene: [],
};
/**
* Convert a rgb color value to a hex string.
*
* No "#" or "0x" are added.
* @param {number} r Red
* @param {number} g Green
* @param {number} b Blue
* @returns {string}
*/
gdjs.rgbToHex = function(r, g, b) {
return '' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
};
/**
* Convert a rgb color value to a hex value.
* @param {number} r Red
* @param {number} g Green
* @param {number} b Blue
* @returns {number}
*/
gdjs.rgbToHexNumber = function(r, g, b) {
return (r << 16) + (g << 8) + b;
};
/**
* Get a random integer between 0 and max.
* @param {number} max The maximum value (inclusive).
* @returns {number}
*/
gdjs.random = function(max) {
if (max <= 0) return 0;
return Math.floor(Math.random() * (max + 1));
};
/**
* Get a random integer between min and max.
* @param {number} min The minimum value (inclusive).
* @param {number} max The maximum value (inclusive).
* @returns {number}
*/
gdjs.randomInRange = function(min, max) {
return min + gdjs.random(max - min); // return min if min >= max
};
/**
* Get a random float in the range 0 to less than max (inclusive of 0, but not max).
* @param {number} max The maximum value (exclusive).
* @returns {number}
*/
gdjs.randomFloat = function(max) {
if (max <= 0) return 0;
return Math.random() * max;
};
/**
* Get a random float between min and max
* @param {number} min The minimum value (inclusive).
* @param {number} max The maximum value (exclusive).
* @returns {number}
*/
gdjs.randomFloatInRange = function(min, max) {
return min + gdjs.randomFloat(max - min); // return min if min >= max
};
/**
* Get a random number between min and max in steps
* @param {number} min The minimum value (inclusive).
* @param {number} max The maximum value (inclusive).
* @param {number} step The interval between each value.
* @returns {number}
*/
gdjs.randomWithStep = function(min, max, step) {
if (step <= 0) return min + gdjs.random(max - min);
return min + gdjs.random(Math.floor((max - min) / step)) * step; // return min if min >= max
};
/**
* Convert an angle in degrees to radians.
* @param {number} angleInDegrees The angle in degrees.
* @returns {number}
*/
gdjs.toRad = function(angleInDegrees) {
return (angleInDegrees / 180) * 3.14159;
};
/**
* Convert an angle in radians to degrees.
* @param {number} angleInRadians The angle in radians.
* @returns {number}
*/
gdjs.toDegrees = function(angleInRadians) {
return (angleInRadians * 180) / 3.14159;
};
/**
* A Constructor for a {@link gdjs.RuntimeObject}.
* @name RuntimeObjectConstructor
* @function
* @param {gdjs.RuntimeScene} runtimeScene The {@link gdjs.RuntimeScene} the object belongs to.
* @param {ObjectData} objectData The initial properties of the object.
*/
/**
* Register a runtime object (class extending {@link gdjs.RuntimeObject}) that can be used in a scene.
*
* The name of the type of the object must be complete, with the namespace if any. For
* example, if you are providing a Text object in the TextObject extension, the full name
* of the type of the object is "TextObject::Text".
*
* @param {string} objectTypeName The name of the type of the Object.
* @param {RuntimeObjectConstructor} Ctor The constructor of the Object.
*/
gdjs.registerObject = function(objectTypeName, Ctor) {
gdjs.objectsTypes.put(objectTypeName, Ctor);
};
/**
* A Constructor for a {@link gdjs.RuntimeBehavior}.
* @name RuntimeBehaviorConstructor
* @function
* @param {gdjs.RuntimeScene} runtimeScene The scene owning the object of the behavior
* @param {BehaviorData} behaviorData The properties used to setup the behavior
* @param {gdjs.RuntimeObject} owner The object owning the behavior
*/
/**
* Register a runtime behavior (class extending {@link gdjs.RuntimeBehavior}) that can be used by a
* {@link gdjs.RuntimeObject}.
*
* The type of the behavior must be complete, with the namespace of the extension. For
* example, if you are providing a Draggable behavior in the DraggableBehavior extension,
* the full name of the type of the behavior is "DraggableBehavior::Draggable".
*
* @param {string} behaviorTypeName The name of the type of the behavior.
* @param {RuntimeBehaviorConstructor} Ctor The constructor of the Object.
*/
gdjs.registerBehavior = function(behaviorTypeName, Ctor) {
gdjs.behaviorsTypes.put(behaviorTypeName, Ctor);
};
/**
* Register a function to be called when the first {@link gdjs.RuntimeScene} is loaded, after
* resources loading is done. This can be considered as the "start of the game".
*
* @param {Function} callback The function to be called.
*/
gdjs.registerFirstRuntimeSceneLoadedCallback = function(callback) {
gdjs.callbacksFirstRuntimeSceneLoaded.push(callback);
};
/**
* Register a function to be called when a scene is loaded.
* @param {Function} callback The function to be called.
*/
gdjs.registerRuntimeSceneLoadedCallback = function(callback) {
gdjs.callbacksRuntimeSceneLoaded.push(callback);
};
/**
* Register a function to be called each time a scene is stepped (i.e: at every frame),
* before events are run.
* @param {Function} callback The function to be called.
*/
gdjs.registerRuntimeScenePreEventsCallback = function(callback) {
gdjs.callbacksRuntimeScenePreEvents.push(callback);
};
/**
* Register a function to be called each time a scene is stepped (i.e: at every frame),
* after events are run and before rendering.
* @param {Function} callback The function to be called.
*/
gdjs.registerRuntimeScenePostEventsCallback = function(callback) {
gdjs.callbacksRuntimeScenePostEvents.push(callback);
};
/**
* Register a function to be called when a scene is paused.
* @param {Function} callback The function to be called.
*/
gdjs.registerRuntimeScenePausedCallback = function(callback) {
gdjs.callbacksRuntimeScenePaused.push(callback);
};
/**
* Register a function to be called when a scene is resumed.
* @param {Function} callback The function to be called.
*/
gdjs.registerRuntimeSceneResumedCallback = function(callback) {
gdjs.callbacksRuntimeSceneResumed.push(callback);
};
/**
* Register a function to be called when a scene unload started. This is
* before the object deletion and renderer destruction. It is safe to
* manipulate these. It is **not** be safe to release resources as other
* callbacks might do operations on objects or the scene.
*
* @param {Function} callback The function to be called.
*/
gdjs.registerRuntimeSceneUnloadingCallback = function(callback) {
gdjs.callbacksRuntimeSceneUnloading.push(callback);
};
/**
* Register a function to be called when a scene is unloaded. The objects
* and renderer are now destroyed - it is **not** safe to do anything apart
* from releasing resources.
*
* @param {Function} callback The function to be called.
*/
gdjs.registerRuntimeSceneUnloadedCallback = function(callback) {
gdjs.callbacksRuntimeSceneUnloaded.push(callback);
};
/**
* Register a function to be called when an object is deleted from a scene.
* @param {Function} callback The function to be called.
*/
gdjs.registerObjectDeletedFromSceneCallback = function(callback) {
gdjs.callbacksObjectDeletedFromScene.push(callback);
};
/**
* Keep this function until we're sure now client is using it anymore.
* @deprecated
* @private
*/
gdjs.registerGlobalCallbacks = function() {
console.warning(
"You're calling gdjs.registerGlobalCallbacks. This method is now useless and you must not call it anymore."
);
};
/**
* Remove all the global callbacks that were registered previously.
*
* Should only be used for testing - this should never be used at runtime.
*/
gdjs.clearGlobalCallbacks = function() {
gdjs.callbacksFirstRuntimeSceneLoaded = [];
gdjs.callbacksRuntimeSceneLoaded = [];
gdjs.callbacksRuntimeScenePreEvents = [];
gdjs.callbacksRuntimeScenePostEvents = [];
gdjs.callbacksRuntimeScenePaused = [];
gdjs.callbacksRuntimeSceneResumed = [];
gdjs.callbacksRuntimeSceneUnloading = [];
gdjs.callbacksRuntimeSceneUnloaded = [];
gdjs.callbacksObjectDeletedFromScene = [];
};
/**
* Get the constructor of an object.
*
* @param {string} name The name of the type of the object.
* @returns {ObjectCtor}
*/
gdjs.getObjectConstructor = function(name) {
if (name !== undefined && gdjs.objectsTypes.containsKey(name))
return gdjs.objectsTypes.get(name);
console.warn('Object type "' + name + '" was not found.');
return gdjs.objectsTypes.get(''); //Create a base empty runtime object.
};
/**
* Get the constructor of a behavior.
*
* @param {string} name The name of the type of the behavior.
* @returns {BehaviorCtor}
*/
gdjs.getBehaviorConstructor = function(name) {
if (name !== undefined && gdjs.behaviorsTypes.containsKey(name))
return gdjs.behaviorsTypes.get(name);
console.warn('Behavior type "' + name + '" was not found.');
return gdjs.behaviorsTypes.get(''); //Create a base empty runtime behavior.
};
/**
* Create a static array that won't need a new allocation each time it's used.
* @param {any} owner The owner of the Array.
* @returns {Array<any>}
*/
gdjs.staticArray = function(owner) {
owner._staticArray = owner._staticArray || [];
return owner._staticArray;
};
/**
* Create a second static array that won't need a new allocation each time it's used.
* @param {any} owner The owner of the Array.
* @returns {Array<any>}
*/
gdjs.staticArray2 = function(owner) {
owner._staticArray2 = owner._staticArray2 || [];
return owner._staticArray2;
};
/**
* Create a static object that won't need a new allocation each time it's used.
* @param {any} owner The owner of the Array.
* @returns {Object}
*/
gdjs.staticObject = function(owner) {
owner._staticObject = owner._staticObject || {};
return owner._staticObject;
};
/**
* Return a new array of objects that is the concatenation of all the objects passed
* as parameters.
* @param objectsLists
* @returns {Array}
*/
gdjs.objectsListsToArray = function(objectsLists) {
var lists = gdjs.staticArray(gdjs.objectsListsToArray);
objectsLists.values(lists);
var result = [];
for (var i = 0; i < lists.length; ++i) {
var arr = lists[i];
for (var k = 0; k < arr.length; ++k) {
result.push(arr[k]);
}
}
return result;
};
Array.prototype.remove = function(from) {
//Adapted from the nice article available at
//https://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript
for (var i = from, len = this.length - 1; i < len; i++) this[i] = this[i + 1];
this.length = len;
};
Array.prototype.createFrom = function(arr) {
var len = arr.length;
for (var i = 0; i < len; ++i) {
this[i] = arr[i];
}
this.length = len;
};
//Make sure console.warn and console.error are available.
console.warn = console.warn || console.log;
console.error = console.error || console.log;

View File

@ -0,0 +1,419 @@
/*
* GDevelop JS Platform
* Copyright 2013-present Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* A thin wrapper around a Howl object with:
* * Extra methods `paused`, `stopped`, `getRate`/`setRate` and `canBeDestroyed` methods.
* * Automatic clamping when calling `setRate` to ensure a valid value is passed to Howler.js.
*
* See https://github.com/goldfire/howler.js#methods for the full documentation.
*
* @memberof gdjs
* @class HowlerSound
*/
gdjs.HowlerSound = function(o) {
Howl.call(this, o);
this._paused = false;
this._stopped = true;
this._canBeDestroyed = false;
this._rate = o.rate || 1;
//Add custom events listener to keep
//track of the sound status.
var that = this;
this.on('end', function() {
if (!that.loop()) {
that._canBeDestroyed = true;
that._paused = false;
that._stopped = true;
}
});
this.on('playerror', function(id, error) {
console.error(
"Can't play a sound, considering it as stopped. Error is:",
error
);
that._paused = false;
that._stopped = true;
});
// Track play/pause event to be sure the status is
// sync'ed with the sound - though this should be redundant
// with `play`/`pause` methods already doing that. Keeping
// that to be sure that the status is always correct.
this.on('play', function() {
that._paused = false;
that._stopped = false;
});
this.on('pause', function() {
that._paused = true;
that._stopped = false;
});
};
gdjs.HowlerSound.prototype = Object.create(Howl.prototype);
// Redefine `stop`/`play`/`pause` to ensure the status of the sound
// is immediately updated (so that calling `stopped` just after
// `play` will return false).
gdjs.HowlerSound.prototype.stop = function() {
this._paused = false;
this._stopped = true;
return Howl.prototype.stop.call(this);
};
gdjs.HowlerSound.prototype.play = function() {
this._paused = false;
this._stopped = false;
return Howl.prototype.play.call(this);
};
gdjs.HowlerSound.prototype.pause = function() {
this._paused = true;
this._stopped = false;
return Howl.prototype.pause.call(this);
};
// Add methods to query the status of the sound:
gdjs.HowlerSound.prototype.paused = function() {
return this._paused;
};
gdjs.HowlerSound.prototype.stopped = function() {
return this._stopped;
};
gdjs.HowlerSound.prototype.canBeDestroyed = function() {
return this._canBeDestroyed;
};
// Methods to safely update the rate of the sound:
gdjs.HowlerSound.prototype.getRate = function() {
return this._rate;
};
gdjs.HowlerSound.prototype.setRate = function(rate) {
this._rate = gdjs.HowlerSoundManager.clampRate(rate);
this.rate(this._rate);
};
/**
* HowlerSoundManager is used to manage the sounds and musics of a RuntimeScene.
*
* It is basically a container to associate channels to sounds and keep a list
* of all sounds being played.
*
* @memberof gdjs
* @class HowlerSoundManager
*/
gdjs.HowlerSoundManager = function(resources) {
this._resources = resources;
this._availableResources = {}; //Map storing "audio" resources for faster access.
this._globalVolume = 100;
this._sounds = {};
this._musics = {};
this._freeSounds = []; //Sounds without an assigned channel.
this._freeMusics = []; //Musics without an assigned channel.
this._pausedSounds = [];
this._paused = false;
var that = this;
this._checkForPause = function() {
if (that._paused) {
this.pause();
that._pausedSounds.push(this);
}
};
document.addEventListener('deviceready', function() {
// pause/resume sounds in Cordova when the app is being paused/resumed
document.addEventListener(
'pause',
function() {
var soundList = that._freeSounds.concat(that._freeMusics);
for (var key in that._sounds) {
if (that._sounds.hasOwnProperty(key)) {
soundList.push(that._sounds[key]);
}
}
for (var key in that._musics) {
if (that._musics.hasOwnProperty(key)) {
soundList.push(that._musics[key]);
}
}
for (var i = 0; i < soundList.length; i++) {
var sound = soundList[i];
if (!sound.paused() && !sound.stopped()) {
sound.pause();
that._pausedSounds.push(sound);
}
}
that._paused = true;
},
false
);
document.addEventListener(
'resume',
function() {
for (var i = 0; i < that._pausedSounds.length; i++) {
var sound = that._pausedSounds[i];
if (!sound.stopped()) {
sound.play();
}
}
that._pausedSounds.length = 0;
that._paused = false;
},
false
);
});
};
gdjs.SoundManager = gdjs.HowlerSoundManager; //Register the class to let the engine use it.
/**
* Ensure rate is in a range valid for Howler.js
* @return The clamped rate
* @private
*/
gdjs.HowlerSoundManager.clampRate = function(rate) {
if (rate > 4.0) return 4.0;
if (rate < 0.5) return 0.5;
return rate;
};
/**
* Return the file associated to the given sound name.
*
* Names and files are loaded from resources when preloadAudio is called. If no
* file is associated to the given name, then the name will be considered as a
* filename and will be returned.
*
* @private
* @return The associated filename
*/
gdjs.HowlerSoundManager.prototype._getFileFromSoundName = function(soundName) {
if (
this._availableResources.hasOwnProperty(soundName) &&
this._availableResources[soundName].file
) {
return this._availableResources[soundName].file;
}
return soundName;
};
/**
* Store the sound in the specified array, put it at the first index that
* is free, or add it at the end if no element is free
* ("free" means that the gdjs.HowlerSound can be destroyed).
*
* @param {Array} arr The array containing the sounds.
* @param {gdjs.HowlerSound} arr The gdjs.HowlerSound to add.
* @return The gdjs.HowlerSound that have been added (i.e: the second parameter).
* @private
*/
gdjs.HowlerSoundManager.prototype._storeSoundInArray = function(arr, sound) {
//Try to recycle an old sound.
var index = null;
for (var i = 0, len = arr.length; i < len; ++i) {
if (arr[i] !== null && arr[i].canBeDestroyed()) {
arr[index] = sound;
return sound;
}
}
arr.push(sound);
return sound;
};
gdjs.HowlerSoundManager.prototype.playSound = function(
soundName,
loop,
volume,
pitch
) {
var soundFile = this._getFileFromSoundName(soundName);
var sound = new gdjs.HowlerSound({
src: [soundFile], //TODO: ogg, mp3...
loop: loop,
volume: volume / 100,
rate: gdjs.HowlerSoundManager.clampRate(pitch),
});
this._storeSoundInArray(this._freeSounds, sound).play();
sound.on('play', this._checkForPause);
};
gdjs.HowlerSoundManager.prototype.playSoundOnChannel = function(
soundName,
channel,
loop,
volume,
pitch
) {
var oldSound = this._sounds[channel];
if (oldSound) {
oldSound.unload();
}
var soundFile = this._getFileFromSoundName(soundName);
var sound = new gdjs.HowlerSound({
src: [soundFile], //TODO: ogg, mp3...
loop: loop,
volume: volume / 100,
rate: gdjs.HowlerSoundManager.clampRate(pitch),
});
sound.play();
this._sounds[channel] = sound;
sound.on('play', this._checkForPause);
};
gdjs.HowlerSoundManager.prototype.getSoundOnChannel = function(channel) {
return this._sounds[channel];
};
gdjs.HowlerSoundManager.prototype.playMusic = function(
soundName,
loop,
volume,
pitch
) {
var soundFile = this._getFileFromSoundName(soundName);
var sound = new gdjs.HowlerSound({
src: [soundFile], //TODO: ogg, mp3...
loop: loop,
html5: true, //Force HTML5 audio so we don't wait for the full file to be loaded on Android.
volume: volume / 100,
rate: gdjs.HowlerSoundManager.clampRate(pitch),
});
this._storeSoundInArray(this._freeMusics, sound).play();
sound.on('play', this._checkForPause);
};
gdjs.HowlerSoundManager.prototype.playMusicOnChannel = function(
soundName,
channel,
loop,
volume,
pitch
) {
var oldMusic = this._musics[channel];
if (oldMusic) {
oldMusic.unload();
}
var soundFile = this._getFileFromSoundName(soundName);
var music = new gdjs.HowlerSound({
src: [soundFile], //TODO: ogg, mp3...
loop: loop,
html5: true, //Force HTML5 audio so we don't wait for the full file to be loaded on Android.
volume: volume / 100,
rate: gdjs.HowlerSoundManager.clampRate(pitch),
});
music.play();
this._musics[channel] = music;
music.on('play', this._checkForPause);
};
gdjs.HowlerSoundManager.prototype.getMusicOnChannel = function(channel) {
return this._musics[channel];
};
gdjs.HowlerSoundManager.prototype.setGlobalVolume = function(volume) {
this._globalVolume = volume;
if (this._globalVolume > 100) this._globalVolume = 100;
if (this._globalVolume < 0) this._globalVolume = 0;
Howler.volume(this._globalVolume / 100);
};
gdjs.HowlerSoundManager.prototype.getGlobalVolume = function() {
return this._globalVolume;
};
gdjs.HowlerSoundManager.prototype.clearAll = function() {
for (var i = 0; i < this._freeSounds.length; ++i) {
if (this._freeSounds[i]) this._freeSounds[i].unload();
}
for (var i = 0; i < this._freeMusics.length; ++i) {
if (this._freeMusics[i]) this._freeMusics[i].unload();
}
this._freeSounds.length = 0;
this._freeMusics.length = 0;
for (var p in this._sounds) {
if (this._sounds.hasOwnProperty(p) && this._sounds[p]) {
this._sounds[p].unload();
delete this._sounds[p];
}
}
for (var p in this._musics) {
if (this._musics.hasOwnProperty(p) && this._musics[p]) {
this._musics[p].unload();
delete this._musics[p];
}
}
this._pausedSounds.length = 0;
};
gdjs.HowlerSoundManager.prototype.preloadAudio = function(
onProgress,
onComplete,
resources
) {
resources = resources || this._resources;
//Construct the list of files to be loaded.
//For one loaded file, it can have one or more resources
//that use it.
var files = [];
for (var i = 0, len = resources.length; i < len; ++i) {
var res = resources[i];
if (res.file && res.kind === 'audio') {
this._availableResources[res.name] = res;
if (files.indexOf(res.file) === -1) {
files.push(res.file);
}
}
}
if (files.length === 0) return onComplete(files.length);
var loaded = 0;
function onLoad(audioFile) {
loaded++;
if (loaded === files.length) {
return onComplete(files.length);
}
onProgress(loaded, files.length);
}
var that = this;
for (var i = 0; i < files.length; ++i) {
(function(audioFile) {
var sound = new XMLHttpRequest();
sound.addEventListener('load', onLoad.bind(that, audioFile));
sound.addEventListener('error', onLoad.bind(that, audioFile));
sound.addEventListener('abort', onLoad.bind(that, audioFile));
sound.open('GET', audioFile);
sound.send();
})(files[i]);
}
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,114 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#000000" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
body {
margin: 0;
padding: 0;
background-color: #000000;
overflow: hidden;
}
#canvasArea {
margin-left: auto;
margin-right: auto;
overflow: hidden;
}
@font-face{ font-family : "gdjs_font_Kenney Future Narrow.ttf"; src : url('Kenney Future Narrow.ttf') format('truetype'); }
</style>
<!-- Libs and GDJS core files : -->
<script src="libs\jshashtable.js" crossorigin="anonymous"></script>
<script src="gd.js" crossorigin="anonymous"></script>
<script src="gd-splash-image.js" crossorigin="anonymous"></script>
<script src="libs\hshg.js" crossorigin="anonymous"></script>
<script src="libs\rbush.js" crossorigin="anonymous"></script>
<script src="inputmanager.js" crossorigin="anonymous"></script>
<script src="jsonmanager.js" crossorigin="anonymous"></script>
<script src="timemanager.js" crossorigin="anonymous"></script>
<script src="runtimeobject.js" crossorigin="anonymous"></script>
<script src="profiler.js" crossorigin="anonymous"></script>
<script src="runtimescene.js" crossorigin="anonymous"></script>
<script src="scenestack.js" crossorigin="anonymous"></script>
<script src="polygon.js" crossorigin="anonymous"></script>
<script src="force.js" crossorigin="anonymous"></script>
<script src="layer.js" crossorigin="anonymous"></script>
<script src="timer.js" crossorigin="anonymous"></script>
<script src="runtimegame.js" crossorigin="anonymous"></script>
<script src="variable.js" crossorigin="anonymous"></script>
<script src="variablescontainer.js" crossorigin="anonymous"></script>
<script src="oncetriggers.js" crossorigin="anonymous"></script>
<script src="runtimebehavior.js" crossorigin="anonymous"></script>
<script src="spriteruntimeobject.js" crossorigin="anonymous"></script>
<script src="events-tools\commontools.js" crossorigin="anonymous"></script>
<script src="events-tools\runtimescenetools.js" crossorigin="anonymous"></script>
<script src="events-tools\inputtools.js" crossorigin="anonymous"></script>
<script src="events-tools\objecttools.js" crossorigin="anonymous"></script>
<script src="events-tools\cameratools.js" crossorigin="anonymous"></script>
<script src="events-tools\soundtools.js" crossorigin="anonymous"></script>
<script src="events-tools\storagetools.js" crossorigin="anonymous"></script>
<script src="events-tools\stringtools.js" crossorigin="anonymous"></script>
<script src="events-tools\windowtools.js" crossorigin="anonymous"></script>
<script src="events-tools\networktools.js" crossorigin="anonymous"></script>
<script src="pixi-renderers\pixi.js" crossorigin="anonymous"></script>
<script src="pixi-renderers\pixi-filters-tools.js" crossorigin="anonymous"></script>
<script src="pixi-renderers\runtimegame-pixi-renderer.js" crossorigin="anonymous"></script>
<script src="pixi-renderers\runtimescene-pixi-renderer.js" crossorigin="anonymous"></script>
<script src="pixi-renderers\layer-pixi-renderer.js" crossorigin="anonymous"></script>
<script src="pixi-renderers\pixi-image-manager.js" crossorigin="anonymous"></script>
<script src="pixi-renderers\spriteruntimeobject-pixi-renderer.js" crossorigin="anonymous"></script>
<script src="pixi-renderers\loadingscreen-pixi-renderer.js" crossorigin="anonymous"></script>
<script src="howler-sound-manager\howler.min.js" crossorigin="anonymous"></script>
<script src="howler-sound-manager\howler-sound-manager.js" crossorigin="anonymous"></script>
<script src="fontfaceobserver-font-manager\fontfaceobserver.js" crossorigin="anonymous"></script>
<script src="fontfaceobserver-font-manager\fontfaceobserver-font-manager.js" crossorigin="anonymous"></script>
<script src="Extensions\PanelSpriteObject\panelspriteruntimeobject-pixi-renderer.js" crossorigin="anonymous"></script>
<script src="Extensions\PanelSpriteObject\panelspriteruntimeobject.js" crossorigin="anonymous"></script>
<script src="Extensions\TextObject\textruntimeobject-pixi-renderer.js" crossorigin="anonymous"></script>
<script src="Extensions\TextObject\textruntimeobject.js" crossorigin="anonymous"></script>
<script src="code0.js" crossorigin="anonymous"></script>
<script src="Extensions\DestroyOutsideBehavior\destroyoutsideruntimebehavior.js" crossorigin="anonymous"></script>
<script src="Extensions\SystemInfo\systeminfotools.js" crossorigin="anonymous"></script>
<script src="code1.js" crossorigin="anonymous"></script>
<script src="code2.js" crossorigin="anonymous"></script>
<script src="code3.js" crossorigin="anonymous"></script>
<script src="code4.js" crossorigin="anonymous"></script>
<script src="code5.js" crossorigin="anonymous"></script>
<script src="data.js" crossorigin="anonymous"></script>
</head>
<body>
<script>
(function() {
//Initialization
var game = new gdjs.RuntimeGame(gdjs.projectData, {});
//Create a renderer
game.getRenderer().createStandardCanvas(document.body);
//Bind keyboards/mouse/touch events
game.getRenderer().bindStandardEvents(game.getInputManager(), window, document);
//Load all assets and start the game
game.loadAllAssets(function() {
setTimeout(function() {
game.startGameLoop();
}, 2000)
});
})();
</script>
</body>
</html>

View File

@ -0,0 +1,317 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Store input made on a canvas: mouse position, key pressed
* and touches states.
*
* See **bindStandardEvents** method for connecting the input
* manager to a canvas and **onFrameEnded** for signaling the
* end of a frame (necessary for proper touches events handling).
*
* @constructor
* @memberof gdjs
* @class InputManager
*/
gdjs.InputManager = function()
{
this._pressedKeys = new Hashtable();
this._releasedKeys = new Hashtable();
this._lastPressedKey = 0;
this._pressedMouseButtons = new Array(5);
this._releasedMouseButtons = new Array(5);
this._mouseX = 0;
this._mouseY = 0;
this._mouseWheelDelta = 0;
this._touches = new Hashtable();
this._startedTouches = []; //Identifiers of the touches that started during/before the frame.
this._endedTouches = []; //Identifiers of the touches that ended during/before the frame.
this._touchSimulateMouse = true;
};
/** @constant {number} */
gdjs.InputManager.MOUSE_LEFT_BUTTON = 0;
/** @constant {number} */
gdjs.InputManager.MOUSE_RIGHT_BUTTON = 1;
/** @constant {number} */
gdjs.InputManager.MOUSE_MIDDLE_BUTTON = 2;
/**
* Should be called whenever a key is pressed
* @param {number} keyCode The key code associated to the key press.
*/
gdjs.InputManager.prototype.onKeyPressed = function(keyCode) {
this._pressedKeys.put(keyCode, true);
this._lastPressedKey = keyCode;
};
/**
* Should be called whenever a key is released
* @param {number} keyCode The key code associated to the key release.
*/
gdjs.InputManager.prototype.onKeyReleased = function(keyCode) {
this._pressedKeys.put(keyCode, false);
this._releasedKeys.put(keyCode, true);
};
/**
* Return the code of the last key that was pressed.
* @return {number} The code of the last key pressed.
*/
gdjs.InputManager.prototype.getLastPressedKey = function() {
return this._lastPressedKey;
};
/**
* Return true if the key corresponding to keyCode is pressed.
* @param {number} keyCode The key code to be tested.
*/
gdjs.InputManager.prototype.isKeyPressed = function(keyCode) {
return this._pressedKeys.containsKey(keyCode) && this._pressedKeys.get(keyCode);
};
/**
* Return true if the key corresponding to keyCode was released during the last frame.
* @param {number} keyCode The key code to be tested.
*/
gdjs.InputManager.prototype.wasKeyReleased = function(keyCode) {
return this._releasedKeys.containsKey(keyCode) && this._releasedKeys.get(keyCode);
};
/**
* Return true if any key is pressed
*/
gdjs.InputManager.prototype.anyKeyPressed = function() {
for(var keyCode in this._pressedKeys.items) {
if (this._pressedKeys.items.hasOwnProperty(keyCode)) {
if (this._pressedKeys.items[keyCode]) {
return true;
}
}
}
return false;
};
/**
* Should be called when the mouse is moved.<br>
* Please note that the coordinates must be expressed relative to the view position.
*
* @param {number} x The mouse new X position
* @param {number} y The mouse new Y position
*/
gdjs.InputManager.prototype.onMouseMove = function(x,y) {
this._mouseX = x;
this._mouseY = y;
};
/**
* Get the mouse X position
*
* @return the mouse X position, relative to the game view.
*/
gdjs.InputManager.prototype.getMouseX = function() {
return this._mouseX;
};
/**
* Get the mouse Y position
*
* @return the mouse Y position, relative to the game view.
*/
gdjs.InputManager.prototype.getMouseY = function() {
return this._mouseY;
};
/**
* Should be called whenever a mouse button is pressed
* @param {number} buttonCode The mouse button code associated to the event.
* See gdjs.InputManager.MOUSE_LEFT_BUTTON, gdjs.InputManager.MOUSE_RIGHT_BUTTON, gdjs.InputManager.MOUSE_MIDDLE_BUTTON
*/
gdjs.InputManager.prototype.onMouseButtonPressed = function(buttonCode) {
this._pressedMouseButtons[buttonCode] = true;
this._releasedMouseButtons[buttonCode] = false;
};
/**
* Should be called whenever a mouse button is released
* @param {number} buttonCode The mouse button code associated to the event. (see onMouseButtonPressed)
*/
gdjs.InputManager.prototype.onMouseButtonReleased = function(buttonCode) {
this._pressedMouseButtons[buttonCode] = false;
this._releasedMouseButtons[buttonCode] = true;
};
/**
* Return true if the mouse button corresponding to buttonCode is pressed.
* @param {number} buttonCode The mouse button code (0: Left button, 1: Right button).
*/
gdjs.InputManager.prototype.isMouseButtonPressed = function(buttonCode) {
return this._pressedMouseButtons[buttonCode] !== undefined && this._pressedMouseButtons[buttonCode];
};
/**
* Return true if the mouse button corresponding to buttonCode was just released.
* @param {number} buttonCode The mouse button code (0: Left button, 1: Right button).
*/
gdjs.InputManager.prototype.isMouseButtonReleased = function(buttonCode) {
return this._releasedMouseButtons[buttonCode] !== undefined && this._releasedMouseButtons[buttonCode];
};
/**
* Should be called whenever the mouse wheel is used
* @param {number} wheelDelta The mouse wheel delta
*/
gdjs.InputManager.prototype.onMouseWheel = function(wheelDelta) {
this._mouseWheelDelta = wheelDelta;
};
/**
* Return the mouse wheel delta
*/
gdjs.InputManager.prototype.getMouseWheelDelta = function() {
return this._mouseWheelDelta;
};
/**
* Get a touch X position
*
* @return the touch X position, relative to the game view.
*/
gdjs.InputManager.prototype.getTouchX = function(identifier) {
if (!this._touches.containsKey(identifier))
return 0;
return this._touches.get(identifier).x;
};
/**
* Get a touch Y position
*
* @return the touch Y position, relative to the game view.
*/
gdjs.InputManager.prototype.getTouchY = function(identifier) {
if (!this._touches.containsKey(identifier))
return 0;
return this._touches.get(identifier).y;
};
/**
* Update and return the array containing the identifiers of all touches.
*
*/
gdjs.InputManager.prototype.getAllTouchIdentifiers = function() {
gdjs.InputManager._allTouchIds = gdjs.InputManager._allTouchIds || [];
gdjs.InputManager._allTouchIds.length = 0;
for(var id in this._touches.items) {
if (this._touches.items.hasOwnProperty(id)) {
gdjs.InputManager._allTouchIds.push(parseInt(id, 10));
}
}
return gdjs.InputManager._allTouchIds;
};
gdjs.InputManager.prototype.onTouchStart = function(identifier, x, y) {
this._startedTouches.push(identifier);
this._touches.put(identifier, {x: x, y: y});
if (this._touchSimulateMouse) {
this.onMouseMove(x, y);
this.onMouseButtonPressed(gdjs.InputManager.MOUSE_LEFT_BUTTON);
}
};
gdjs.InputManager.prototype.onTouchMove = function(identifier, x, y) {
var touch = this._touches.get(identifier);
if (!touch) return;
touch.x = x;
touch.y = y;
if (this._touchSimulateMouse) {
this.onMouseMove(x, y);
}
};
gdjs.InputManager.prototype.onTouchEnd = function(identifier) {
this._endedTouches.push(identifier);
if (this._touches.containsKey(identifier)) { //Postpone deletion at the end of the frame
this._touches.get(identifier).justEnded = true;
}
if (this._touchSimulateMouse) {
this.onMouseButtonReleased(gdjs.InputManager.MOUSE_LEFT_BUTTON);
}
};
gdjs.InputManager.prototype.getStartedTouchIdentifiers = function() {
return this._startedTouches;
};
gdjs.InputManager.prototype.popStartedTouch = function() {
return this._startedTouches.shift();
};
gdjs.InputManager.prototype.popEndedTouch = function() {
return this._endedTouches.shift();
};
/**
* Set if touch events should simulate mouse events.
*
* If true, any touch will move the mouse position and set mouse buttons
* as pressed/released.
* @param enable {Boolean} true to simulate mouse events, false to disable it.
*/
gdjs.InputManager.prototype.touchSimulateMouse = function(enable) {
if (enable === undefined) enable = true;
this._touchSimulateMouse = enable;
};
/**
* Notify the input manager that the frame ended, so anything that last
* only for one frame (started/ended touches) should be reset.
*
* This method should be called in the game loop (see gdjs.RuntimeGame.startGameLoop).
*/
gdjs.InputManager.prototype.onFrameEnded = function() {
//Only clear the ended touches at the end of the frame.
for(var id in this._touches.items) {
if (this._touches.items.hasOwnProperty(id)) {
var touch = this._touches.items[id];
if(touch.justEnded) {
this._touches.remove(id);
}
}
}
this._startedTouches.length = 0;
this._endedTouches.length = 0;
this._releasedKeys.clear();
this._releasedMouseButtons.length = 0;
this._mouseWheelDelta = 0;
};
/**
* Return true if the mouse wheel scroll to up
*/
gdjs.InputManager.prototype.isScrollingUp = function() {
return this.getMouseWheelDelta() > 0;
};
/**
* Return true if the mouse wheel scroll to down
*/
gdjs.InputManager.prototype.isScrollingDown = function() {
return this.getMouseWheelDelta() < 0;
};

View File

@ -0,0 +1,158 @@
/*
* GDevelop JS Platform
* Copyright 2013-present Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* JsonManager loads json files (using XMLHttpRequest), using the "json" resources
* registered in the game resources.
*
* Contrary to audio/fonts, json files are loaded asynchronously, when requested.
* You should properly handle errors, and give the developer/player a way to know
* that loading failed.
*
* @class JsonManager
* @memberof gdjs
* @param {Object[]} resources The resources data of the game.
*/
gdjs.JsonManager = function(resources) {
this._resources = resources;
/** @type Object.<string, Object> */
this._loadedJsons = {};
};
/**
* The callback called when a json is preloaded
* @callback JsonManagerOnProgressCallback
* @param {number} loaded The number of json files loaded so far
* @param {number} total The total number to be loaded
* @returns {undefined} Nothing
*/
/**
* The callback called when all jsons are preloaded
* @callback JsonManagerOnCompleteCallback
* @param {number} total The total number to be loaded
* @returns {undefined} Nothing
*/
/**
* Request all the json resources to be preloaded (unless they are marked as not preloaded).
*
* @param {JsonManagerOnProgressCallback} onProgress The function called after each json is loaded.
* @param {JsonManagerOnCompleteCallback} onComplete The function called when all jsons are loaded.
*/
gdjs.JsonManager.prototype.preloadJsons = function(onProgress, onComplete) {
var resources = this._resources;
var jsonResources = resources.filter(function(resource) {
return resource.kind === 'json' && !resource.disablePreload;
});
if (jsonResources.length === 0) return onComplete(jsonResources.length);
var loaded = 0;
/** @type JsonManagerRequestCallback */
var onLoad = function(error, jsonContent) {
if (error) {
console.error('Error while preloading a json resource:' + error);
}
loaded++;
if (loaded === jsonResources.length) {
return onComplete(jsonResources.length);
}
onProgress(loaded, jsonResources.length);
};
for (var i = 0; i < jsonResources.length; ++i) {
this.loadJson(jsonResources[i].name, onLoad);
}
};
/**
* The callback called when a json that was requested is loaded (or an error occured).
* @callback JsonManagerRequestCallback
* @param {?Error} error The error, if any. `null` otherwise.
* @param {?Object} jsonContent The content of the json file (or null if an error occured).
* @returns {undefined} Nothing
*/
/**
* Request the json file from the given resource name.
* This method is asynchronous. When loaded, the `callback` is called with the error
* (null if none) and the loaded json (a JS Object).
*
* @param {string} resourceName The resource pointing to the json file to load.
* @param {JsonManagerRequestCallback} callback The callback function called when json is loaded (or an error occured).
*/
gdjs.JsonManager.prototype.loadJson = function(resourceName, callback) {
var resource = this._resources.find(function(resource) {
return resource.kind === 'json' && resource.name === resourceName;
});
if (!resource) {
callback(
new Error(
'Can\'t find resource with name: "' +
resourceName +
'" (or is not a json resource).'
),
null
);
return;
}
// Don't fetch again an object that is already in memory
if (this._loadedJsons[resourceName]) {
callback(null, this._loadedJsons[resourceName]);
return;
}
var that = this;
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open('GET', resource.file);
xhr.onload = function() {
if (xhr.status !== 200) {
callback(
new Error('HTTP error: ' + xhr.status + '(' + xhr.statusText + ')'),
null
);
return;
}
// Cache the result
that._loadedJsons[resourceName] = xhr.response;
callback(null, xhr.response);
};
xhr.onerror = function() {
callback(new Error('Network error'), null);
};
xhr.onabort = function() {
callback(new Error('Request aborted'), null);
};
xhr.send();
};
/**
* Check if the given json resource was loaded (preloaded or loaded with `loadJson`).
* @param {string} resourceName The name of the json resource.
* @returns {boolean} true if the content of the json resource is loaded. false otherwise.
*/
gdjs.JsonManager.prototype.isJsonLoaded = function(resourceName) {
return !!this._loadedJsons[resourceName];
};
/**
* Get the object for the given resource that is already loaded (preloaded or loaded with `loadJson`).
* If the resource is not loaded, `null` will be returned.
*
* @param {string} resourceName The name of the json resource.
* @returns {?Object} the content of the json resource, if loaded. `null` otherwise.
*/
gdjs.JsonManager.prototype.getLoadedJson = function(resourceName) {
return this._loadedJsons[resourceName] || null;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

View File

@ -0,0 +1,391 @@
// @ts-check
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Represents a layer of a scene, used to display objects.
*
* Viewports and multiple cameras are not supported.
*
* @class Layer
* @param {Object} layerData The data used to initialize the layer
* @param {gdjs.RuntimeScene} runtimeScene The scene in which the layer is used
* @memberof gdjs
*/
gdjs.Layer = function(layerData, runtimeScene) {
this._name = layerData.name;
this._cameraRotation = 0;
this._zoomFactor = 1;
this._timeScale = 1;
this._hidden = !layerData.visibility;
this._effects = layerData.effects || [];
this._cameraX = runtimeScene.getGame().getGameResolutionWidth() / 2;
this._cameraY = runtimeScene.getGame().getGameResolutionHeight() / 2;
this._cachedGameResolutionWidth = runtimeScene
.getGame()
.getGameResolutionWidth();
this._cachedGameResolutionHeight = runtimeScene
.getGame()
.getGameResolutionHeight();
this._runtimeScene = runtimeScene;
// @ts-ignore - assume the proper renderer is passed
this._renderer = new gdjs.LayerRenderer(this, runtimeScene.getRenderer());
this.show(!this._hidden);
this._setEffectsDefaultParameters();
};
gdjs.Layer.prototype.getRenderer = function() {
return this._renderer;
};
/**
* Called by the RuntimeScene whenever the game resolution size is changed.
* Updates the layer width/height and position.
*/
gdjs.Layer.prototype.onGameResolutionResized = function() {
var oldGameResolutionWidth = this._cachedGameResolutionWidth;
var oldGameResolutionHeight = this._cachedGameResolutionHeight;
this._cachedGameResolutionWidth = this._runtimeScene
.getGame()
.getGameResolutionWidth();
this._cachedGameResolutionHeight = this._runtimeScene
.getGame()
.getGameResolutionHeight();
// Adapt position of the camera center as:
// * Most cameras following a player/object on the scene will be updating this
// in events anyway.
// * Cameras not following a player/object are usually UIs which are intuitively
// expected not to "move". Not adapting the center position would make the camera
// move from its initial position (which is centered in the screen) - and anchor
// behavior would behave counterintuitively.
this._cameraX +=
(this._cachedGameResolutionWidth - oldGameResolutionWidth) / 2;
this._cameraY +=
(this._cachedGameResolutionHeight - oldGameResolutionHeight) / 2;
this._renderer.updatePosition();
};
/**
* Returns the scene the layer belongs to
* @returns {gdjs.RuntimeScene} the scene the layer belongs to
*/
gdjs.Layer.prototype.getRuntimeScene = function() {
return this._runtimeScene;
};
/**
* Called at each frame, after events are run and before rendering.
* @param {gdjs.RuntimeScene} runtimeScene The scene the layer belongs to.
*/
gdjs.Layer.prototype.update = function(runtimeScene) {
return this._renderer.updateTime();
};
/**
* Get the name of the layer
* @return {String} The name of the layer
*/
gdjs.Layer.prototype.getName = function() {
return this._name;
};
/**
* Change the camera center X position.
*
* @param {number=} cameraId The camera number. Currently ignored.
* @return The x position of the camera
*/
gdjs.Layer.prototype.getCameraX = function(cameraId) {
return this._cameraX;
};
/**
* Change the camera center Y position.
*
* @param {number=} cameraId The camera number. Currently ignored.
* @return The y position of the camera
*/
gdjs.Layer.prototype.getCameraY = function(cameraId) {
return this._cameraY;
};
/**
* Set the camera center X position.
*
* @param {number} x The new x position
* @param {number=} cameraId The camera number. Currently ignored.
*/
gdjs.Layer.prototype.setCameraX = function(x, cameraId) {
this._cameraX = x;
this._renderer.updatePosition();
};
/**
* Set the camera center Y position.
*
* @param {number} y The new y position
* @param {number=} cameraId The camera number. Currently ignored.
*/
gdjs.Layer.prototype.setCameraY = function(y, cameraId) {
this._cameraY = y;
this._renderer.updatePosition();
};
/**
* Get the camera width (which can be different than the game resolution width
* if the camera is zoomed).
*
* @param {number=} cameraId The camera number. Currently ignored.
* @return {number} The width of the camera
*/
gdjs.Layer.prototype.getCameraWidth = function(cameraId) {
return (+this._cachedGameResolutionWidth * 1) / this._zoomFactor;
};
/**
* Get the camera height (which can be different than the game resolution height
* if the camera is zoomed).
*
* @param {number=} cameraId The camera number. Currently ignored.
* @return {number} The height of the camera
*/
gdjs.Layer.prototype.getCameraHeight = function(cameraId) {
return (+this._cachedGameResolutionHeight * 1) / this._zoomFactor;
};
/**
* Show (or hide) the layer.
* @param {boolean} enable true to show the layer, false to hide it.
*/
gdjs.Layer.prototype.show = function(enable) {
this._hidden = !enable;
this._renderer.updateVisibility(enable);
};
/**
* Check if the layer is visible.
*
* @return true if the layer is visible.
*/
gdjs.Layer.prototype.isVisible = function() {
return !this._hidden;
};
/**
* Set the zoom of a camera.
*
* @param {number} newZoom The new zoom. Must be superior to 0. 1 is the default zoom.
* @param {number=} cameraId The camera number. Currently ignored.
*/
gdjs.Layer.prototype.setCameraZoom = function(newZoom, cameraId) {
this._zoomFactor = newZoom;
this._renderer.updatePosition();
};
/**
* Get the zoom of a camera.
*
* @param {number=} cameraId The camera number. Currently ignored.
* @return {number} The zoom.
*/
gdjs.Layer.prototype.getCameraZoom = function(cameraId) {
return this._zoomFactor;
};
/**
* Get the rotation of the camera, expressed in degrees.
*
* @param {number=} cameraId The camera number. Currently ignored.
* @return {number} The rotation, in degrees.
*/
gdjs.Layer.prototype.getCameraRotation = function(cameraId) {
return this._cameraRotation;
};
/**
* Set the rotation of the camera, expressed in degrees.
* The rotation is made around the camera center.
*
* @param {number} rotation The new rotation, in degrees.
* @param {number=} cameraId The camera number. Currently ignored.
*/
gdjs.Layer.prototype.setCameraRotation = function(rotation, cameraId) {
this._cameraRotation = rotation;
this._renderer.updatePosition();
};
/**
* Convert a point from the canvas coordinates (For example, the mouse position) to the
* "world" coordinates.
*
* TODO: Update this method to store the result in a static array
*
* @param {number} x The x position, in canvas coordinates.
* @param {number} y The y position, in canvas coordinates.
* @param {number=} cameraId The camera number. Currently ignored.
*/
gdjs.Layer.prototype.convertCoords = function(x, y, cameraId) {
x -= this._cachedGameResolutionWidth / 2;
y -= this._cachedGameResolutionHeight / 2;
x /= Math.abs(this._zoomFactor);
y /= Math.abs(this._zoomFactor);
// Only compute angle and cos/sin once (allow heavy optimization from JS engines).
var angleInRadians = (this._cameraRotation / 180) * Math.PI;
var tmp = x;
var cosValue = Math.cos(angleInRadians);
var sinValue = Math.sin(angleInRadians);
x = cosValue * x - sinValue * y;
y = sinValue * tmp + cosValue * y;
return [x + this.getCameraX(cameraId), y + this.getCameraY(cameraId)];
};
gdjs.Layer.prototype.convertInverseCoords = function(x, y, cameraId) {
x -= this.getCameraX(cameraId);
y -= this.getCameraY(cameraId);
// Only compute angle and cos/sin once (allow heavy optimization from JS engines).
var angleInRadians = (this._cameraRotation / 180) * Math.PI;
var tmp = x;
var cosValue = Math.cos(-angleInRadians);
var sinValue = Math.sin(-angleInRadians);
x = cosValue * x - sinValue * y;
y = sinValue * tmp + cosValue * y;
x *= Math.abs(this._zoomFactor);
y *= Math.abs(this._zoomFactor);
return [
x + this._cachedGameResolutionWidth / 2,
y + this._cachedGameResolutionHeight / 2,
];
};
gdjs.Layer.prototype.getWidth = function() {
return this._cachedGameResolutionWidth;
};
gdjs.Layer.prototype.getHeight = function() {
return this._cachedGameResolutionHeight;
};
gdjs.Layer.prototype.getEffects = function() {
return this._effects;
};
/**
* Change an effect parameter value (for parameters that are numbers).
* @param {string} name The name of the effect to update.
* @param {string} parameterName The name of the parameter to update.
* @param {number} value The new value (number).
*/
gdjs.Layer.prototype.setEffectDoubleParameter = function(
name,
parameterName,
value
) {
return this._renderer.setEffectDoubleParameter(name, parameterName, value);
};
/**
* Change an effect parameter value (for parameters that are strings).
* @param {string} name The name of the effect to update.
* @param {string} parameterName The name of the parameter to update.
* @param {string} value The new value (string).
*/
gdjs.Layer.prototype.setEffectStringParameter = function(
name,
parameterName,
value
) {
return this._renderer.setEffectStringParameter(name, parameterName, value);
};
/**
* Change an effect parameter value (for parameters that are booleans).
* @param {string} name The name of the effect to update.
* @param {string} parameterName The name of the parameter to update.
* @param {boolean} value The new value (boolean).
*/
gdjs.Layer.prototype.setEffectBooleanParameter = function(
name,
parameterName,
value
) {
return this._renderer.setEffectBooleanParameter(name, parameterName, value);
};
/**
* Enable or disable an effect.
* @param {string} name The name of the effect to enable or disable.
* @param {boolean} enable true to enable, false to disable
*/
gdjs.Layer.prototype.enableEffect = function(name, enable) {
this._renderer.enableEffect(name, enable);
};
/**
* Check if an effect is enabled
* @param {string} name The name of the effect
* @return {boolean} true if the effect is enabled, false otherwise.
*/
gdjs.Layer.prototype.isEffectEnabled = function(name) {
return this._renderer.isEffectEnabled(name);
};
gdjs.Layer.prototype._setEffectsDefaultParameters = function() {
for (var i = 0; i < this._effects.length; ++i) {
var effect = this._effects[i];
for (var name in effect.doubleParameters) {
this.setEffectDoubleParameter(
effect.name,
name,
effect.doubleParameters[name]
);
}
for (var name in effect.stringParameters) {
this.setEffectStringParameter(
effect.name,
name,
effect.stringParameters[name]
);
}
for (var name in effect.booleanParameters) {
this.setEffectBooleanParameter(
effect.name,
name,
effect.booleanParameters[name]
);
}
}
};
/**
* Set the time scale for the objects on the layer:
* time will be slower if time scale is < 1, faster if > 1.
* @param {number} timeScale The new time scale (must be positive).
*/
gdjs.Layer.prototype.setTimeScale = function(timeScale) {
if (timeScale >= 0) this._timeScale = timeScale;
};
/**
* Get the time scale for the objects on the layer.
*/
gdjs.Layer.prototype.getTimeScale = function() {
return this._timeScale;
};
/**
* Return the time elapsed since the last frame,
* in milliseconds, for objects on the layer.
*/
gdjs.Layer.prototype.getElapsedTime = function() {
return this._runtimeScene.getTimeManager().getElapsedTime() * this._timeScale;
};

View File

@ -0,0 +1,617 @@
// Hierarchical Spatial Hash Grid: HSHG
//Note that this file has been customized so that HSHG is put into the gdjs object.
//Thus, it must be included after gd.js
/**
* @namespace
* @memberof gdjs
*/
gdjs.HSHG = gdjs.HSHG || {};
(function(root, undefined){
//---------------------------------------------------------------------
// GLOBAL FUNCTIONS
//---------------------------------------------------------------------
/**
* Updates every object's position in the grid, but only if
* the hash value for that object has changed.
* This method DOES NOT take into account object expansion or
* contraction, just position, and does not attempt to change
* the grid the object is currently in; it only (possibly) changes
* the cell.
*
* If the object has significantly changed in size, the best bet is to
* call removeObject() and addObject() sequentially, outside of the
* normal update cycle of HSHG.
*
* @return void
*/
function update_RECOMPUTE(){
var i
,obj
,grid
,meta
,objAABB
,newObjHash;
// for each object
for(i = 0; i < this._globalObjects.length; i++){
obj = this._globalObjects[i];
meta = obj.HSHG;
grid = meta.grid;
// recompute hash
objAABB = obj.getAABB();
newObjHash = grid.toHash(objAABB.min[0], objAABB.min[1]);
if(newObjHash !== meta.hash){
// grid position has changed, update!
grid.removeObject(obj);
grid.addObject(obj, newObjHash);
}
}
}
function update_REMOVEALL(){
// not implemented yet :)
}
function testAABBOverlap(objA, objB){
var a = objA.getAABB()
,b = objB.getAABB();
if(a.min[0] > b.max[0] || a.min[1] > b.max[1]
|| a.max[0] < b.min[0] || a.max[1] < b.min[1]){
return false;
} else {
return true;
}
}
function getLongestAABBEdge(min, max){
return Math.max(
Math.abs(max[0] - min[0])
,Math.abs(max[1] - min[1])
);
}
//---------------------------------------------------------------------
// ENTITIES
//---------------------------------------------------------------------
/**
* A hierarchical spatial grid containing objects and allowing fast test collisions between them.
*
* @class HSHG
* @memberof gdjs.HSHG
* @constructor
*/
function HSHG(){
this.MAX_OBJECT_CELL_DENSITY = 1/8 // objects / cells
this.INITIAL_GRID_LENGTH = 256 // 16x16
this.HIERARCHY_FACTOR = 2
this.HIERARCHY_FACTOR_SQRT = Math.SQRT2
this.UPDATE_METHOD = update_RECOMPUTE // or update_REMOVEALL
this._grids = [];
this._globalObjects = [];
}
/**
* Add an object to the grid. The object can be anything as long as it provides a getAABB method.
* An 'HSHG' property is added to the object, and is then deleted when the object is removed from the HSHG.
*/
HSHG.prototype.addObject = function(obj){
var x ,i
,cellSize
,objAABB = obj.getAABB()
,objSize = getLongestAABBEdge(objAABB.min, objAABB.max)
,oneGrid, newGrid;
// for HSHG metadata
obj.HSHG = {
globalObjectsIndex: this._globalObjects.length
}; //TODO: recycle existing object if necessary.
// add to global object array
this._globalObjects.push(obj);
if(this._grids.length === 0) {
// no grids exist yet
cellSize = objSize * this.HIERARCHY_FACTOR_SQRT;
newGrid = new Grid(cellSize, this.INITIAL_GRID_LENGTH, this);
newGrid.initCells();
newGrid.addObject(obj);
this._grids.push(newGrid);
} else {
x = 0;
// grids are sorted by cellSize, smallest to largest
for(i = 0; i < this._grids.length; i++){
oneGrid = this._grids[i];
x = oneGrid.cellSize;
if(objSize < x){
x = x / this.HIERARCHY_FACTOR;
if(objSize < x) {
// find appropriate size
while( objSize < x ) {
x = x / this.HIERARCHY_FACTOR;
}
newGrid = new Grid(x * this.HIERARCHY_FACTOR, this.INITIAL_GRID_LENGTH, this);
newGrid.initCells();
// assign obj to grid
newGrid.addObject(obj)
// insert grid into list of grids directly before oneGrid
this._grids.splice(i, 0, newGrid);
} else {
// insert obj into grid oneGrid
oneGrid.addObject(obj);
}
return;
}
}
while( objSize >= x ){
x = x * this.HIERARCHY_FACTOR;
}
newGrid = new Grid(x, this.INITIAL_GRID_LENGTH, this);
newGrid.initCells();
// insert obj into grid
newGrid.addObject(obj)
// add newGrid as last element in grid list
this._grids.push(newGrid);
}
};
/**
* Remove an object from the HSHG. The object must be in the HSHG before being removed.
*/
HSHG.prototype.removeObject = function(obj){
var meta = obj.HSHG
,globalObjectsIndex
,replacementObj;
if(meta === undefined){
throw Error( obj + ' was not in the HSHG.' );
return;
}
// remove object from global object list
globalObjectsIndex = meta.globalObjectsIndex
if(globalObjectsIndex === this._globalObjects.length - 1){
this._globalObjects.pop();
} else {
replacementObj = this._globalObjects.pop();
replacementObj.HSHG.globalObjectsIndex = globalObjectsIndex;
this._globalObjects[ globalObjectsIndex ] = replacementObj;
}
meta.grid.removeObject(obj);
// remove meta data
delete obj.HSHG;
};
/**
* Must be called when objects have been moved ( typically at each "tick" of the game/simulation ).
*/
HSHG.prototype.update = function(){
this.UPDATE_METHOD.call(this);
};
/**
* Return a list of objects colliding with theObject.
* @param {gdjs.RuntimeObject} theObject The object to be tested against.
*/
HSHG.prototype.queryForCollisionWith = function(theObject, result){
var i, j, k, l, c
,grid
,cell
,objA
,objB
,offset
,adjacentCell
,biggerGrid
,objAAABB
,objAHashInBiggerGrid;
result.length = 0;
theObject.HSHG.excludeMe = true;
var theObjectAABB = theObject.getAABB();
var theObjectHashInItsGrid = theObject.HSHG.grid.toHash(theObjectAABB.min[0], theObjectAABB.min[1]);
var theObjectCellInItsGrid = theObject.HSHG.grid.allCells[theObjectHashInItsGrid];
// default broad test to internal aabb overlap test
broadOverlapTest = testAABBOverlap;
// for all grids ordered by cell size ASC
for(i = 0; i < this._grids.length; i++){
grid = this._grids[i];
if ( grid.cellSize === theObject.HSHG.grid.cellSize ) { //We're in the grid of theObject:
// 1)Test against neighbors:
// For each cell of the grid that is occupied
for(j = 0; j < grid.occupiedCells.length; j++){
cell = grid.occupiedCells[j];
// Collide all objects within the occupied cell
for(l = 0; l < cell.objectContainer.length; l++){
objB = cell.objectContainer[l]; //Note that objB could be theObject.
if(!objB.HSHG.excludeMe && broadOverlapTest(theObject, objB) === true){
result.push( objB );
}
}
// For the first half of all adjacent cells (offset 4 is the current cell)
for(c = 0; c < 4; c++){
offset = cell.neighborOffsetArray[c];
adjacentCell = grid.allCells[ cell.allCellsIndex + offset ];
// Collide all objects in cell with adjacent cell
for(l = 0; l < adjacentCell.objectContainer.length; l++){
objB = adjacentCell.objectContainer[l]; //Note that objB could be theObject.
if(!objB.HSHG.excludeMe && broadOverlapTest(theObject, objB) === true){
result.push( objB );
}
}
}
}
// 2)Test against objects of bigger grids:
// For all grids with cellsize larger than the grid of theObject:
for(k = i + 1; k < this._grids.length; k++){
biggerGrid = this._grids[k];
var objectHashInBiggerGrid = biggerGrid.toHash(theObjectAABB.min[0], theObjectAABB.min[1]);
cell = biggerGrid.allCells[objectHashInBiggerGrid];
// Check theObject against every object in all cells in offset array of cell
// for all adjacent cells...
for(c = 0; c < cell.neighborOffsetArray.length; c++){
offset = cell.neighborOffsetArray[c];
adjacentCell = biggerGrid.allCells[ cell.allCellsIndex + offset ];
// for all objects in the adjacent cell...
for(l = 0; l < adjacentCell.objectContainer.length; l++){
objB = adjacentCell.objectContainer[l];
// Test against theObject: Note that objB is necessarily different from theObject.
if(broadOverlapTest(theObject, objB) === true){
result.push( objB );
}
}
}
}
break; //All collisions with object have now been registered
}
else if ( grid.cellSize < theObject.HSHG.grid.cellSize ) { //We're in a grid with smaller objects
// For all objects that are stored in this smaller grid
for(j = 0; j < grid.allObjects.length; j++){
//Get the object of the smaller grid.
objA = grid.allObjects[j];
objAAABB = objA.getAABB();
//Get its position in the (bigger) grid containing theObject.
objAHashInBiggerGrid = theObject.HSHG.grid.toHash(objAAABB.min[0], objAAABB.min[1]);
//Check if it is near theObject (i.e: Check if the cell of objA is a neighbor of the cell
//of theObject ).
var objAIsInAdjacentCellToObject = false;
for(c = 0; c < theObjectCellInItsGrid.neighborOffsetArray.length; c++){
offset = theObjectCellInItsGrid.neighborOffsetArray[c];
if ( objAHashInBiggerGrid === theObjectCellInItsGrid.allCellsIndex + offset ) {
objAIsInAdjacentCellToObject = true;
break;
}
}
//If objA is near theObject, trigger a collision test.
if ( objAIsInAdjacentCellToObject ) {
//Note that objA is necessarily different from theObject
if(broadOverlapTest(theObject, objA) === true){
result.push( objA );
}
}
}
}
}
delete theObject.HSHG.excludeMe;
};
HSHG.update_RECOMPUTE = update_RECOMPUTE;
HSHG.update_REMOVEALL = update_REMOVEALL;
/**
* Grid
*
* @class Grid
* @memberof gdjs.HSHG
* @constructor
* @param cellSize {int} the pixel size of each cell of the grid
* @param cellCount {int} the total number of cells for the grid (width x height)
* @param parentHierarchy {HSHG} the HSHG to which this grid belongs
* @return void
*/
function Grid(cellSize, cellCount, parentHierarchy){
this.cellSize = cellSize;
this.inverseCellSize = 1/cellSize;
this.rowColumnCount = ~~Math.sqrt(cellCount);
this.xyHashMask = this.rowColumnCount - 1;
this.occupiedCells = [];
this.allCells = Array(this.rowColumnCount*this.rowColumnCount);
this.allObjects = [];
this.sharedInnerOffsets = [];
this._parentHierarchy = parentHierarchy || null;
}
Grid.prototype.initCells = function(){
// TODO: inner/unique offset rows 0 and 2 may need to be
// swapped due to +y being "down" vs "up"
var i, gridLength = this.allCells.length
,x, y
,wh = this.rowColumnCount
,isOnRightEdge, isOnLeftEdge, isOnTopEdge, isOnBottomEdge
,innerOffsets = [
// y+ down offsets
//-1 + -wh, -wh, -wh + 1,
//-1, 0, 1,
//wh - 1, wh, wh + 1
// y+ up offsets
wh - 1, wh, wh + 1,
-1, 0, 1,
-1 + -wh, -wh, -wh + 1
]
,leftOffset, rightOffset, topOffset, bottomOffset
,uniqueOffsets = []
,cell;
this.sharedInnerOffsets = innerOffsets;
// init all cells, creating offset arrays as needed
for(i = 0; i < gridLength; i++){
cell = new Cell();
// compute row (y) and column (x) for an index
y = ~~(i / this.rowColumnCount);
x = ~~(i - (y*this.rowColumnCount));
// reset / init
isOnRightEdge = false;
isOnLeftEdge = false;
isOnTopEdge = false;
isOnBottomEdge = false;
// right or left edge cell
if((x+1) % this.rowColumnCount == 0){ isOnRightEdge = true; }
else if(x % this.rowColumnCount == 0){ isOnLeftEdge = true; }
// top or bottom edge cell
if((y+1) % this.rowColumnCount == 0){ isOnTopEdge = true; }
else if(y % this.rowColumnCount == 0){ isOnBottomEdge = true; }
// if cell is edge cell, use unique offsets, otherwise use inner offsets
if(isOnRightEdge || isOnLeftEdge || isOnTopEdge || isOnBottomEdge){
// figure out cardinal offsets first
rightOffset = isOnRightEdge === true ? -wh + 1 : 1;
leftOffset = isOnLeftEdge === true ? wh - 1 : -1;
topOffset = isOnTopEdge === true ? -gridLength + wh : wh;
bottomOffset = isOnBottomEdge === true ? gridLength - wh : -wh;
// diagonals are composites of the cardinals
uniqueOffsets = [
// y+ down offset
//leftOffset + bottomOffset, bottomOffset, rightOffset + bottomOffset,
//leftOffset, 0, rightOffset,
//leftOffset + topOffset, topOffset, rightOffset + topOffset
// y+ up offset
leftOffset + topOffset, topOffset, rightOffset + topOffset,
leftOffset, 0, rightOffset,
leftOffset + bottomOffset, bottomOffset, rightOffset + bottomOffset
];
cell.neighborOffsetArray = uniqueOffsets;
} else {
cell.neighborOffsetArray = this.sharedInnerOffsets;
}
cell.allCellsIndex = i;
this.allCells[i] = cell;
}
}
Grid.prototype.toHash = function(x, y, z){
var i, xHash, yHash, zHash;
if(x < 0){
i = (-x) * this.inverseCellSize;
xHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask );
} else {
i = x * this.inverseCellSize;
xHash = ~~i & this.xyHashMask;
}
if(y < 0){
i = (-y) * this.inverseCellSize;
yHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask );
} else {
i = y * this.inverseCellSize;
yHash = ~~i & this.xyHashMask;
}
return xHash + yHash * this.rowColumnCount;
}
Grid.prototype.addObject = function(obj, hash){
var objAABB
,objHash
,targetCell;
// technically, passing this in this should save some computational effort when updating objects
if(hash !== undefined){
objHash = hash;
} else {
objAABB = obj.getAABB()
objHash = this.toHash(objAABB.min[0], objAABB.min[1])
}
targetCell = this.allCells[objHash];
if(targetCell.objectContainer.length === 0){
// insert this cell into occupied cells list
targetCell.occupiedCellsIndex = this.occupiedCells.length;
this.occupiedCells.push(targetCell);
}
// add meta data to obj, for fast update/removal
obj.HSHG.objectContainerIndex = targetCell.objectContainer.length;
obj.HSHG.hash = objHash;
obj.HSHG.grid = this;
obj.HSHG.allGridObjectsIndex = this.allObjects.length;
// add obj to cell
targetCell.objectContainer.push(obj);
// we can assume that the targetCell is already a member of the occupied list
// add to grid-global object list
this.allObjects.push(obj);
// do test for grid density
if(this.allObjects.length / this.allCells.length > this._parentHierarchy.MAX_OBJECT_CELL_DENSITY){
// grid must be increased in size
this.expandGrid();
}
}
Grid.prototype.removeObject = function(obj){
var meta = obj.HSHG
,hash
,containerIndex
,allGridObjectsIndex
,cell
,replacementCell
,replacementObj;
hash = meta.hash;
containerIndex = meta.objectContainerIndex;
allGridObjectsIndex = meta.allGridObjectsIndex;
cell = this.allCells[hash];
// remove object from cell object container
if(cell.objectContainer.length === 1){
// this is the last object in the cell, so reset it
cell.objectContainer.length = 0;
// remove cell from occupied list
if(cell.occupiedCellsIndex === this.occupiedCells.length - 1){
// special case if the cell is the newest in the list
this.occupiedCells.pop();
} else {
replacementCell = this.occupiedCells.pop();
replacementCell.occupiedCellsIndex = cell.occupiedCellsIndex;
this.occupiedCells[ cell.occupiedCellsIndex ] = replacementCell;
}
cell.occupiedCellsIndex = null;
} else {
// there is more than one object in the container
if(containerIndex === cell.objectContainer.length - 1){
// special case if the obj is the newest in the container
cell.objectContainer.pop();
} else {
replacementObj = cell.objectContainer.pop();
replacementObj.HSHG.objectContainerIndex = containerIndex;
cell.objectContainer[ containerIndex ] = replacementObj;
}
}
// remove object from grid object list
if(allGridObjectsIndex === this.allObjects.length - 1){
this.allObjects.pop();
} else {
replacementObj = this.allObjects.pop();
replacementObj.HSHG.allGridObjectsIndex = allGridObjectsIndex;
this.allObjects[ allGridObjectsIndex ] = replacementObj;
}
}
Grid.prototype.expandGrid = function(){
var i, j
,currentCellCount = this.allCells.length
,currentRowColumnCount = this.rowColumnCount
,currentXYHashMask = this.xyHashMask
,newCellCount = currentCellCount * 4 // double each dimension
,newRowColumnCount = ~~Math.sqrt(newCellCount)
,newXYHashMask = newRowColumnCount - 1
,allObjects = this.allObjects.slice(0) // duplicate array, not objects contained
,aCell
,push = Array.prototype.push;
// remove all objects
for(i = 0; i < allObjects.length; i++){
this.removeObject(allObjects[i]);
}
// reset grid values, set new grid to be 4x larger than last
this.rowColumnCount = newRowColumnCount;
this.allCells = Array(this.rowColumnCount*this.rowColumnCount);
this.xyHashMask = newXYHashMask;
// initialize new cells
this.initCells();
// re-add all objects to grid
for(i = 0; i < allObjects.length; i++){
this.addObject(allObjects[i]);
}
}
/**
* A cell of a grid
*
* @class Cell
* @memberof gdjs.HSHG
* @constructor
* @private
*/
function Cell(){
this.objectContainer = [];
this.neighborOffsetArray;
this.occupiedCellsIndex = null;
this.allCellsIndex = null;
}
//---------------------------------------------------------------------
// EXPORTS
//---------------------------------------------------------------------
root['HSHG'] = HSHG;
HSHG._private = {
Grid: Grid,
Cell: Cell,
testAABBOverlap: testAABBOverlap,
getLongestAABBEdge: getLongestAABBEdge
};
})(gdjs.HSHG);

View File

@ -0,0 +1,134 @@
// @ts-check
/**
* A generic map (key-value) container.
*
* Mostly used for storing lists of objects for
* GDevelop generated events.
*
* @constructor
*/
function Hashtable()
{
/**
* The content of the Hashtable. Prefer using methods rather
* than accessing this internal object, unless you need to iterate
* on the values.
* @type {Object.<string, any>}
*/
this.items = {};
}
/**
* Construct a Hashtable from a JS object.
*
* @param {Object.<string, any>} items The content of the Hashtable.
* @returns {Hashtable} The new hashtable.
* @static
*/
Hashtable.newFrom = function(items) {
var hashtable = new Hashtable();
hashtable.items = items;
return hashtable;
}
/**
* Add a key-value pair to the Hashtable.
* If a value already exists for this key, it is overwritten.
*
* @memberof Hashtable
* @param {string} key The key.
* @param {any} value The value to associate to the key.
*/
Hashtable.prototype.put = function(key, value) {
this.items[key] = value;
}
/**
* Get a value corresponding to a key, or undefined if not found.
*
* @memberof Hashtable
* @param {string} key The key associated to the value.
*/
Hashtable.prototype.get = function(key) {
return this.items[key];
}
/**
* Verify if a key exists in the Hashtable.
*
* @memberof Hashtable
* @param {string} key The key to search in the Hashtable.
* @returns {boolean} true if the key exists.
*/
Hashtable.prototype.containsKey = function(key) {
return this.items.hasOwnProperty(key);
}
/**
* Remove the value associated to the specified key.
*
* @memberof Hashtable
* @param {string} key The key to remove.
*/
Hashtable.prototype.remove = function(key) {
delete this.items[key];
}
/**
* Get the first key of the Hashtable.
*
* @memberof Hashtable
* @returns {?string} The first key of the Hashtable, or undefined if empty.
*/
Hashtable.prototype.firstKey = function() {
for (var k in this.items) {
if (this.items.hasOwnProperty(k)) {
return k;
}
}
return null;
}
/**
* Dump all the keys of the Hashtable to an array (which is cleared first).
*
* @memberof Hashtable
* @param {Array<string>} result The Array where the result gets pushed.
*/
Hashtable.prototype.keys = function(result) {
result.length = 0;
for (var k in this.items) {
if (this.items.hasOwnProperty(k)) {
result.push(k);
}
}
}
/**
* Dump all the values of the Hashtable to an array (which is cleared first).
*
* @memberof Hashtable
* @param {Array<any>} result The Array where the results get pushed.
*/
Hashtable.prototype.values = function(result) {
result.length = 0;
for (var k in this.items) {
if (this.items.hasOwnProperty(k)) {
result.push(this.items[k]);
}
}
}
/**
* Clear the Hashtable.
*
* @memberof Hashtable
*/
Hashtable.prototype.clear = function() {
for (var k in this.items) {
if (this.items.hasOwnProperty(k)) {
delete this.items[k];
}
}
}

View File

@ -0,0 +1,624 @@
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.rbush = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
module.exports = rbush;
var quickselect = require('quickselect');
function rbush(maxEntries, format) {
if (!(this instanceof rbush)) return new rbush(maxEntries, format);
// max entries in a node is 9 by default; min node fill is 40% for best performance
this._maxEntries = Math.max(4, maxEntries || 9);
this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
if (format) {
this._initFormat(format);
}
this.clear();
}
rbush.prototype = {
all: function () {
return this._all(this.data, []);
},
search: function (bbox) {
var node = this.data,
result = [],
toBBox = this.toBBox;
if (!intersects(bbox, node)) return result;
var nodesToSearch = [],
i, len, child, childBBox;
while (node) {
for (i = 0, len = node.children.length; i < len; i++) {
child = node.children[i];
childBBox = node.leaf ? toBBox(child) : child;
if (intersects(bbox, childBBox)) {
if (node.leaf) result.push(child);
else if (contains(bbox, childBBox)) this._all(child, result);
else nodesToSearch.push(child);
}
}
node = nodesToSearch.pop();
}
return result;
},
collides: function (bbox) {
var node = this.data,
toBBox = this.toBBox;
if (!intersects(bbox, node)) return false;
var nodesToSearch = [],
i, len, child, childBBox;
while (node) {
for (i = 0, len = node.children.length; i < len; i++) {
child = node.children[i];
childBBox = node.leaf ? toBBox(child) : child;
if (intersects(bbox, childBBox)) {
if (node.leaf || contains(bbox, childBBox)) return true;
nodesToSearch.push(child);
}
}
node = nodesToSearch.pop();
}
return false;
},
load: function (data) {
if (!(data && data.length)) return this;
if (data.length < this._minEntries) {
for (var i = 0, len = data.length; i < len; i++) {
this.insert(data[i]);
}
return this;
}
// recursively build the tree with the given data from stratch using OMT algorithm
var node = this._build(data.slice(), 0, data.length - 1, 0);
if (!this.data.children.length) {
// save as is if tree is empty
this.data = node;
} else if (this.data.height === node.height) {
// split root if trees have the same height
this._splitRoot(this.data, node);
} else {
if (this.data.height < node.height) {
// swap trees if inserted one is bigger
var tmpNode = this.data;
this.data = node;
node = tmpNode;
}
// insert the small tree into the large tree at appropriate level
this._insert(node, this.data.height - node.height - 1, true);
}
return this;
},
insert: function (item) {
if (item) this._insert(item, this.data.height - 1);
return this;
},
clear: function () {
this.data = createNode([]);
return this;
},
remove: function (item, equalsFn) {
if (!item) return this;
var node = this.data,
bbox = this.toBBox(item),
path = [],
indexes = [],
i, parent, index, goingUp;
// depth-first iterative tree traversal
while (node || path.length) {
if (!node) { // go up
node = path.pop();
parent = path[path.length - 1];
i = indexes.pop();
goingUp = true;
}
if (node.leaf) { // check current node
index = findItem(item, node.children, equalsFn);
if (index !== -1) {
// item found, remove the item and condense tree upwards
node.children.splice(index, 1);
path.push(node);
this._condense(path);
return this;
}
}
if (!goingUp && !node.leaf && contains(node, bbox)) { // go down
path.push(node);
indexes.push(i);
i = 0;
parent = node;
node = node.children[0];
} else if (parent) { // go right
i++;
node = parent.children[i];
goingUp = false;
} else node = null; // nothing found
}
return this;
},
toBBox: function (item) { return item; },
compareMinX: compareNodeMinX,
compareMinY: compareNodeMinY,
toJSON: function () { return this.data; },
fromJSON: function (data) {
this.data = data;
return this;
},
_all: function (node, result) {
var nodesToSearch = [];
while (node) {
if (node.leaf) result.push.apply(result, node.children);
else nodesToSearch.push.apply(nodesToSearch, node.children);
node = nodesToSearch.pop();
}
return result;
},
_build: function (items, left, right, height) {
var N = right - left + 1,
M = this._maxEntries,
node;
if (N <= M) {
// reached leaf level; return leaf
node = createNode(items.slice(left, right + 1));
calcBBox(node, this.toBBox);
return node;
}
if (!height) {
// target height of the bulk-loaded tree
height = Math.ceil(Math.log(N) / Math.log(M));
// target number of root entries to maximize storage utilization
M = Math.ceil(N / Math.pow(M, height - 1));
}
node = createNode([]);
node.leaf = false;
node.height = height;
// split the items into M mostly square tiles
var N2 = Math.ceil(N / M),
N1 = N2 * Math.ceil(Math.sqrt(M)),
i, j, right2, right3;
multiSelect(items, left, right, N1, this.compareMinX);
for (i = left; i <= right; i += N1) {
right2 = Math.min(i + N1 - 1, right);
multiSelect(items, i, right2, N2, this.compareMinY);
for (j = i; j <= right2; j += N2) {
right3 = Math.min(j + N2 - 1, right2);
// pack each entry recursively
node.children.push(this._build(items, j, right3, height - 1));
}
}
calcBBox(node, this.toBBox);
return node;
},
_chooseSubtree: function (bbox, node, level, path) {
var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
while (true) {
path.push(node);
if (node.leaf || path.length - 1 === level) break;
minArea = minEnlargement = Infinity;
for (i = 0, len = node.children.length; i < len; i++) {
child = node.children[i];
area = bboxArea(child);
enlargement = enlargedArea(bbox, child) - area;
// choose entry with the least area enlargement
if (enlargement < minEnlargement) {
minEnlargement = enlargement;
minArea = area < minArea ? area : minArea;
targetNode = child;
} else if (enlargement === minEnlargement) {
// otherwise choose one with the smallest area
if (area < minArea) {
minArea = area;
targetNode = child;
}
}
}
node = targetNode || node.children[0];
}
return node;
},
_insert: function (item, level, isNode) {
var toBBox = this.toBBox,
bbox = isNode ? item : toBBox(item),
insertPath = [];
// find the best node for accommodating the item, saving all nodes along the path too
var node = this._chooseSubtree(bbox, this.data, level, insertPath);
// put the item into the node
node.children.push(item);
extend(node, bbox);
// split on node overflow; propagate upwards if necessary
while (level >= 0) {
if (insertPath[level].children.length > this._maxEntries) {
this._split(insertPath, level);
level--;
} else break;
}
// adjust bboxes along the insertion path
this._adjustParentBBoxes(bbox, insertPath, level);
},
// split overflowed node into two
_split: function (insertPath, level) {
var node = insertPath[level],
M = node.children.length,
m = this._minEntries;
this._chooseSplitAxis(node, m, M);
var splitIndex = this._chooseSplitIndex(node, m, M);
var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
newNode.height = node.height;
newNode.leaf = node.leaf;
calcBBox(node, this.toBBox);
calcBBox(newNode, this.toBBox);
if (level) insertPath[level - 1].children.push(newNode);
else this._splitRoot(node, newNode);
},
_splitRoot: function (node, newNode) {
// split root node
this.data = createNode([node, newNode]);
this.data.height = node.height + 1;
this.data.leaf = false;
calcBBox(this.data, this.toBBox);
},
_chooseSplitIndex: function (node, m, M) {
var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
minOverlap = minArea = Infinity;
for (i = m; i <= M - m; i++) {
bbox1 = distBBox(node, 0, i, this.toBBox);
bbox2 = distBBox(node, i, M, this.toBBox);
overlap = intersectionArea(bbox1, bbox2);
area = bboxArea(bbox1) + bboxArea(bbox2);
// choose distribution with minimum overlap
if (overlap < minOverlap) {
minOverlap = overlap;
index = i;
minArea = area < minArea ? area : minArea;
} else if (overlap === minOverlap) {
// otherwise choose distribution with minimum area
if (area < minArea) {
minArea = area;
index = i;
}
}
}
return index;
},
// sorts node children by the best axis for split
_chooseSplitAxis: function (node, m, M) {
var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
xMargin = this._allDistMargin(node, m, M, compareMinX),
yMargin = this._allDistMargin(node, m, M, compareMinY);
// if total distributions margin value is minimal for x, sort by minX,
// otherwise it's already sorted by minY
if (xMargin < yMargin) node.children.sort(compareMinX);
},
// total margin of all possible split distributions where each node is at least m full
_allDistMargin: function (node, m, M, compare) {
node.children.sort(compare);
var toBBox = this.toBBox,
leftBBox = distBBox(node, 0, m, toBBox),
rightBBox = distBBox(node, M - m, M, toBBox),
margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
i, child;
for (i = m; i < M - m; i++) {
child = node.children[i];
extend(leftBBox, node.leaf ? toBBox(child) : child);
margin += bboxMargin(leftBBox);
}
for (i = M - m - 1; i >= m; i--) {
child = node.children[i];
extend(rightBBox, node.leaf ? toBBox(child) : child);
margin += bboxMargin(rightBBox);
}
return margin;
},
_adjustParentBBoxes: function (bbox, path, level) {
// adjust bboxes along the given tree path
for (var i = level; i >= 0; i--) {
extend(path[i], bbox);
}
},
_condense: function (path) {
// go through the path, removing empty nodes and updating bboxes
for (var i = path.length - 1, siblings; i >= 0; i--) {
if (path[i].children.length === 0) {
if (i > 0) {
siblings = path[i - 1].children;
siblings.splice(siblings.indexOf(path[i]), 1);
} else this.clear();
} else calcBBox(path[i], this.toBBox);
}
},
_initFormat: function (format) {
// data format (minX, minY, maxX, maxY accessors)
// uses eval-type function compilation instead of just accepting a toBBox function
// because the algorithms are very sensitive to sorting functions performance,
// so they should be dead simple and without inner calls
var compareArr = ['return a', ' - b', ';'];
this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
this.toBBox = new Function('a',
'return {minX: a' + format[0] +
', minY: a' + format[1] +
', maxX: a' + format[2] +
', maxY: a' + format[3] + '};');
}
};
function findItem(item, items, equalsFn) {
if (!equalsFn) return items.indexOf(item);
for (var i = 0; i < items.length; i++) {
if (equalsFn(item, items[i])) return i;
}
return -1;
}
// calculate node's bbox from bboxes of its children
function calcBBox(node, toBBox) {
distBBox(node, 0, node.children.length, toBBox, node);
}
// min bounding rectangle of node children from k to p-1
function distBBox(node, k, p, toBBox, destNode) {
if (!destNode) destNode = createNode(null);
destNode.minX = Infinity;
destNode.minY = Infinity;
destNode.maxX = -Infinity;
destNode.maxY = -Infinity;
for (var i = k, child; i < p; i++) {
child = node.children[i];
extend(destNode, node.leaf ? toBBox(child) : child);
}
return destNode;
}
function extend(a, b) {
a.minX = Math.min(a.minX, b.minX);
a.minY = Math.min(a.minY, b.minY);
a.maxX = Math.max(a.maxX, b.maxX);
a.maxY = Math.max(a.maxY, b.maxY);
return a;
}
function compareNodeMinX(a, b) { return a.minX - b.minX; }
function compareNodeMinY(a, b) { return a.minY - b.minY; }
function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); }
function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
function enlargedArea(a, b) {
return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
(Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
}
function intersectionArea(a, b) {
var minX = Math.max(a.minX, b.minX),
minY = Math.max(a.minY, b.minY),
maxX = Math.min(a.maxX, b.maxX),
maxY = Math.min(a.maxY, b.maxY);
return Math.max(0, maxX - minX) *
Math.max(0, maxY - minY);
}
function contains(a, b) {
return a.minX <= b.minX &&
a.minY <= b.minY &&
b.maxX <= a.maxX &&
b.maxY <= a.maxY;
}
function intersects(a, b) {
return b.minX <= a.maxX &&
b.minY <= a.maxY &&
b.maxX >= a.minX &&
b.maxY >= a.minY;
}
function createNode(children) {
return {
children: children,
height: 1,
leaf: true,
minX: Infinity,
minY: Infinity,
maxX: -Infinity,
maxY: -Infinity
};
}
// sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
// combines selection algorithm with binary divide & conquer approach
function multiSelect(arr, left, right, n, compare) {
var stack = [left, right],
mid;
while (stack.length) {
right = stack.pop();
left = stack.pop();
if (right - left <= n) continue;
mid = left + Math.ceil((right - left) / n / 2) * n;
quickselect(arr, mid, left, right, compare);
stack.push(left, mid, mid, right);
}
}
},{"quickselect":2}],2:[function(require,module,exports){
'use strict';
module.exports = partialSort;
// Floyd-Rivest selection algorithm:
// Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];
// The k-th element will have the (k - left + 1)th smallest value in [left, right]
function partialSort(arr, k, left, right, compare) {
while (right > left) {
if (right - left > 600) {
var n = right - left + 1;
var m = k - left + 1;
var z = Math.log(n);
var s = 0.5 * Math.exp(2 * z / 3);
var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
partialSort(arr, k, newLeft, newRight, compare);
}
var t = arr[k];
var i = left;
var j = right;
swap(arr, left, k);
if (compare(arr[right], t) > 0) swap(arr, left, right);
while (i < j) {
swap(arr, i, j);
i++;
j--;
while (compare(arr[i], t) < 0) i++;
while (compare(arr[j], t) > 0) j--;
}
if (compare(arr[left], t) === 0) swap(arr, left, j);
else {
j++;
swap(arr, j, right);
}
if (j <= k) left = j + 1;
if (k <= j) right = j - 1;
}
}
function swap(arr, i, j) {
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
function defaultCompare(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
},{}]},{},[1])(1)
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,52 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* OnceTriggers is used to store the status of the conditions "Trigger once",
* that are used in events to have conditions that are only valid for one frame in a row.
*
* @memberof gdjs
* @class OnceTriggers
* @constructor
*/
gdjs.OnceTriggers = function()
{
this._onceTriggers = {};
this._lastFrameOnceTrigger = {};
};
/**
* To be called when events begin so that "Trigger once" conditions
* are properly handled.
*/
gdjs.OnceTriggers.prototype.startNewFrame = function() {
this._clearObject(this._lastFrameOnceTrigger);
for (var k in this._onceTriggers) {
if (this._onceTriggers.hasOwnProperty(k)) {
this._lastFrameOnceTrigger[k] = this._onceTriggers[k];
delete this._onceTriggers[k];
}
}
};
/**
* Used by "Trigger once" conditions: return true only if
* this method was not called with the same identifier during the last frame.
* @param triggerId The identifier of the "Trigger once" condition.
*/
gdjs.OnceTriggers.prototype.triggerOnce = function(triggerId) {
this._onceTriggers[triggerId] = true;
return !this._lastFrameOnceTrigger.hasOwnProperty(triggerId);
};
gdjs.OnceTriggers.prototype._clearObject = function(obj) {
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
delete obj[k];
}
}
};

View File

@ -0,0 +1,228 @@
// @ts-check
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* The renderer for a gdjs.Layer using Pixi.js.
*
* @class LayerPixiRenderer
* @memberof gdjs
* @param {gdjs.Layer} layer The layer
* @param {gdjs.RuntimeScenePixiRenderer} runtimeSceneRenderer The scene renderer
*/
gdjs.LayerPixiRenderer = function(layer, runtimeSceneRenderer) {
// @ts-ignore
this._pixiContainer = new PIXI.Container();
/** @type Object.<string, gdjsPixiFiltersToolsFilter> */
this._filters = {};
this._layer = layer;
runtimeSceneRenderer.getPIXIContainer().addChild(this._pixiContainer);
this._setupFilters();
};
gdjs.LayerRenderer = gdjs.LayerPixiRenderer; //Register the class to let the engine use it.
/**
* Update the position of the PIXI container. To be called after each change
* made to position, zoom or rotation of the camera.
* @private
*/
gdjs.LayerPixiRenderer.prototype.updatePosition = function() {
var angle = -gdjs.toRad(this._layer.getCameraRotation());
var zoomFactor = this._layer.getCameraZoom();
this._pixiContainer.rotation = angle;
this._pixiContainer.scale.x = zoomFactor;
this._pixiContainer.scale.y = zoomFactor;
var cosValue = Math.cos(angle);
var sinValue = Math.sin(angle);
var centerX =
this._layer.getCameraX() * zoomFactor * cosValue -
this._layer.getCameraY() * zoomFactor * sinValue;
var centerY =
this._layer.getCameraX() * zoomFactor * sinValue +
this._layer.getCameraY() * zoomFactor * cosValue;
this._pixiContainer.position.x = -centerX;
this._pixiContainer.position.y = -centerY;
this._pixiContainer.position.x += this._layer.getWidth() / 2;
this._pixiContainer.position.y += this._layer.getHeight() / 2;
};
gdjs.LayerPixiRenderer.prototype.updateVisibility = function(visible) {
this._pixiContainer.visible = !!visible;
};
gdjs.LayerPixiRenderer.prototype.updateTime = function() {
for(var filterName in this._filters) {
var filter = this._filters[filterName];
filter.update(filter.pixiFilter, this._layer);
}
};
gdjs.LayerPixiRenderer.prototype._setupFilters = function() {
var effects = this._layer.getEffects();
if (effects.length === 0) {
return;
}
this._filters = {};
// @ts-ignore
/** @type PIXI.Filter[] */
var pixiFilters = [];
for (var i = 0; i < effects.length; ++i) {
var effect = effects[i];
var filterCreator = gdjs.PixiFiltersTools.getFilterCreator(
effect.effectType
);
if (!filterCreator) {
console.log(
'Filter "' +
effect.name +
'" has an unknown effect type: "' +
effect.effectType +
'". Was it registered properly? Is the effect type correct?'
);
continue;
}
/** @type gdjsPixiFiltersToolsFilter */
var filter = {
pixiFilter: filterCreator.makePIXIFilter(this._layer, effect),
updateDoubleParameter: filterCreator.updateDoubleParameter,
updateStringParameter: filterCreator.updateStringParameter,
updateBooleanParameter: filterCreator.updateBooleanParameter,
update: filterCreator.update,
};
pixiFilters.push(filter.pixiFilter);
this._filters[effect.name] = filter;
}
this._pixiContainer.filters = pixiFilters;
};
/**
* Add a child to the pixi container associated to the layer.
* All objects which are on this layer must be children of this container.
*
* @param child The child (PIXI object) to be added.
* @param zOrder The z order of the associated object.
*/
gdjs.LayerPixiRenderer.prototype.addRendererObject = function(child, zOrder) {
child.zOrder = zOrder; //Extend the pixi object with a z order.
for (var i = 0, len = this._pixiContainer.children.length; i < len; ++i) {
if (this._pixiContainer.children[i].zOrder >= zOrder) {
//TODO : Dichotomic search
this._pixiContainer.addChildAt(child, i);
return;
}
}
this._pixiContainer.addChild(child);
};
/**
* Change the z order of a child associated to an object.
*
* @param child The child (PIXI object) to be modified.
* @param newZOrder The z order of the associated object.
*/
gdjs.LayerPixiRenderer.prototype.changeRendererObjectZOrder = function(
child,
newZOrder
) {
this._pixiContainer.removeChild(child);
this.addRendererObject(child, newZOrder);
};
/**
* Remove a child from the internal pixi container.
* Should be called when an object is deleted or removed from the layer.
*
* @param child The child (PIXI object) to be removed.
*/
gdjs.LayerPixiRenderer.prototype.removeRendererObject = function(child) {
this._pixiContainer.removeChild(child);
};
/**
* Update the parameter of an effect (with a number).
* @param {string} name The effect name
* @param {string} parameterName The parameter name
* @param {number} value The new value for the parameter
*/
gdjs.LayerPixiRenderer.prototype.setEffectDoubleParameter = function(
name,
parameterName,
value
) {
var filter = this._filters[name];
if (!filter) return;
filter.updateDoubleParameter(filter.pixiFilter, parameterName, value);
};
/**
* Update the parameter of an effect (with a string).
* @param {string} name The effect name
* @param {string} parameterName The parameter name
* @param {string} value The new value for the parameter
*/
gdjs.LayerPixiRenderer.prototype.setEffectStringParameter = function(
name,
parameterName,
value
) {
var filter = this._filters[name];
if (!filter) return;
filter.updateStringParameter(filter.pixiFilter, parameterName, value);
};
/**
* Enable or disable the parameter of an effect (boolean).
* @param {string} name The effect name
* @param {string} parameterName The parameter name
* @param {boolean} value The new value for the parameter
*/
gdjs.LayerPixiRenderer.prototype.setEffectBooleanParameter = function(
name,
parameterName,
value
) {
var filter = this._filters[name];
if (!filter) return;
filter.updateBooleanParameter(filter.pixiFilter, parameterName, value);
};
/**
* Enable an effect.
* @param {string} name The effect name
* @param {boolean} value Set to true to enable, false to disable
*/
gdjs.LayerPixiRenderer.prototype.enableEffect = function(name, value) {
var filter = this._filters[name];
if (!filter) return;
gdjs.PixiFiltersTools.enableEffect(filter, value);
};
/**
* Check if an effect is enabled.
* @param {string} name The effect name
* @return {boolean} true if the filter is enabled
*/
gdjs.LayerPixiRenderer.prototype.isEffectEnabled = function(name) {
var filter = this._filters[name];
if (!filter) return false;
return gdjs.PixiFiltersTools.isEffectEnabled(filter);
};

View File

@ -0,0 +1,83 @@
gdjs.LoadingScreenPixiRenderer = function(runtimeGamePixiRenderer, loadingScreenSetup) {
this._pixiRenderer = runtimeGamePixiRenderer.getPIXIRenderer();
if (!this._pixiRenderer) {
// A PIXI Renderer can be missing during tests, when creating a runtime game
// without a canvas.
return;
}
this._loadingScreen = new PIXI.Container();
this._progressText = new PIXI.Text(' ', {
fontSize: '30px',
fontFamily: 'Arial',
fill: '#FFFFFF',
align: 'center',
});
this._loadingScreen.addChild(this._progressText);
if (loadingScreenSetup && loadingScreenSetup.showGDevelopSplash) {
this._madeWithText = new PIXI.Text('Made with', {
fontSize: '30px',
fontFamily: 'Arial',
fill: '#FFFFFF',
align: 'center',
});
this._madeWithText.position.y = this._pixiRenderer.height / 2 - 130;
this._websiteText = new PIXI.Text('gdevelop-app.com', {
fontSize: '30px',
fontFamily: 'Arial',
fill: '#FFFFFF',
align: 'center',
});
this._websiteText.position.y = this._pixiRenderer.height / 2 + 100;
this._splashImage = new PIXI.Sprite.fromImage(gdjs.splashImage);
this._splashImage.position.x = this._pixiRenderer.width / 2;
this._splashImage.position.y = this._pixiRenderer.height / 2;
this._splashImage.anchor.x = 0.5;
this._splashImage.anchor.y = 0.5;
this._splashImage.scale.x = this._pixiRenderer.width / 800;
this._splashImage.scale.y = this._pixiRenderer.width / 800;
this._loadingScreen.addChild(this._splashImage);
this._loadingScreen.addChild(this._madeWithText);
this._loadingScreen.addChild(this._websiteText);
}
};
gdjs.LoadingScreenRenderer = gdjs.LoadingScreenPixiRenderer; //Register the class to let the engine use it.
gdjs.LoadingScreenPixiRenderer.prototype.render = function(percent) {
if (!this._pixiRenderer) {
return;
}
var screenBorder = 10;
if (this._madeWithText) {
this._madeWithText.position.x =
this._pixiRenderer.width / 2 - this._madeWithText.width / 2;
this._madeWithText.position.y =
this._pixiRenderer.height / 2 -
this._splashImage.height / 2 -
this._madeWithText.height -
20;
}
if (this._websiteText) {
this._websiteText.position.x =
this._pixiRenderer.width - this._websiteText.width - screenBorder;
this._websiteText.position.y =
this._pixiRenderer.height - this._websiteText.height - screenBorder;
}
this._progressText.text = percent + '%';
this._progressText.position.x = screenBorder;
this._progressText.position.y =
this._pixiRenderer.height - this._progressText.height - screenBorder;
this._pixiRenderer.render(this._loadingScreen);
};
gdjs.LoadingScreenPixiRenderer.prototype.unload = function() {
// Nothing to do
};

View File

@ -0,0 +1,120 @@
// @ts-check
/**
* Contains tools related to PIXI filters handling.
*/
gdjs.PixiFiltersTools = {};
gdjs.PixiFiltersTools.clampValue = function(value, min, max) { return Math.max(min, Math.min(max, value)); };
gdjs.PixiFiltersTools.clampKernelSize = function(value) { return (([5, 7, 9, 11, 13, 15].indexOf(value) !== -1) ? value : 5); };
/** Object.<string, gdjsPixiFiltersToolsFilterCreator> */
gdjs.PixiFiltersTools._filterCreators = {};
/**
* Enable an effect.
* @param {gdjsPixiFiltersToolsFilter} filter The filter to enable or disable
* @param {boolean} value Set to true to enable, false to disable
*/
gdjs.PixiFiltersTools.enableEffect = function(filter, value) {
filter.pixiFilter.enabled = value;
}
/**
* Check if an effect is enabled.
* @param {gdjsPixiFiltersToolsFilter} filter The filter to be checked
* @return {boolean} true if the filter is enabled
*/
gdjs.PixiFiltersTools.isEffectEnabled = function(filter) {
return filter.pixiFilter.enabled;
}
/**
* Return the creator for the filter with the given name, if any.
* @param {string} filterName The name of the filter to get
* @return {?gdjsPixiFiltersToolsFilterCreator} The filter creator, if any (null otherwise).
*/
gdjs.PixiFiltersTools.getFilterCreator = function(filterName) {
if (gdjs.PixiFiltersTools._filterCreators.hasOwnProperty(filterName))
return gdjs.PixiFiltersTools._filterCreators[filterName];
return null;
}
/**
* Register a new PIXI filter creator, to be used by GDJS.
* @param {string} filterName The name of the filter to get
* @param {gdjsPixiFiltersToolsFilterCreator} filterCreator The object used to create the filter.
*/
gdjs.PixiFiltersTools.registerFilterCreator = function(filterName, filterCreator) {
if (gdjs.PixiFiltersTools._filterCreators.hasOwnProperty(filterName))
console.warn("Filter \"" + filterName + "\" was already registered in gdjs.PixiFiltersTools. Replacing it with the new one.");
gdjs.PixiFiltersTools._filterCreators[filterName] = filterCreator;
}
// Type definitions:
/**
* Function to call to create the PIXI filter used at runtime
* @callback gdjsPixiFiltersToolsFilterCreatorMakePIXIFilter
* @param {gdjs.Layer} layer
* @param {Object} effectData
* @returns {Object}
*/
/**
* The function to be called to update the filter at every frame
* @callback gdjsPixiFiltersToolsUpdate
* @param {Object} filter
* @param {gdjs.Layer} layer
* @returns {Object}
*/
/**
* The function to be called to update a parameter (with a number)
* @callback gdjsPixiFiltersToolsUpdateDoubleParameter
* @param {Object} filter
* @param {string} parameterName
* @param {number} value
* @returns {void}
*/
/**
* The function to be called to update a parameter (with a string)
* @callback gdjsPixiFiltersToolsUpdateStringParameter
* @param {Object} filter
* @param {string} parameterName
* @param {string} value
* @returns {void}
*/
/**
* The function to be called to update a parameter (with a boolean)
* @callback gdjsPixiFiltersToolsUpdateBooleanParameter
* @param {Object} filter
* @param {string} parameterName
* @param {boolean} value
* @returns {void}
*/
/**
* A wrapper allowing to create a PIXI filter and update it using a common interface
* @typedef gdjsPixiFiltersToolsFilterCreator
* @type {Object}
* @property {gdjsPixiFiltersToolsFilterCreatorMakePIXIFilter} makePIXIFilter Function to call to create the filter
* @property {gdjsPixiFiltersToolsUpdate} update The function to be called to update the filter at every frame
* @property {gdjsPixiFiltersToolsUpdateDoubleParameter} updateDoubleParameter The function to be called to update a parameter (with a number)
* @property {gdjsPixiFiltersToolsUpdateStringParameter} updateStringParameter The function to be called to update a parameter (with a string)
* @property {gdjsPixiFiltersToolsUpdateBooleanParameter} updateBooleanParameter The function to be called to update a parameter (with a boolean)
*/
/**
* The type of a filter used to manipulate a Pixi filter.
* @typedef gdjsPixiFiltersToolsFilter
* @type {Object}
* @property {any} pixiFilter The PIXI filter
* @property {gdjsPixiFiltersToolsUpdate} update The function to be called to update the filter at every frame
* @property {gdjsPixiFiltersToolsUpdateDoubleParameter} updateDoubleParameter The function to be called to update a parameter (with a number)
* @property {gdjsPixiFiltersToolsUpdateStringParameter} updateStringParameter The function to be called to update a parameter (with a string)
* @property {gdjsPixiFiltersToolsUpdateBooleanParameter} updateBooleanParameter The function to be called to update a parameter (with a boolean)
*/

View File

@ -0,0 +1,174 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* PixiImageManager loads and stores textures that can be used by the Pixi.js renderers.
*
* @class PixiImageManager
* @memberof gdjs
* @param {Object} resources The resources data of the game.
*/
gdjs.PixiImageManager = function(resources)
{
this._resources = resources;
// The invalid texture is a 8x8 PNG file filled with magenta (#ff00ff), to be
// easily spotted if rendered on screen.
this._invalidTexture = PIXI.Texture.from("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAFElEQVQoU2P8z/D/PwMewDgyFAAApMMX8Zi0uXAAAAAASUVORK5CYIIA");
this._loadedTextures = new Hashtable();
};
gdjs.ImageManager = gdjs.PixiImageManager; //Register the class to let the engine use it.
/**
* Return the PIXI texture associated to the specified resource name.
* Returns a placeholder texture if not found.
* @param {string} resourceName The name of the resource
* @returns {PIXI.Texture} The requested texture, or a placeholder if not found.
*/
gdjs.PixiImageManager.prototype.getPIXITexture = function(resourceName) {
if ( this._loadedTextures.containsKey(resourceName) ) {
return this._loadedTextures.get(resourceName);
}
if ( resourceName === "" ) {
return this._invalidTexture;
}
//Texture is not loaded, load it now from the resources list.
if ( this._resources ) {
var texture = null;
for(var i = 0, len = this._resources.length;i<len;++i) {
var res = this._resources[i];
if (res.name === resourceName && res.kind === "image") {
texture = PIXI.Texture.fromImage(res.file);
break;
}
}
if ( texture !== null ) {
console.log("Loaded texture for resource \""+resourceName+"\".");
this._loadedTextures.put(resourceName, texture);
return texture;
}
}
console.warn("Unable to find texture for resource \""+resourceName+"\".");
return this._invalidTexture;
};
/**
* Return the PIXI video texture associated to the specified resource name.
* Returns a placeholder texture if not found.
* @param {string} resourceName The name of the resource to get.
*/
gdjs.PixiImageManager.prototype.getPIXIVideoTexture = function(resourceName) {
if ( this._loadedTextures.containsKey(resourceName) ) {
return this._loadedTextures.get(resourceName);
}
if ( resourceName === "" ) {
return this._invalidTexture;
}
//Texture is not loaded, load it now from the resources list.
if ( this._resources ) {
var texture = null;
for(var i = 0, len = this._resources.length;i<len;++i) {
var res = this._resources[i];
if (res.name === resourceName && res.kind === "video") {
texture = PIXI.Texture.fromVideo(res.file);
break;
}
}
if ( texture !== null ) {
console.log("Loaded video texture for resource \""+resourceName+"\".");
this._loadedTextures.put(resourceName, texture);
return texture;
}
}
console.warn("Unable to find video texture for resource \""+resourceName+"\".");
return this._invalidTexture;
};
/**
* Return a PIXI texture which can be used as a placeholder when no
* suitable texture can be found.
*/
gdjs.PixiImageManager.prototype.getInvalidPIXITexture = function() {
return this._invalidTexture;
};
/**
* Load the specified resources, so that textures are loaded and can then be
* used by calling `getPIXITexture`.
* @param onProgress Callback called each time a new file is loaded.
* @param onComplete Callback called when loading is done.
* @param resources The resources to be loaded. If not specified, will load the resources
* specified in the PixiImageManager constructor.
*/
gdjs.PixiImageManager.prototype.loadTextures = function(onProgress, onComplete, resources) {
resources = resources || this._resources;
//Construct the list of files to be loaded.
//For one loaded file, it can have one or more resources
//that use it.
var files = {};
for(var i = 0, len = resources.length;i<len;++i) {
var res = resources[i];
if ( res.file && res.kind === "image" ) {
if (this._loadedTextures.containsKey(res.name)) {
console.log("Texture \"" + res.name + "\" is already loaded.");
continue;
}
files[res.file] = files[res.file] ? files[res.file].concat(res) : [res];
}
}
var totalCount = Object.keys(files).length;
if (totalCount === 0)
return onComplete(totalCount); //Nothing to load.
var loadingCount = 0;
var loader = PIXI.loader;
var that = this;
loader.once('complete', function(loader, loadedFiles) {
//Store the loaded textures so that they are ready to use.
for (var file in loadedFiles) {
if (loadedFiles.hasOwnProperty(file)) {
if (!files.hasOwnProperty(file)) continue;
files[file].forEach(function(res) {
that._loadedTextures.put(res.name, loadedFiles[file].texture);
if (!res.smoothed) {
loadedFiles[file].texture.baseTexture.scaleMode =
PIXI.SCALE_MODES.NEAREST;
}
});
}
}
onComplete(totalCount);
});
loader.on('progress', function() {
loadingCount++;
onProgress(loadingCount, totalCount);
});
for (var file in files) {
if (files.hasOwnProperty(file)) {
loader.add(file, file);
}
}
loader.load();
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,496 @@
/**
* The renderer for a gdjs.RuntimeGame using Pixi.js.
* @class RuntimeGamePixiRenderer
* @memberof gdjs
* @param {gdjs.RuntimeGame} game The game that is being rendered
* @param {boolean} forceFullscreen If fullscreen should be always activated
*/
gdjs.RuntimeGamePixiRenderer = function(game, forceFullscreen) {
this._game = game;
this._isFullPage = true; //Used to track if the canvas is displayed on the full page.
this._isFullscreen = false; //Used to track if the window is displayed as fullscreen (see setFullscreen method).
this._forceFullscreen = forceFullscreen; //If set to true, the canvas will always be displayed as fullscreen, even if _isFullscreen == false.
/** @type {PIXI.SystemRenderer} */
this._pixiRenderer = null;
this._canvasWidth = 0; // Current width of the canvas (might be scaled down/up compared to renderer)
this._canvasHeight = 0; // Current height of the canvas (might be scaled down/up compared to renderer)
this._keepRatio = true;
this._marginLeft = this._marginTop = this._marginRight = this._marginBottom = 0;
};
gdjs.RuntimeGameRenderer = gdjs.RuntimeGamePixiRenderer; //Register the class to let the engine use it.
/**
* Create a standard canvas inside canvasArea.
*
*/
gdjs.RuntimeGamePixiRenderer.prototype.createStandardCanvas = function(
parentElement
) {
//This prevents flickering on some mobile devices
PIXI.glCore.VertexArrayObject.FORCE_NATIVE = true;
//Create the renderer and setup the rendering area
//"preserveDrawingBuffer: true" is needed to avoid flickering and background issues on some mobile phones (see #585 #572 #566 #463)
this._pixiRenderer = PIXI.autoDetectRenderer(
this._game.getGameResolutionWidth(),
this._game.getGameResolutionHeight(),
{
preserveDrawingBuffer: true,
antialias: false,
}
);
parentElement.appendChild(this._pixiRenderer.view); // add the renderer view element to the DOM
this._pixiRenderer.view.style['position'] = 'absolute';
this._pixiRenderer.view.tabindex = '1'; //Ensure that the canvas has the focus.
this._resizeCanvas();
// Handle scale mode
if (this._game.getScaleMode() === 'nearest') {
this._pixiRenderer.view.style['image-rendering'] = '-moz-crisp-edges';
this._pixiRenderer.view.style['image-rendering'] =
'-webkit-optimize-contrast';
this._pixiRenderer.view.style['image-rendering'] = '-webkit-crisp-edges';
this._pixiRenderer.view.style['image-rendering'] = 'pixelated';
}
//Handle resize
var that = this;
window.addEventListener('resize', function() {
that._game.onWindowInnerSizeChanged();
that._resizeCanvas();
that._game._notifySceneForResize = true;
});
return this._pixiRenderer;
};
gdjs.RuntimeGamePixiRenderer.getWindowInnerWidth = function() {
return typeof window !== 'undefined' ? window.innerWidth : 800;
};
gdjs.RuntimeGamePixiRenderer.getWindowInnerHeight = function() {
return typeof window !== 'undefined' ? window.innerHeight : 800;
};
/**
* Update the game renderer size according to the "game resolution".
* Called when game resolution changes.
*
* Note that if the canvas is fullscreen, it won't be resized, but when going back to
* non fullscreen mode, the requested size will be used.
*/
gdjs.RuntimeGamePixiRenderer.prototype.updateRendererSize = function() {
this._resizeCanvas();
};
/**
* Resize the renderer (the "game resolution") and the canvas (which can be larger
* or smaller to fill the page, with optional margins).
*
* @private
*/
gdjs.RuntimeGamePixiRenderer.prototype._resizeCanvas = function() {
// Set the Pixi renderer size to the game size.
// There is no "smart" resizing to be done here: the rendering of the game
// should be done with the size set on the game.
if (
this._pixiRenderer.width !== this._game.getGameResolutionWidth() ||
this._pixiRenderer.height !== this._game.getGameResolutionHeight()
) {
this._pixiRenderer.resize(
this._game.getGameResolutionWidth(),
this._game.getGameResolutionHeight()
);
}
// Set the canvas size.
// Resizing is done according to the settings. This is a "CSS" resize
// only, so won't create visual artifacts during the rendering.
var isFullPage =
this._forceFullscreen || this._isFullPage || this._isFullscreen;
var canvasWidth = this._game.getGameResolutionWidth();
var canvasHeight = this._game.getGameResolutionHeight();
var maxWidth = window.innerWidth - this._marginLeft - this._marginRight;
var maxHeight = window.innerHeight - this._marginTop - this._marginBottom;
if (maxWidth < 0) maxWidth = 0;
if (maxHeight < 0) maxHeight = 0;
if (isFullPage && !this._keepRatio) {
canvasWidth = maxWidth;
canvasHeight = maxHeight;
} else if (
(isFullPage && this._keepRatio) ||
canvasWidth > maxWidth ||
canvasHeight > maxHeight
) {
var factor = maxWidth / canvasWidth;
if (canvasHeight * factor > maxHeight) factor = maxHeight / canvasHeight;
canvasWidth *= factor;
canvasHeight *= factor;
}
this._pixiRenderer.view.style['top'] =
this._marginTop + (maxHeight - canvasHeight) / 2 + 'px';
this._pixiRenderer.view.style['left'] =
this._marginLeft + (maxWidth - canvasWidth) / 2 + 'px';
this._pixiRenderer.view.style.width = canvasWidth + 'px';
this._pixiRenderer.view.style.height = canvasHeight + 'px';
// Store the canvas size for fast access to it.
this._canvasWidth = canvasWidth;
this._canvasHeight = canvasHeight;
};
/**
* Set if the aspect ratio must be kept when the game canvas is resized to fill
* the page.
*/
gdjs.RuntimeGamePixiRenderer.prototype.keepAspectRatio = function(enable) {
if (this._keepRatio === enable) return;
this._keepRatio = enable;
this._resizeCanvas();
this._game._notifySceneForResize = true;
};
/**
* Change the margin that must be preserved around the game canvas.
*/
gdjs.RuntimeGamePixiRenderer.prototype.setMargins = function(
top,
right,
bottom,
left
) {
if (
this._marginTop === top &&
this._marginRight === right &&
this._marginBottom === bottom &&
this._marginLeft === left
)
return;
this._marginTop = top;
this._marginRight = right;
this._marginBottom = bottom;
this._marginLeft = left;
this._resizeCanvas();
this._game._notifySceneForResize = true;
};
/**
* Update the window size, if possible.
* @param {number} width The new width, in pixels.
* @param {number} height The new height, in pixels.
*/
gdjs.RuntimeGamePixiRenderer.prototype.setWindowSize = function(width, height) {
var electron = this.getElectron();
if (electron) {
// Use Electron BrowserWindow API
var browserWindow = electron.remote.getCurrentWindow();
if (browserWindow) {
browserWindow.setContentSize(width, height);
}
} else {
console.warn("Window size can't be changed on this platform.");
}
};
/**
* Center the window on screen.
*/
gdjs.RuntimeGamePixiRenderer.prototype.centerWindow = function() {
var electron = this.getElectron();
if (electron) {
// Use Electron BrowserWindow API
var browserWindow = electron.remote.getCurrentWindow();
if (browserWindow) {
browserWindow.center();
}
} else {
// Not supported
}
};
/**
* De/activate fullscreen for the game.
*/
gdjs.RuntimeGamePixiRenderer.prototype.setFullScreen = function(enable) {
if (this._forceFullscreen) return;
if (this._isFullscreen !== enable) {
this._isFullscreen = !!enable;
var electron = this.getElectron();
if (electron) {
// Use Electron BrowserWindow API
var browserWindow = electron.remote.getCurrentWindow();
if (browserWindow) {
browserWindow.setFullScreen(this._isFullscreen);
}
} else {
// Use HTML5 Fullscreen API
//TODO: Do this on a user gesture, otherwise most browsers won't activate fullscreen
if (this._isFullscreen) {
if (document.documentElement.requestFullScreen) {
document.documentElement.requestFullScreen();
} else if (document.documentElement.mozRequestFullScreen) {
document.documentElement.mozRequestFullScreen();
} else if (document.documentElement.webkitRequestFullScreen) {
document.documentElement.webkitRequestFullScreen();
}
} else {
if (document.cancelFullScreen) {
document.cancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
}
}
}
this._resizeCanvas();
this._notifySceneForResize = true;
}
};
/**
* Add the standard events handler.
*/
gdjs.RuntimeGamePixiRenderer.prototype.bindStandardEvents = function(
manager,
window,
document
) {
var renderer = this._pixiRenderer;
var canvas = renderer.view;
//Translate an event (mouse or touch) made on the canvas on the page
//to game coordinates.
var that = this;
function getEventPosition(e) {
var pos = [0, 0];
if (e.pageX) {
pos[0] = e.pageX - canvas.offsetLeft;
pos[1] = e.pageY - canvas.offsetTop;
} else {
pos[0] =
e.clientX +
document.body.scrollLeft +
document.documentElement.scrollLeft -
canvas.offsetLeft;
pos[1] =
e.clientY +
document.body.scrollTop +
document.documentElement.scrollTop -
canvas.offsetTop;
}
//Handle the fact that the game is stretched to fill the canvas.
pos[0] *= that._game.getGameResolutionWidth() / (that._canvasWidth || 1);
pos[1] *= that._game.getGameResolutionHeight() / (that._canvasHeight || 1);
return pos;
}
//Some browsers lacks definition of some variables used to do calculations
//in getEventPosition. They are defined to 0 as they are useless.
(function ensureOffsetsExistence() {
if (isNaN(canvas.offsetLeft)) {
canvas.offsetLeft = 0;
canvas.offsetTop = 0;
}
if (isNaN(document.body.scrollLeft)) {
document.body.scrollLeft = 0;
document.body.scrollTop = 0;
}
if (
document.documentElement === undefined ||
document.documentElement === null
) {
document.documentElement = {};
}
if (isNaN(document.documentElement.scrollLeft)) {
document.documentElement.scrollLeft = 0;
document.documentElement.scrollTop = 0;
}
if (isNaN(canvas.offsetLeft)) {
canvas.offsetLeft = 0;
canvas.offsetTop = 0;
}
})();
//Keyboard
document.onkeydown = function(e) {
manager.onKeyPressed(e.keyCode);
};
document.onkeyup = function(e) {
manager.onKeyReleased(e.keyCode);
};
//Mouse
renderer.view.onmousemove = function(e) {
var pos = getEventPosition(e);
manager.onMouseMove(pos[0], pos[1]);
};
renderer.view.onmousedown = function(e) {
manager.onMouseButtonPressed(
e.button === 2
? gdjs.InputManager.MOUSE_RIGHT_BUTTON
: e.button === 1
? gdjs.InputManager.MOUSE_MIDDLE_BUTTON
: gdjs.InputManager.MOUSE_LEFT_BUTTON
);
if (window.focus !== undefined) window.focus();
return false;
};
renderer.view.onmouseup = function(e) {
manager.onMouseButtonReleased(
e.button === 2
? gdjs.InputManager.MOUSE_RIGHT_BUTTON
: e.button === 1
? gdjs.InputManager.MOUSE_MIDDLE_BUTTON
: gdjs.InputManager.MOUSE_LEFT_BUTTON
);
return false;
};
window.addEventListener(
'click',
function(e) {
if (window.focus !== undefined) window.focus();
e.preventDefault();
return false;
},
false
);
renderer.view.oncontextmenu = function(event) {
event.preventDefault();
event.stopPropagation();
return false;
};
renderer.view.onmousewheel = function(event) {
manager.onMouseWheel(event.wheelDelta);
};
//Touches
//Also simulate mouse events when receiving touch events
window.addEventListener('touchmove', function(e) {
e.preventDefault();
if (e.changedTouches) {
for (var i = 0; i < e.changedTouches.length; ++i) {
var pos = getEventPosition(e.changedTouches[i]);
manager.onTouchMove(e.changedTouches[i].identifier, pos[0], pos[1]);
}
}
});
window.addEventListener('touchstart', function(e) {
e.preventDefault();
if (e.changedTouches) {
for (var i = 0; i < e.changedTouches.length; ++i) {
var pos = getEventPosition(e.changedTouches[i]);
manager.onTouchStart(e.changedTouches[i].identifier, pos[0], pos[1]);
}
}
return false;
});
window.addEventListener('touchend', function(e) {
e.preventDefault();
if (e.changedTouches) {
for (var i = 0; i < e.changedTouches.length; ++i) {
var pos = getEventPosition(e.changedTouches[i]);
manager.onTouchEnd(e.changedTouches[i].identifier);
}
}
return false;
});
};
gdjs.RuntimeGamePixiRenderer.prototype.setWindowTitle = function(title) {
if (typeof document !== 'undefined') document.title = title;
};
gdjs.RuntimeGamePixiRenderer.prototype.getWindowTitle = function() {
return typeof document !== 'undefined' ? document.title : '';
};
gdjs.RuntimeGamePixiRenderer.prototype.startGameLoop = function(fn) {
requestAnimationFrame(gameLoop);
var oldTime = 0;
function gameLoop(time) {
var dt = oldTime ? time - oldTime : 0;
oldTime = time;
if (fn(dt)) requestAnimationFrame(gameLoop);
}
};
gdjs.RuntimeGamePixiRenderer.prototype.getPIXIRenderer = function() {
return this._pixiRenderer;
};
/**
* Open the given URL in the system browser (or a new tab)
*/
gdjs.RuntimeGamePixiRenderer.prototype.openURL = function(url) {
// Try to detect the environment to use the most adapted
// way of opening an URL.
if (typeof Cocoon !== 'undefined' && Cocoon.App && Cocoon.App.openURL) {
Cocoon.App.openURL(url);
} else if (typeof window !== 'undefined') {
var target = window.cordova ? '_system' : '_blank';
window.open(url, target);
}
};
/**
* Close the game, if applicable
*/
gdjs.RuntimeGamePixiRenderer.prototype.stopGame = function() {
// Try to detect the environment to use the most adapted
// way of closing the app
var electron = this.getElectron();
if (electron) {
var browserWindow = electron.remote.getCurrentWindow();
if (browserWindow) {
browserWindow.close();
}
} else if (
typeof navigator !== 'undefined' &&
navigator.app &&
navigator.app.exitApp
) {
navigator.app.exitApp();
}
// HTML5 games on mobile/browsers don't have a way to close their window/page.
};
/**
* Get the canvas DOM element.
*/
gdjs.RuntimeGamePixiRenderer.prototype.getCanvas = function() {
return this._pixiRenderer.view;
};
/**
* Check if the device supports WebGL.
* @returns {boolean} true if WebGL is supported
*/
gdjs.RuntimeGamePixiRenderer.prototype.isWebGLSupported = function() {
return this._pixiRenderer.type === PIXI.RENDERER_TYPE.WEBGL;
};
/**
* Get the electron module, if running as a electron renderer process.
*/
gdjs.RuntimeGamePixiRenderer.prototype.getElectron = function() {
if (typeof require !== 'undefined') {
return require('electron');
}
return null;
};

View File

@ -0,0 +1,87 @@
gdjs.RuntimeScenePixiRenderer = function(runtimeScene, runtimeGameRenderer) {
this._pixiRenderer = runtimeGameRenderer
? runtimeGameRenderer.getPIXIRenderer()
: null;
this._runtimeScene = runtimeScene;
this._pixiContainer = new PIXI.Container(); //The Container meant to contains all pixi objects of the scene.
};
gdjs.RuntimeSceneRenderer = gdjs.RuntimeScenePixiRenderer; //Register the class to let the engine use it.
gdjs.RuntimeScenePixiRenderer.prototype.onGameResolutionResized = function() {
if (!this._pixiRenderer) return;
var runtimeGame = this._runtimeScene.getGame();
this._pixiContainer.scale.x =
this._pixiRenderer.width / runtimeGame.getGameResolutionWidth();
this._pixiContainer.scale.y =
this._pixiRenderer.height / runtimeGame.getGameResolutionHeight();
};
gdjs.RuntimeScenePixiRenderer.prototype.render = function() {
if (!this._pixiRenderer) return;
// this._renderProfileText(); //Uncomment to display profiling times
// render the PIXI container of the scene
this._pixiRenderer.backgroundColor = this._runtimeScene.getBackgroundColor();
this._pixiRenderer.render(this._pixiContainer);
};
gdjs.RuntimeScenePixiRenderer.prototype._renderProfileText = function() {
if (!this._runtimeScene.getProfiler()) return;
if (!this._profilerText) {
this._profilerText = new PIXI.Text(" ", {
align: "left",
stroke: "#FFF",
strokeThickness: 1
});
this._pixiContainer.addChild(this._profilerText);
}
var average = this._runtimeScene.getProfiler().getFramesAverageMeasures();
var outputs = [];
gdjs.Profiler.getProfilerSectionTexts("All", average, outputs);
this._profilerText.text = outputs.join("\n");
};
gdjs.RuntimeScenePixiRenderer.prototype.renderDebugDraw = function(instances, layersCameraCoordinates) {
if (!this._debugDraw) {
this._debugDraw = new PIXI.Graphics();
this._pixiContainer.addChild(this._debugDraw);
}
/** @type PIXI.Graphics */
var debugDraw = this._debugDraw;
debugDraw.clear();
debugDraw.beginFill(0x6868e8);
debugDraw.lineStyle(1, 0x6868e8, 1);
debugDraw.fillAlpha = 0.1;
debugDraw.alpha = 0.8;
for(var i = 0;i < instances.length;i++) {
var object = instances[i];
var cameraCoords = layersCameraCoordinates[object.getLayer()];
var rendererObject = object.getRendererObject();
if (!cameraCoords || !rendererObject) continue;
var aabb = object.getAABB();
debugDraw.drawRect(aabb.min[0], aabb.min[1], aabb.max[0] - aabb.min[0], aabb.max[1] - aabb.min[1]);
}
debugDraw.endFill();
};
gdjs.RuntimeScenePixiRenderer.prototype.hideCursor = function() {
this._pixiRenderer.view.style.cursor = "none";
};
gdjs.RuntimeScenePixiRenderer.prototype.showCursor = function() {
this._pixiRenderer.view.style.cursor = "";
};
gdjs.RuntimeScenePixiRenderer.prototype.getPIXIContainer = function() {
return this._pixiContainer;
};

View File

@ -0,0 +1,137 @@
/**
* The renderer for a gdjs.SpriteRuntimeObject using Pixi.js.
* @class SpriteRuntimeObjectPixiRenderer
* @memberof gdjs
* @param {gdjs.SpriteRuntimeObject} runtimeObject The object
* @param {gdjs.RuntimeScene} runtimeScene The scene
*/
gdjs.SpriteRuntimeObjectPixiRenderer = function(runtimeObject, runtimeScene)
{
/** @type gdjs.SpriteRuntimeObject */
this._object = runtimeObject;
this._spriteDirty = true;
this._textureDirty = true;
if ( this._sprite === undefined )
this._sprite = new PIXI.Sprite(runtimeScene.getGame().getImageManager().getInvalidPIXITexture());
var layer = runtimeScene.getLayer("");
if (layer) layer.getRenderer().addRendererObject(this._sprite, runtimeObject.getZOrder());
}
gdjs.SpriteRuntimeObjectRenderer = gdjs.SpriteRuntimeObjectPixiRenderer; //Register the class to let the engine use it.
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.getRendererObject = function() {
return this._sprite;
};
/**
* Update the internal PIXI.Sprite position, angle...
*/
gdjs.SpriteRuntimeObjectPixiRenderer.prototype._updatePIXISprite = function() {
if (this._object._animationFrame !== null) {
this._sprite.anchor.x = this._object._animationFrame.center.x/this._sprite.texture.frame.width;
this._sprite.anchor.y = this._object._animationFrame.center.y/this._sprite.texture.frame.height;
this._sprite.position.x = this._object.x + (this._object._animationFrame.center.x - this._object._animationFrame.origin.x)*Math.abs(this._object._scaleX);
this._sprite.position.y = this._object.y + (this._object._animationFrame.center.y - this._object._animationFrame.origin.y)*Math.abs(this._object._scaleY);
this._sprite.rotation = gdjs.toRad(this._object.angle);
this._sprite.visible = !this._object.hidden;
this._sprite.blendMode = this._object._blendMode;
this._sprite.alpha = this._sprite.visible ? this._object.opacity/255 : 0; //TODO: Workaround not working property in PIXI.js
this._sprite.scale.x = this._object._scaleX;
this._sprite.scale.y = this._object._scaleY;
this._cachedWidth = Math.abs(this._sprite.width);
this._cachedHeight = Math.abs(this._sprite.height);
} else {
this._sprite.visible = false;
this._sprite.alpha = 0;
this._cachedWidth = 0;
this._cachedHeight = 0;
}
this._spriteDirty = false;
};
/**
* Call this to make sure the sprite is ready to be rendered.
*/
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.ensureUpToDate = function() {
if ( this._spriteDirty ) this._updatePIXISprite();
};
/**
* Update the internal texture of the PIXI sprite.
*/
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.updateFrame = function(animationFrame) {
this._spriteDirty = true;
this._sprite.texture = animationFrame.texture;
};
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.update = function() {
this._spriteDirty = true;
}
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.updateX = function() {
this._sprite.position.x = this._object.x + (this._object._animationFrame.center.x - this._object._animationFrame.origin.x)*Math.abs(this._object._scaleX);
}
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.updateY = function() {
this._sprite.position.y = this._object.y + (this._object._animationFrame.center.y - this._object._animationFrame.origin.y)*Math.abs(this._object._scaleY);
}
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.updateAngle = function() {
this._sprite.rotation = gdjs.toRad(this._object.angle);
}
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.updateOpacity = function() {
//TODO: Workaround a not working property in PIXI.js:
this._sprite.alpha = this._sprite.visible ? this._object.opacity/255 : 0;
}
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.updateVisibility = function() {
this._sprite.visible = !this._object.hidden;
//TODO: Workaround a not working property in PIXI.js:
this._sprite.alpha = this._sprite.visible ? this._object.opacity/255 : 0;
}
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.setColor = function(rgbColor) {
var colors = rgbColor.split(";");
if ( colors.length < 3 ) return;
this._sprite.tint = "0x" + gdjs.rgbToHex(parseInt(colors[0], 10), parseInt(colors[1], 10), parseInt(colors[2], 10));
};
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.getColor = function() {
var rgb = PIXI.utils.hex2rgb(this._sprite.tint)
return Math.floor(rgb[0]*255) + ';' + Math.floor(rgb[1]*255) + ';' + Math.floor(rgb[2]*255);
}
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.getWidth = function() {
if ( this._spriteDirty ) this._updatePIXISprite();
return this._cachedWidth;
};
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.getHeight = function() {
if ( this._spriteDirty ) this._updatePIXISprite();
return this._cachedHeight;
};
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.getUnscaledWidth = function() {
return this._sprite.texture.frame.width;
};
gdjs.SpriteRuntimeObjectPixiRenderer.prototype.getUnscaledHeight = function() {
return this._sprite.texture.frame.height;
};
gdjs.SpriteRuntimeObjectPixiRenderer.getAnimationFrame = function(imageManager, imageName) {
return imageManager.getPIXITexture(imageName);
};
gdjs.SpriteRuntimeObjectPixiRenderer.getAnimationFrameWidth = function(pixiTexture) {
return pixiTexture.width;
};
gdjs.SpriteRuntimeObjectPixiRenderer.getAnimationFrameHeight = function(pixiTexture) {
return pixiTexture.height;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,430 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Polygon represents a polygon which can be used to create collisions masks for RuntimeObject.
*
* @memberof gdjs
* @class Polygon
*/
gdjs.Polygon = function()
{
/**
* The vertices of the polygon
* @member {Array}
*/
this.vertices = [];
/**
* The edges of the polygon. This property is only valid after calling
* computeEdges, and remains valid until vertices are modified.
* @member {Array}
*/
this.edges = [];
/**
* The center of the polygon. This property is only valid after calling
* computeCenter, and remains valid until vertices are modified.
* @member {Array}
*/
this.center = [0,0];
};
gdjs.Polygon.prototype.move = function(x,y) {
for(var i = 0, len = this.vertices.length;i<len;++i) {
this.vertices[i][0] += x;
this.vertices[i][1] += y;
}
};
gdjs.Polygon.prototype.rotate = function(angle) {
var t, cosa = Math.cos(-angle),
sina = Math.sin(-angle); //We want a clockwise rotation
for (var i = 0, len = this.vertices.length;i<len;++i) {
t = this.vertices[i][0];
this.vertices[i][0] = t*cosa + this.vertices[i][1]*sina;
this.vertices[i][1] = -t*sina + this.vertices[i][1]*cosa;
}
};
gdjs.Polygon.prototype.computeEdges = function() {
var v1, v2;
//Ensure edge array has the right size. ( And avoid recreating an edge array ).
while ( this.edges.length < this.vertices.length ) {
this.edges.push([0,0]);
}
if ( this.edges.length != this.vertices.length )
this.edges.length = this.vertices.length;
for (var i = 0, len = this.vertices.length;i<len;++i) {
v1 = this.vertices[i];
if ((i + 1) >= len) v2 = this.vertices[0];
else v2 = this.vertices[i + 1];
this.edges[i][0] = v2[0] - v1[0];
this.edges[i][1] = v2[1] - v1[1];
}
};
gdjs.Polygon.prototype.isConvex = function() {
this.computeEdges();
var edgesLen = this.edges.length;
if ( edgesLen < 3 ) {
return false;
}
var zProductIsPositive = (this.edges[0][0]*this.edges[0+1][1] - this.edges[0][1]*this.edges[0+1][0]) > 0;
for (var i = 1;i<edgesLen-1;++i) {
var zCrossProduct = this.edges[i][0]*this.edges[i+1][1] - this.edges[i][1]*this.edges[i+1][0];
if ( (zCrossProduct > 0) !== zProductIsPositive ) return false;
}
var lastZCrossProduct = this.edges[edgesLen-1][0]*this.edges[0][1] - this.edges[edgesLen-1][1]*this.edges[0][0];
if ( (lastZCrossProduct > 0) !== zProductIsPositive ) return false;
return true;
};
gdjs.Polygon.prototype.computeCenter = function() {
this.center[0] = 0;
this.center[1] = 0;
var len = this.vertices.length;
for (var i = 0;i<len;++i) {
this.center[0] += this.vertices[i][0];
this.center[1] += this.vertices[i][1];
}
this.center[0] /= len;
this.center[1] /= len;
return this.center;
};
gdjs.Polygon.createRectangle = function(width, height) {
var rect = new gdjs.Polygon();
rect.vertices.push([-width/2.0, -height/2.0]);
rect.vertices.push([+width/2.0, -height/2.0]);
rect.vertices.push([+width/2.0, +height/2.0]);
rect.vertices.push([-width/2.0, +height/2.0]);
return rect;
};
/**
* Do a collision test between two polygons.
* Please note that polygons must *convexes*!
*
* Uses <a href="http://en.wikipedia.org/wiki/Hyperplane_separation_theorem">Separating Axis Theorem </a>.<br>
* Based on <a href="http://www.codeproject.com/Articles/15573/2D-Polygon-Collision-Detection">this</a>
* and <a href="http://stackoverflow.com/questions/5742329/problem-with-collision-response-sat">this</a> article.
*
* @return {{collision: boolean, move_axis: Array<number>}} returnValue.collision is equal to true if polygons are overlapping
* @param {gdjs.Polygon} p1 The first polygon
* @param {gdjs.Polygon} p2 The second polygon
* @param {boolean | undefined} ignoreTouchingEdges If true, then edges that are touching each other, without the polygons actually overlapping, won't be considered in collision.
*/
gdjs.Polygon.collisionTest = function(p1, p2, ignoreTouchingEdges) {
//Algorithm core :
p1.computeEdges();
p2.computeEdges();
var edge = gdjs.Polygon.collisionTest._statics.edge;
var move_axis = gdjs.Polygon.collisionTest._statics.move_axis;
var result = gdjs.Polygon.collisionTest._statics.result;
var minDist = Number.MAX_VALUE;
edge[0] = 0;
edge[1] = 0;
edge[0] = 0;
edge[1] = 0;
result.collision = false;
result.move_axis[0] = 0;
result.move_axis[1] = 0;
//Iterate over all the edges composing the polygons
for (var i = 0, len1 = p1.vertices.length, len2 = p2.vertices.length; i < len1+len2; i++) {
if (i < len1) { // or <=
edge = p1.edges[i];
} else {
edge = p2.edges[i - len1];
}
var axis = gdjs.Polygon.collisionTest._statics.axis; //Get the axis to which polygons will be projected
axis[0] = -edge[1];
axis[1] = edge[0];
gdjs.Polygon.normalise(axis);
var minMaxA = gdjs.Polygon.collisionTest._statics.minMaxA;
var minMaxB = gdjs.Polygon.collisionTest._statics.minMaxB;
gdjs.Polygon.project(axis, p1, minMaxA); //Do projection on the axis.
gdjs.Polygon.project(axis, p2, minMaxB);
//If the projections on the axis do not overlap, then their is no collision
var dist = gdjs.Polygon.distance(minMaxA[0], minMaxA[1], minMaxB[0], minMaxB[1]);
if (dist > 0 || (dist === 0 && ignoreTouchingEdges)) {
result.collision = false;
result.move_axis[0] = 0;
result.move_axis[1] = 0;
return result;
}
var absDist = Math.abs(dist);
if (absDist < minDist) {
minDist = absDist;
move_axis[0] = axis[0];
move_axis[1] = axis[1];
}
}
result.collision = true;
//Ensure move axis is correctly oriented.
var p1Center = p1.computeCenter();
var p2Center = p2.computeCenter();
var d = [p1Center[0]-p2Center[0], p1Center[1]-p2Center[1]];
if (gdjs.Polygon.dotProduct(d, move_axis) < 0) {
move_axis[0] = -move_axis[0];
move_axis[1] = -move_axis[1];
}
//Add the magnitude to the move axis.
result.move_axis[0] = move_axis[0] * minDist;
result.move_axis[1] = move_axis[1] * minDist;
return result;
};
//Arrays and data structure that are (re)used by gdjs.Polygon.collisionTest to
//avoid any allocation.
gdjs.Polygon.collisionTest._statics = {
minMaxA: [0,0],
minMaxB: [0,0],
edge: [0,0],
axis: [0,0],
move_axis: [0,0],
result: {
collision:false,
move_axis:[0,0]
}
};
/**
* Do a raycast test.<br>
* Please note that the polygon must be <b>convex</b>!
*
* For some theory, check <a href="https://www.codeproject.com/Tips/862988/Find-the-Intersection-Point-of-Two-Line-Segments">Find the Intersection Point of Two Line Segments</a>.
*
* @param {gdjs.Polygon} poly The polygon to test
* @param {number} startX The raycast start point X
* @param {number} startY The raycast start point Y
* @param {number} endX The raycast end point X
* @param {number} endY The raycast end point Y
* @return A raycast result with the contact points and distances
*/
gdjs.Polygon.raycastTest = function(poly, startX, startY, endX, endY)
{
var result = gdjs.Polygon.raycastTest._statics.result;
result.collision = false;
if ( poly.vertices.length < 2 )
{
return result;
}
poly.computeEdges();
var p = gdjs.Polygon.raycastTest._statics.p;
var q = gdjs.Polygon.raycastTest._statics.q;
var r = gdjs.Polygon.raycastTest._statics.r;
var s = gdjs.Polygon.raycastTest._statics.s;
var minSqDist = Number.MAX_VALUE;
// Ray segment: p + t*r, with p = start and r = end - start
p[0] = startX;
p[1] = startY;
r[0] = endX - startX;
r[1] = endY - startY;
for(var i=0; i<poly.edges.length; i++)
{
// Edge segment: q + u*s
q[0] = poly.vertices[i][0];
q[1] = poly.vertices[i][1];
s[0] = poly.edges[i][0];
s[1] = poly.edges[i][1];
var deltaQP = gdjs.Polygon.raycastTest._statics.deltaQP;
deltaQP[0] = q[0] - p[0];
deltaQP[1] = q[1] - p[1];
var crossRS = gdjs.Polygon.crossProduct(r, s);
var t = gdjs.Polygon.crossProduct(deltaQP, s) / crossRS;
var u = gdjs.Polygon.crossProduct(deltaQP, r) / crossRS;
// Collinear
if ( Math.abs(crossRS) <= 0.0001 && Math.abs(gdjs.Polygon.crossProduct(deltaQP, r)) <= 0.0001 )
{
// Project the ray and the edge to work on floats, keeping linearity through t
var axis = gdjs.Polygon.raycastTest._statics.axis;
axis[0] = r[0];
axis[1] = r[1];
gdjs.Polygon.normalise(axis);
var rayA = 0;
var rayB = gdjs.Polygon.dotProduct(axis, r);
var edgeA = gdjs.Polygon.dotProduct(axis, deltaQP);
var edgeB = gdjs.Polygon.dotProduct(axis, [deltaQP[0] + s[0], deltaQP[1] + s[1]]);
// Get overlapping range
var minOverlap = Math.max(Math.min(rayA, rayB), Math.min(edgeA, edgeB));
var maxOverlap = Math.min(Math.max(rayA, rayB), Math.max(edgeA, edgeB));
if( minOverlap > maxOverlap ){
return result;
}
result.collision = true;
// Zero distance ray
if( rayB === 0 ){
result.closeX = startX;
result.closeY = startY;
result.closeSqDist = 0;
result.farX = startX;
result.farY = startY;
result.farSqDist = 0;
}
var t1 = minOverlap / Math.abs(rayB);
var t2 = maxOverlap / Math.abs(rayB);
result.closeX = startX + t1*r[0];
result.closeY = startY + t1*r[1];
result.closeSqDist = t1*t1*(r[0]*r[0] + r[1]*r[1]);
result.farX = startX + t2*r[0];
result.farY = startY + t2*r[1];
result.farSqDist = t2*t2*(r[0]*r[0] + r[1]*r[1]);
return result;
}
// One point intersection
else if ( crossRS !== 0 && 0<=t && t<=1 && 0<=u && u<=1 )
{
var x = p[0] + t*r[0];
var y = p[1] + t*r[1];
var sqDist = (x-startX)*(x-startX) + (y-startY)*(y-startY);
if ( sqDist < minSqDist )
{
if ( !result.collision ){
result.farX = x;
result.farY = y;
result.farSqDist = sqDist;
}
minSqDist = sqDist;
result.closeX = x;
result.closeY = y;
result.closeSqDist = sqDist;
result.collision = true;
}
else
{
result.farX = x;
result.farY = y;
result.farSqDist = sqDist;
}
}
}
return result;
};
gdjs.Polygon.raycastTest._statics = {
p: [0,0],
q: [0,0],
r: [0,0],
s: [0,0],
deltaQP: [0,0],
axis: [0,0],
result: {
collision: false,
closeX: 0,
closeY: 0,
closeSqDist: 0,
farX: 0,
farY: 0,
farSqDist: 0
}
}
//Tools functions :
gdjs.Polygon.normalise = function(v)
{
var len = Math.sqrt(v[0]*v[0] + v[1]*v[1]);
if (len != 0) {
v[0] /= len;
v[1] /= len;
}
}
gdjs.Polygon.dotProduct = function(a, b)
{
var dp = a[0]*b[0] + a[1]*b[1];
return dp;
}
gdjs.Polygon.crossProduct = function(a, b)
{
var cp = a[0]*b[1] - a[1]*b[0];
return cp;
}
gdjs.Polygon.project = function(axis, p, result)
{
var dp = gdjs.Polygon.dotProduct(axis, p.vertices[0]);
result[0] = dp;
result[1] = dp;
for (var i = 1, len = p.vertices.length; i < len; ++i) {
dp = gdjs.Polygon.dotProduct(axis, p.vertices[i]);
if (dp < result[0])
result[0] = dp;
else if (dp > result[1])
result[1] = dp;
}
}
gdjs.Polygon.distance = function(minA, maxA, minB, maxB)
{
if (minA < minB) return minB - maxA;
else return minA - maxB;
}
/**
* Check if a point is inside a polygon.
*
* Uses <a href="https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html">PNPOLY</a> by W. Randolph Franklin.
*
* @param {gdjs.Polygon} poly The polygon to test
* @param {number} x The point x coordinate
* @param {number} y The point y coordinate
* @return {boolean} true if the point is inside the polygon
*/
gdjs.Polygon.isPointInside = function(poly, x, y)
{
var inside = false;
var vi, vj;
for (var i = 0, j = poly.vertices.length-1; i < poly.vertices.length; j = i++) {
vi = poly.vertices[i];
vj = poly.vertices[j];
if ( ((vi[1]>y) != (vj[1]>y)) && (x < (vj[0]-vi[0]) * (y-vi[1]) / (vj[1]-vi[1]) + vi[0]) )
inside = !inside;
}
return inside;
};

View File

@ -0,0 +1,173 @@
/**
* A basic profiling tool that can be used to measure time spent in sections of the engine.
* @class Profiler
* @see gdjs.RuntimeGame
* @memberof gdjs
*/
gdjs.Profiler = function() {
this._framesMeasures = []; // All the measures for the last frames
this._currentFrameIndex = 0;
this._currentFrameMeasure = null; // The measures being done
this._currentSection = null; // The section being measured
this._maxFramesCount = 600;
this._framesCount = 0; // The number of frames that have been measured
while (this._framesMeasures.length < this._maxFramesCount) {
this._framesMeasures.push({
parent: null,
time: 0,
subsections: {},
});
}
this._getTimeNow =
window.performance && typeof window.performance.now === 'function'
? window.performance.now.bind(window.performance)
: Date.now;
};
gdjs.Profiler.prototype.beginFrame = function() {
this._currentFrameMeasure = {
parent: null,
time: 0,
lastStartTime: this._getTimeNow(),
subsections: {},
};
this._currentSection = this._currentFrameMeasure;
};
gdjs.Profiler.prototype.begin = function(sectionName) {
// Push the new section
var subsections = this._currentSection.subsections;
var subsection = (subsections[sectionName] = subsections[sectionName] || {
parent: this._currentSection,
time: 0,
lastStartTime: 0,
subsections: {},
});
this._currentSection = subsection;
// Start the timer
this._currentSection.lastStartTime = this._getTimeNow();
};
gdjs.Profiler.prototype.end = function(sectionName) {
// Stop the timer
var sectionTime = this._getTimeNow() - this._currentSection.lastStartTime;
this._currentSection.time = (this._currentSection.time || 0) + sectionTime;
// Pop the section
this._currentSection = this._currentSection.parent;
};
gdjs.Profiler.prototype.endFrame = function() {
if (this._currentSection.parent !== null) {
throw new Error(
'Mismatch in profiler, endFrame should be called on root section'
);
}
this.end();
this._framesCount++;
if (this._framesCount > this._maxFramesCount)
this._framesCount = this._maxFramesCount;
this._framesMeasures[this._currentFrameIndex] = this._currentFrameMeasure;
this._currentFrameIndex++;
if (this._currentFrameIndex >= this._maxFramesCount)
this._currentFrameIndex = 0;
};
gdjs.Profiler._addAverageSectionTimes = function(
section,
destinationSection,
totalCount,
i
) {
destinationSection.time =
(destinationSection.time || 0) + section.time / totalCount;
for (var sectionName in section.subsections) {
if (section.subsections.hasOwnProperty(sectionName)) {
var destinationSubsections = destinationSection.subsections;
var destinationSubsection = (destinationSubsections[
sectionName
] = destinationSubsections[sectionName] || {
parent: destinationSection,
time: 0,
subsections: {},
});
gdjs.Profiler._addAverageSectionTimes(
section.subsections[sectionName],
destinationSubsection,
totalCount,
i
);
}
}
};
/**
* Return the measures for all the section of the game during the frames
* captured.
*/
gdjs.Profiler.prototype.getFramesAverageMeasures = function() {
var framesAverageMeasures = {
parent: null,
time: 0,
subsections: {},
};
for (var i = 0; i < this._framesCount; ++i) {
gdjs.Profiler._addAverageSectionTimes(
this._framesMeasures[i],
framesAverageMeasures,
this._framesCount,
i
);
}
return framesAverageMeasures;
};
/**
* Get stats measured during the frames captured.
*/
gdjs.Profiler.prototype.getStats = function() {
return {
framesCount: this._framesCount,
};
};
/**
* Convert measures for a section into texts.
* Useful for ingame profiling.
*
* @param {string} sectionName The name of the section
* @param {s} profilerSection The section measures
* @param {*} outputs The array where to push the results
*/
gdjs.Profiler.getProfilerSectionTexts = function(
sectionName,
profilerSection,
outputs
) {
var percent =
profilerSection.parent && profilerSection.parent.time !== 0
? ((profilerSection.time / profilerSection.parent.time) * 100).toFixed(1)
: '100%';
var time = profilerSection.time.toFixed(2);
outputs.push(sectionName + ': ' + time + 'ms (' + percent + ')');
var subsectionsOutputs = [];
for (var subsectionName in profilerSection.subsections) {
if (profilerSection.subsections.hasOwnProperty(subsectionName)) {
gdjs.Profiler.getProfilerSectionTexts(
subsectionName,
profilerSection.subsections[subsectionName],
subsectionsOutputs
);
}
}
outputs.push.apply(outputs, subsectionsOutputs);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,149 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* @typedef BehaviorData Properties to set up a behavior.
* @property {string} name The name of the behavior (for getting from an object (object.getBehavior) for example)
* @property {string} type The behavior type. Used by GDJS to find the proper behavior to construct.
*/
/**
* RuntimeBehavior represents a behavior being used by a RuntimeObject.
*
* @class RuntimeBehavior
* @memberof gdjs
* @param {gdjs.RuntimeScene} runtimeScene The scene owning the object of the behavior
* @param {BehaviorData} behaviorData The properties used to setup the behavior
* @param {gdjs.RuntimeObject} owner The object owning the behavior
*/
gdjs.RuntimeBehavior = function(runtimeScene, behaviorData, owner)
{
this.name = behaviorData.name || "";
this.type = behaviorData.type || "";
this._nameId = gdjs.RuntimeObject.getNameIdentifier(this.name);
this._activated = true;
this.owner = owner;
};
/**
* Get the name of the behavior.
* @return {string} The behavior's name.
*/
gdjs.RuntimeBehavior.prototype.getName = function() {
return this.name;
};
/**
* Get the name identifier of the behavior.
* @return {number} The behavior's name identifier.
*/
gdjs.RuntimeBehavior.prototype.getNameId = function() {
return this._nameId;
};
/**
* Called at each frame before events. Call doStepPreEvents.<br>
* Behaviors writers: Please do not redefine this method. Redefine doStepPreEvents instead.
* @param {gdjs.RuntimeScene} runtimeScene The runtimeScene owning the object
*/
gdjs.RuntimeBehavior.prototype.stepPreEvents = function(runtimeScene) {
if ( this._activated ) {
var profiler = runtimeScene.getProfiler();
if (profiler) profiler.begin(this.name);
this.doStepPreEvents(runtimeScene);
if (profiler) profiler.end(this.name);
}
};
/**
* Called at each frame after events. Call doStepPostEvents.<br>
* Behaviors writers: Please do not redefine this method. Redefine doStepPreEvents instead.
* @param {gdjs.RuntimeScene} runtimeScene The runtimeScene owning the object
*/
gdjs.RuntimeBehavior.prototype.stepPostEvents = function(runtimeScene) {
if ( this._activated ) {
var profiler = runtimeScene.getProfiler();
if (profiler) profiler.begin(this.name);
this.doStepPostEvents(runtimeScene);
if (profiler) profiler.end(this.name);
}
};
/**
* De/Activate the behavior
* @param {boolean} enable true to enable the behavior, false to disable it
*/
gdjs.RuntimeBehavior.prototype.activate = function(enable) {
if ( enable === undefined ) enable = true;
if ( !this._activated && enable ) {
this._activated = true;
this.onActivate();
}
else if ( this._activated && !enable ) {
this._activated = false;
this.onDeActivate();
}
};
/**
* Reimplement this to do extra work when the behavior is created (i.e: an
* object using it was created), after the object is fully initialized (so
* you can use `this.owner` without risk).
*/
gdjs.RuntimeBehavior.prototype.onCreated = function() {
};
/**
* Return true if the behavior is activated
*/
gdjs.RuntimeBehavior.prototype.activated = function() {
return this._activated;
};
/**
* Reimplement this method to do extra work when the behavior is activated (after
* it has been deactivated, see `onDeActivate`).
*/
gdjs.RuntimeBehavior.prototype.onActivate = function() {
};
/**
* Reimplement this method to do extra work when the behavior is deactivated.
*/
gdjs.RuntimeBehavior.prototype.onDeActivate = function() {
};
/**
* This method is called each tick before events are done.
* @param {gdjs.RuntimeScene} runtimeScene The runtimeScene owning the object
*/
gdjs.RuntimeBehavior.prototype.doStepPreEvents = function(runtimeScene) {
};
/**
* This method is called each tick after events are done.
* @param {gdjs.RuntimeScene} runtimeScene The runtimeScene owning the object
*/
gdjs.RuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
}
/**
* This method is called when the owner of the behavior
* is being removed from the scene and is about to be destroyed/reused later,
*/
gdjs.RuntimeBehavior.prototype.onDestroy = function() {
};
gdjs.registerBehavior("", gdjs.RuntimeBehavior);

View File

@ -0,0 +1,528 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Represents a game being played.
*
* @memberof gdjs
* @class RuntimeGame
* @param {Object} data The object (usually stored in data.json) containing the full project data
* @param {Object=} spec Optional object for specifiying additional options: {forceFullscreen: ...}
*/
gdjs.RuntimeGame = function(data, spec) {
spec = spec || {};
this._variables = new gdjs.VariablesContainer(data.variables);
this._data = data;
this._imageManager = new gdjs.ImageManager(
data.resources ? data.resources.resources : undefined
);
this._soundManager = new gdjs.SoundManager(
data.resources ? data.resources.resources : undefined
);
this._fontManager = new gdjs.FontManager(
data.resources ? data.resources.resources : undefined
);
this._jsonManager = new gdjs.JsonManager(
data.resources ? data.resources.resources : undefined
);
this._maxFPS = data ? parseInt(data.properties.maxFPS, 10) : 60;
this._minFPS = data ? parseInt(data.properties.minFPS, 10) : 15;
this._gameResolutionWidth = data.properties.windowWidth;
this._gameResolutionHeight = data.properties.windowHeight;
this._originalWidth = this._gameResolutionWidth;
this._originalHeight = this._gameResolutionHeight;
this._resizeMode = data.properties.sizeOnStartupMode;
this._adaptGameResolutionAtRuntime =
data.properties.adaptGameResolutionAtRuntime;
/** @type {string} */
this._scaleMode = data.properties.scaleMode || 'linear';
this._renderer = new gdjs.RuntimeGameRenderer(
this,
spec.forceFullscreen || false
);
//Game loop management (see startGameLoop method)
this._sceneStack = new gdjs.SceneStack(this);
this._notifyScenesForGameResolutionResize = false; // When set to true, the scenes are notified that gamre resolution size changed.
this._paused = false;
//Inputs :
this._inputManager = new gdjs.InputManager();
//Allow to specify an external layout to insert in the first scene:
this._injectExternalLayout = spec.injectExternalLayout || '';
//Optional client to connect to a debugger:
this._debuggerClient = gdjs.DebuggerClient
? new gdjs.DebuggerClient(this)
: null;
};
gdjs.RuntimeGame.prototype.getRenderer = function() {
return this._renderer;
};
/**
* Get the variables of the RuntimeGame.
* @return {gdjs.VariablesContainer} The global variables
*/
gdjs.RuntimeGame.prototype.getVariables = function() {
return this._variables;
};
/**
* Get the gdjs.SoundManager of the RuntimeGame.
* @return {gdjs.SoundManager} The sound manager.
*/
gdjs.RuntimeGame.prototype.getSoundManager = function() {
return this._soundManager;
};
/**
* Get the gdjs.ImageManager of the RuntimeGame.
* @return {gdjs.ImageManager} The image manager.
*/
gdjs.RuntimeGame.prototype.getImageManager = function() {
return this._imageManager;
};
/**
* Get the gdjs.FontManager of the RuntimeGame.
* @return {gdjs.FontManager} The font manager.
*/
gdjs.RuntimeGame.prototype.getFontManager = function() {
return this._fontManager;
};
/**
* Get the input manager of the game, storing mouse, keyboard
* and touches states.
* @return {gdjs.InputManager} The input manager owned by the game
*/
gdjs.RuntimeGame.prototype.getInputManager = function() {
return this._inputManager;
};
/**
* Get the JSON manager of the game, used to load JSON from game
* resources.
* @return {gdjs.JsonManager} The json manager for the game
*/
gdjs.RuntimeGame.prototype.getJsonManager = function() {
return this._jsonManager;
};
/**
* Get the object containing the game data
* @return {Object} The object associated to the game.
*/
gdjs.RuntimeGame.prototype.getGameData = function() {
return this._data;
};
/**
* Get the data associated to a scene.
*
* @param {string} sceneName The name of the scene. If not defined, the first scene will be returned.
* @return {?Object} The data associated to the scene.
*/
gdjs.RuntimeGame.prototype.getSceneData = function(sceneName) {
var scene = undefined;
for (var i = 0, len = this._data.layouts.length; i < len; ++i) {
var sceneData = this._data.layouts[i];
if (sceneName === undefined || sceneData.name === sceneName) {
scene = sceneData;
break;
}
}
if (scene === undefined)
console.warn('The game has no scene called "' + sceneName + '"');
return scene;
};
/**
* Check if a scene exists
*
* @param {string=} sceneName The name of the scene to search.
* @return {boolean} true if the scene exists. If sceneName is undefined, true if the game has a scene.
*/
gdjs.RuntimeGame.prototype.hasScene = function(sceneName) {
var isTrue = false;
for (var i = 0, len = this._data.layouts.length; i < len; ++i) {
var sceneData = this._data.layouts[i];
if (sceneName === undefined || sceneData.name == sceneName) {
isTrue = true;
break;
}
}
return isTrue;
};
/**
* Get the data associated to an external layout.
*
* @param {string} name The name of the external layout.
* @return {?Object} The data associated to the external layout or null if not found.
*/
gdjs.RuntimeGame.prototype.getExternalLayoutData = function(name) {
var externalLayout = null;
for (var i = 0, len = this._data.externalLayouts.length; i < len; ++i) {
var layoutData = this._data.externalLayouts[i];
if (layoutData.name === name) {
externalLayout = layoutData;
break;
}
}
return externalLayout;
};
/**
* Get the data representing all the global objects of the game.
* @return {Object} The data associated to the global objects.
*/
gdjs.RuntimeGame.prototype.getInitialObjectsData = function() {
return this._data.objects || [];
};
/**
* Get the original width of the game, as set on the startup of the game.
*
* This is guaranteed to never change, even if the size of the game is changed afterwards.
*/
gdjs.RuntimeGame.prototype.getOriginalWidth = function() {
return this._originalWidth;
};
/**
* Get the original height of the game, as set on the startup of the game.
*
* This is guaranteed to never change, even if the size of the game is changed afterwards.
*/
gdjs.RuntimeGame.prototype.getOriginalHeight = function() {
return this._originalHeight;
};
/**
* Get the game resolution (the size at which the game is played and rendered) width.
* @returns {number} The game resolution width, in pixels.
*/
gdjs.RuntimeGame.prototype.getGameResolutionWidth = function() {
return this._gameResolutionWidth;
};
/**
* Get the game resolution (the size at which the game is played and rendered) height.
* @returns {number} The game resolution height, in pixels.
*/
gdjs.RuntimeGame.prototype.getGameResolutionHeight = function() {
return this._gameResolutionHeight;
};
/**
* Change the game resolution.
*
* @param {number} width The new width
* @param {number} height The new height
*/
gdjs.RuntimeGame.prototype.setGameResolutionSize = function(width, height) {
this._gameResolutionWidth = width;
this._gameResolutionHeight = height;
if (this._adaptGameResolutionAtRuntime) {
if (
gdjs.RuntimeGameRenderer &&
gdjs.RuntimeGameRenderer.getWindowInnerWidth &&
gdjs.RuntimeGameRenderer.getWindowInnerHeight
) {
var windowInnerWidth = gdjs.RuntimeGameRenderer.getWindowInnerWidth();
var windowInnerHeight = gdjs.RuntimeGameRenderer.getWindowInnerHeight();
// Enlarge either the width or the eight to fill the inner window space.
var width = this._gameResolutionWidth;
var height = this._gameResolutionHeight;
if (this._resizeMode === 'adaptWidth') {
this._gameResolutionWidth =
(this._gameResolutionHeight * windowInnerWidth) / windowInnerHeight;
} else if (this._resizeMode === 'adaptHeight') {
this._gameResolutionHeight =
(this._gameResolutionWidth * windowInnerHeight) / windowInnerWidth;
}
}
} else {
// Don't alter the game resolution. The renderer
// will maybe adapt the size of the canvas or whatever is used to render the
// game in the window, but this does not change the "game resolution".
}
// Notify the renderer that game resolution changed (so that the renderer size
// can be updated, and maybe other things like the canvas size), and let the
// scenes know too.
this._renderer.updateRendererSize();
this._notifyScenesForGameResolutionResize = true;
};
/**
* Set if the width or the height of the game resolution
* should be changed to fit the game window - or if the game
* resolution should not be updated automatically.
*
* @param {string} resizeMode Either "" (don't change game resolution), "adaptWidth" or "adaptHeight".
*/
gdjs.RuntimeGame.prototype.setGameResolutionResizeMode = function(resizeMode) {
this._resizeMode = resizeMode;
this._forceGameResolutionUpdate();
};
/**
* Returns if the width or the height of the game resolution
* should be changed to fit the game window - or if the game
* resolution should not be updated automatically (empty string).
*
* @returns {string} Either "" (don't change game resolution), "adaptWidth" or "adaptHeight".
*/
gdjs.RuntimeGame.prototype.getGameResolutionResizeMode = function() {
return this._resizeMode;
};
/**
* Set if the game resolution should be automatically adapted
* when the game window or screen size change. This will only
* be the case if the game resolution resize mode is
* configured to adapt the width or the height of the game.
* @param {boolean} enable true to change the game resolution according to the window/screen size.
*/
gdjs.RuntimeGame.prototype.setAdaptGameResolutionAtRuntime = function(enable) {
this._adaptGameResolutionAtRuntime = enable;
this._forceGameResolutionUpdate();
};
/**
* Returns if the game resolution should be automatically adapted
* when the game window or screen size change. This will only
* be the case if the game resolution resize mode is
* configured to adapt the width or the height of the game.
* @returns {boolean} true if the game resolution is automatically changed according to the window/screen size.
*/
gdjs.RuntimeGame.prototype.getAdaptGameResolutionAtRuntime = function() {
return this._adaptGameResolutionAtRuntime;
};
/**
* Return the minimal fps that must be guaranteed by the game
* (otherwise, game is slowed down).
*/
gdjs.RuntimeGame.prototype.getMinimalFramerate = function() {
return this._minFPS;
};
/**
* Return the scale mode of the game ("linear" or "nearest").
*/
gdjs.RuntimeGame.prototype.getScaleMode = function() {
return this._scaleMode;
};
/**
* Set or unset the game as paused.
* When paused, the game won't step and will be freezed. Useful for debugging.
* @param {boolean} enable true to pause the game, false to unpause
*/
gdjs.RuntimeGame.prototype.pause = function(enable) {
this._paused = enable;
};
/**
* Load all assets, displaying progress in renderer.
*/
gdjs.RuntimeGame.prototype.loadAllAssets = function(
callback,
progressCallback
) {
var loadingScreen = new gdjs.LoadingScreenRenderer(
this.getRenderer(),
this._data.properties.loadingScreen
);
var allAssetsTotal = this._data.resources.resources.length;
var that = this;
this._imageManager.loadTextures(
function(count, total) {
var percent = Math.floor((count / allAssetsTotal) * 100);
loadingScreen.render(percent);
if (progressCallback) progressCallback(percent);
},
function(texturesTotalCount) {
that._soundManager.preloadAudio(
function(count, total) {
var percent = Math.floor(
((texturesTotalCount + count) / allAssetsTotal) * 100
);
loadingScreen.render(percent);
if (progressCallback) progressCallback(percent);
},
function(audioTotalCount) {
that._fontManager.loadFonts(
function(count, total) {
var percent = Math.floor(
((texturesTotalCount + audioTotalCount + count) /
allAssetsTotal) *
100
);
loadingScreen.render(percent);
if (progressCallback) progressCallback(percent);
},
function(fontTotalCount) {
that._jsonManager.preloadJsons(
function(count, total) {
var percent = Math.floor(
((texturesTotalCount +
audioTotalCount +
fontTotalCount +
count) /
allAssetsTotal) *
100
);
loadingScreen.render(percent);
if (progressCallback) progressCallback(percent);
},
function() {
loadingScreen.unload();
callback();
}
);
}
);
}
);
}
);
};
/**
* Start the game loop, to be called once assets are loaded.
*/
gdjs.RuntimeGame.prototype.startGameLoop = function() {
if (!this.hasScene()) {
console.log('The game has no scene.');
return;
}
this._forceGameResolutionUpdate();
//Load the first scene
var firstSceneName = this._data.firstLayout;
this._sceneStack.push(
this.hasScene(firstSceneName) ? firstSceneName : this.getSceneData().name,
this._injectExternalLayout
);
//Uncomment to profile the first x frames of the game.
// var x = 500;
// var startTime = Date.now();
// console.profile("Stepping for " + x + " frames")
// for(var i = 0; i < x; ++i) {
// this._sceneStack.step(16);
// }
// console.profileEnd();
// var time = Date.now() - startTime;
// console.log("Took", time, "ms");
// return;
//The standard game loop
var that = this;
var accumulatedElapsedTime = 0;
this._renderer.startGameLoop(function(lastCallElapsedTime) {
if (that._paused) return true;
// Skip the frame if we rendering frames too fast
accumulatedElapsedTime += lastCallElapsedTime;
if (
that._maxFPS > 0 &&
1000.0 / accumulatedElapsedTime > that._maxFPS + 7
) {
// Only skip frame if the framerate is 7 frames above the maximum framerate.
// Most browser/engines will try to run at slightly more than 60 frames per second.
// If game is set to have a maximum FPS to 60, then one out of two frames will be dropped.
// Hence, we use a 7 frames margin to ensure that we're not skipping frames too much.
return true;
}
var elapsedTime = accumulatedElapsedTime;
accumulatedElapsedTime = 0;
//Manage resize events.
if (that._notifyScenesForGameResolutionResize) {
that._sceneStack.onGameResolutionResized();
that._notifyScenesForGameResolutionResize = false;
}
//Render and step the scene.
if (that._sceneStack.step(elapsedTime)) {
that.getInputManager().onFrameEnded();
return true;
}
return false;
});
};
/**
* Called by the game renderer when the window containing the game
* has changed size (this can result from a resize of the window,
* but also other factors like a device orientation change on mobile).
*/
gdjs.RuntimeGame.prototype.onWindowInnerSizeChanged = function() {
this._forceGameResolutionUpdate();
};
/**
* Enlarge/reduce the width (or the height) of the game to fill the inner window.
*/
gdjs.RuntimeGame.prototype._forceGameResolutionUpdate = function() {
this.setGameResolutionSize(
this._gameResolutionWidth,
this._gameResolutionHeight
);
};
/**
* Start a profiler for the currently running scene.
* @param {Function} onProfilerStopped Function to be called when the profiler is stopped. Will be passed the profiler as argument.
*/
gdjs.RuntimeGame.prototype.startCurrentSceneProfiler = function(
onProfilerStopped
) {
var currentScene = this._sceneStack.getCurrentScene();
if (!currentScene) return false;
currentScene.startProfiler(onProfilerStopped);
return true;
};
/**
* Stop the profiler for the currently running scene.
*/
gdjs.RuntimeGame.prototype.stopCurrentSceneProfiler = function() {
var currentScene = this._sceneStack.getCurrentScene();
if (!currentScene) return null;
currentScene.stopProfiler();
};
/**
* Return true if a scene was loaded, false otherwise (i.e: game not yet started).
*/
gdjs.RuntimeGame.prototype.wasFirstSceneLoaded = function() {
return this._sceneStack.wasFirstSceneLoaded();
}

View File

@ -0,0 +1,822 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* The runtimeScene object represents a scene being played and rendered in the browser in a canvas.
*
* @class RuntimeScene
* @memberof gdjs
* @param {gdjs.RuntimeGame} runtimeGame The game associated to this scene.
*/
gdjs.RuntimeScene = function(runtimeGame)
{
this._eventsFunction = null;
this._instances = new Hashtable(); //Contains the instances living on the scene
this._instancesCache = new Hashtable(); //Used to recycle destroyed instance instead of creating new ones.
this._objects = new Hashtable(); //Contains the objects data stored in the project
this._objectsCtor = new Hashtable();
this._layers = new Hashtable();
this._initialBehaviorSharedData = new Hashtable();
this._renderer = new gdjs.RuntimeSceneRenderer(this,
runtimeGame ? runtimeGame.getRenderer() : null);
this._variables = new gdjs.VariablesContainer();
this._runtimeGame = runtimeGame;
this._lastId = 0;
this._name = "";
this._timeManager = new gdjs.TimeManager(Date.now());
this._gameStopRequested = false;
this._requestedScene = "";
this._isLoaded = false; // True if loadFromScene was called and the scene is being played.
this._isJustResumed = false; // True in the first frame after resuming the paused scene
/** @type gdjs.RuntimeObject[] */
this._allInstancesList = []; //An array used to create a list of all instance when necessary ( see _constructListOfAllInstances )
/** @type gdjs.RuntimeObject[] */
this._instancesRemoved = []; //The instances removed from the scene and waiting to be sent to the cache.
/** @type gdjs.Profiler */
this._profiler = null; // Set to `new gdjs.Profiler()` to have profiling done on the scene.
this._onProfilerStopped = null; // The callback function to call when the profiler is stopped.
this.onGameResolutionResized();
};
/**
* Should be called when the canvas where the scene is rendered has been resized.
* See gdjs.RuntimeGame.startGameLoop in particular.
* @memberof gdjs.RuntimeScene
*/
gdjs.RuntimeScene.prototype.onGameResolutionResized = function() {
for(var name in this._layers.items) {
if (this._layers.items.hasOwnProperty(name)) {
/** @type gdjs.Layer */
var theLayer = this._layers.items[name];
theLayer.onGameResolutionResized();
}
}
this._renderer.onGameResolutionResized();
};
/**
* Load the runtime scene from the given scene.
* @param {Object} sceneData An object containing the scene data.
* @see gdjs.RuntimeGame#getSceneData
*/
gdjs.RuntimeScene.prototype.loadFromScene = function(sceneData) {
if ( sceneData === undefined ) {
console.error("loadFromScene was called without a scene");
return;
}
if ( this._isLoaded ) this.unloadScene();
//Setup main properties
if (this._runtimeGame) this._runtimeGame.getRenderer().setWindowTitle(sceneData.title);
this._name = sceneData.name;
this.setBackgroundColor(parseInt(sceneData.r, 10),
parseInt(sceneData.v, 10),
parseInt(sceneData.b, 10));
//Load layers
for(var i = 0, len = sceneData.layers.length;i<len;++i) {
var layerData = sceneData.layers[i];
this._layers.put(layerData.name, new gdjs.Layer(layerData, this));
//console.log("Created layer : \""+name+"\".");
}
//Load variables
this._variables = new gdjs.VariablesContainer(sceneData.variables);
//Cache the initial shared data of the behaviors
for(var i = 0, len = sceneData.behaviorsSharedData.length;i<len;++i) {
var data = sceneData.behaviorsSharedData[i];
//console.log("Initializing shared data for "+data.name);
this._initialBehaviorSharedData.put(data.name, data);
}
var that = this;
function loadObject(objData) {
var objectName = objData.name;
var objectType = objData.type;
that._objects.put(objectName, objData);
that._instances.put(objectName, []); //Also reserve an array for the instances
that._instancesCache.put(objectName, []); //and for cached instances
//And cache the constructor for the performance sake:
that._objectsCtor.put(objectName, gdjs.getObjectConstructor(objectType));
}
//Load objects: Global objects first...
var initialGlobalObjectsData = this.getGame().getInitialObjectsData();
for(var i = 0, len = initialGlobalObjectsData.length;i<len;++i) {
loadObject(initialGlobalObjectsData[i]);
}
//...then the scene objects
this._initialObjectsData = sceneData.objects;
for(var i = 0, len = this._initialObjectsData.length;i<len;++i) {
loadObject(this._initialObjectsData[i]);
}
//Create initial instances of objects
this.createObjectsFrom(sceneData.instances, 0, 0);
//Set up the function to be executed at each tick
var module = gdjs[sceneData.mangledName+"Code"];
if ( module && module.func )
this._eventsFunction = module.func;
else {
console.log("Warning: no function found for running logic of scene " + this._name);
this._eventsFunction = (function() {});
}
this._onceTriggers = new gdjs.OnceTriggers();
// Notify the global callbacks
if (this._runtimeGame && !this._runtimeGame.wasFirstSceneLoaded()) {
for(var i = 0;i<gdjs.callbacksFirstRuntimeSceneLoaded.length;++i) {
gdjs.callbacksFirstRuntimeSceneLoaded[i](this);
}
}
for(var i = 0;i<gdjs.callbacksRuntimeSceneLoaded.length;++i) {
gdjs.callbacksRuntimeSceneLoaded[i](this);
}
if (sceneData.stopSoundsOnStartup && this._runtimeGame)
this._runtimeGame.getSoundManager().clearAll();
this._isLoaded = true;
this._timeManager.reset();
};
/**
* Called when a scene is "paused", i.e it will be not be rendered again
* for some time, until it's resumed or unloaded.
*/
gdjs.RuntimeScene.prototype.onPause = function() {
for(var i = 0;i < gdjs.callbacksRuntimeScenePaused.length;++i) {
gdjs.callbacksRuntimeScenePaused[i](this);
}
}
/**
* Called when a scene is "resumed", i.e it will be rendered again
* on screen after having being paused.
*/
gdjs.RuntimeScene.prototype.onResume = function() {
this._isJustResumed = true;
for(var i = 0;i < gdjs.callbacksRuntimeSceneResumed.length;++i) {
gdjs.callbacksRuntimeSceneResumed[i](this);
}
}
/**
* Called before a scene is removed from the stack of scenes
* rendered on the screen.
*/
gdjs.RuntimeScene.prototype.unloadScene = function() {
if ( !this._isLoaded ) return;
if (this._profiler) this.stopProfiler();
// Notify the global callbacks (which should not release resources yet,
// as other callbacks might still refer to the objects/scene).
for(var i = 0;i < gdjs.callbacksRuntimeSceneUnloading.length;++i) {
gdjs.callbacksRuntimeSceneUnloading[i](this);
}
// Notify the objects they are being destroyed
this._constructListOfAllInstances();
for(var i = 0, len = this._allInstancesList.length;i<len;++i) {
var object = this._allInstancesList[i];
object.onDestroyFromScene(this);
}
// Notify the renderer
if (this._renderer && this._renderer.onSceneUnloaded)
this._renderer.onSceneUnloaded();
// Notify the global callbacks (after notifying objects and renderer, because
// callbacks from extensions might want to free resources - which can't be done
// safely before destroying objects and the renderer).
for(var i = 0;i < gdjs.callbacksRuntimeSceneUnloaded.length;++i) {
gdjs.callbacksRuntimeSceneUnloaded[i](this);
}
// It should not be necessary to reset these variables, but this help
// ensuring that all memory related to the RuntimeScene is released immediately.
this._layers = new Hashtable();
this._variables = new gdjs.VariablesContainer();
this._initialBehaviorSharedData = new Hashtable();
this._objects = new Hashtable();
this._instances = new Hashtable();
this._instancesCache = new Hashtable();
this._initialObjectsData = null;
this._eventsFunction = null;
this._objectsCtor = new Hashtable();
this._allInstancesList = [];
this._instancesRemoved = [];
this._lastId = 0;
this._onceTriggers = null;
this._isLoaded = false;
this.onGameResolutionResized();
};
/**
* Create objects from initial instances data ( for example, the initial instances
* of the scene or from an external layout ).
*
* @param {Object} data The instances data
* @param {number} xPos The offset on X axis
* @param {number} yPos The offset on Y axis
*/
gdjs.RuntimeScene.prototype.createObjectsFrom = function(data, xPos, yPos) {
for(var i = 0, len = data.length;i<len;++i) {
var instanceData = data[i];
var objectName = instanceData.name;
var newObject = this.createObject(objectName);
if ( newObject !== null ) {
newObject.setPosition(parseFloat(instanceData.x) + xPos, parseFloat(instanceData.y) + yPos);
newObject.setZOrder(parseFloat(instanceData.zOrder));
newObject.setAngle(parseFloat(instanceData.angle));
newObject.setLayer(instanceData.layer);
newObject.getVariables().initFrom(instanceData.initialVariables, true);
newObject.extraInitializationFromInitialInstance(instanceData);
}
}
};
/**
* Set the function called each time the scene is stepped.
* The function will be passed the `runtimeScene` as argument.
*
* Note that this is already set up by the gdjs.RuntimeScene constructor and that you should
* not need to use this method.
*
* @param {Function} func The function to be called.
*/
gdjs.RuntimeScene.prototype.setEventsFunction = function(func) {
this._eventsFunction = func;
};
/**
* Step and render the scene.
* @return {boolean} true if the game loop should continue, false if a scene change/push/pop
* or a game stop was requested.
*/
gdjs.RuntimeScene.prototype.renderAndStep = function(elapsedTime) {
if (this._profiler) this._profiler.beginFrame();
this._requestedChange = gdjs.RuntimeScene.CONTINUE;
this._timeManager.update(elapsedTime, this._runtimeGame.getMinimalFramerate());
if (this._profiler) this._profiler.begin("objects (pre-events)");
this._updateObjectsPreEvents();
if (this._profiler) this._profiler.end("objects (pre-events)");
if (this._profiler) this._profiler.begin("callbacks and extensions (pre-events)");
for(var i = 0;i < gdjs.callbacksRuntimeScenePreEvents.length;++i) {
gdjs.callbacksRuntimeScenePreEvents[i](this);
}
if (this._profiler) this._profiler.end("callbacks and extensions (pre-events)");
if (this._profiler) this._profiler.begin("events");
this._eventsFunction(this);
if (this._profiler) this._profiler.end("events");
if (this._profiler) this._profiler.begin("objects (post-events)");
this._updateObjectsPostEvents();
if (this._profiler) this._profiler.end("objects (post-events)");
if (this._profiler) this._profiler.begin("callbacks and extensions (post-events)");
for(var i = 0;i < gdjs.callbacksRuntimeScenePostEvents.length;++i) {
gdjs.callbacksRuntimeScenePostEvents[i](this);
}
if (this._profiler) this._profiler.end("callbacks and extensions (post-events)");
if (this._profiler) this._profiler.begin("objects (visibility)");
this._updateObjectsVisibility();
if (this._profiler) this._profiler.end("objects (visibility)");
if (this._profiler) this._profiler.begin("layers (effects update)");
this._updateLayers();
if (this._profiler) this._profiler.end("layers (effects update)");
if (this._profiler) this._profiler.begin("render");
// Uncomment to enable debug rendering (look for the implementation in the renderer
// to see what is rendered)
// if (this._layersCameraCoordinates) {
// this.getRenderer().renderDebugDraw(this._allInstancesList, this._layersCameraCoordinates); //TODO
// }
this._isJustResumed = false;
this.render();
if (this._profiler) this._profiler.end("render");
if (this._profiler) this._profiler.endFrame();
return !!this.getRequestedChange();
};
/**
* Render the PIXI container associated to the runtimeScene.
*/
gdjs.RuntimeScene.prototype.render = function() {
this._renderer.render();
};
gdjs.RuntimeScene.prototype._updateLayersCameraCoordinates = function() {
this._layersCameraCoordinates = this._layersCameraCoordinates || {};
for(var name in this._layers.items) {
if (this._layers.items.hasOwnProperty(name)) {
var theLayer = this._layers.items[name];
this._layersCameraCoordinates[name] = this._layersCameraCoordinates[name] ||
[0,0,0,0];
this._layersCameraCoordinates[name][0] = theLayer.getCameraX() - theLayer.getCameraWidth();
this._layersCameraCoordinates[name][1] = theLayer.getCameraY() - theLayer.getCameraHeight();
this._layersCameraCoordinates[name][2] = theLayer.getCameraX() + theLayer.getCameraWidth();
this._layersCameraCoordinates[name][3] = theLayer.getCameraY() + theLayer.getCameraHeight();
}
}
}
gdjs.RuntimeScene.prototype._updateLayers = function() {
for(var name in this._layers.items) {
if (this._layers.items.hasOwnProperty(name)) {
/** @type gdjs.Layer */
var theLayer = this._layers.items[name];
theLayer.update(this);
}
}
}
/**
* Called to update visibility of PIXI.DisplayObject of objects
* rendered on the scene.
*
* Visibility is set to false if object is hidden, or if
* object is too far from the camera of its layer ("culling").
* @private
*/
gdjs.RuntimeScene.prototype._updateObjectsVisibility = function() {
if (this._timeManager.isFirstFrame()) {
this._constructListOfAllInstances();
for( var i = 0, len = this._allInstancesList.length;i<len;++i) {
var object = this._allInstancesList[i];
var rendererObject = object.getRendererObject();
if (rendererObject)
object.getRendererObject().visible = !object.isHidden();
}
return;
} else {
//After first frame, optimise rendering by setting only objects
//near camera as visible.
this._updateLayersCameraCoordinates();
this._constructListOfAllInstances();
for( var i = 0, len = this._allInstancesList.length;i<len;++i) {
var object = this._allInstancesList[i];
var cameraCoords = this._layersCameraCoordinates[object.getLayer()];
var rendererObject = object.getRendererObject();
if (!cameraCoords || !rendererObject) continue;
if (object.isHidden()) {
rendererObject.visible = false;
} else {
var aabb = object.getVisibilityAABB();
if (aabb && // If no AABB is returned, the object should always be visible
(aabb.min[0] > cameraCoords[2] || aabb.min[1] > cameraCoords[3] ||
aabb.max[0] < cameraCoords[0] || aabb.max[1] < cameraCoords[1])) {
rendererObject.visible = false;
} else {
rendererObject.visible = true;
}
}
}
}
};
/**
* Empty the list of the removed objects:<br>
* When an object is removed from the scene, it is still kept in the _instancesRemoved member
* of the RuntimeScene.<br>
* This method should be called regularly (after events or behaviors steps) so as to clear this list
* and allows the removed objects to be cached (or destroyed if the cache is full).<br>
* The removed objects could not be sent directly to the cache, as events may still be using them after
* removing them from the scene for example.
*
* @private
*/
gdjs.RuntimeScene.prototype._cacheOrClearRemovedInstances = function() {
for(var k =0, lenk=this._instancesRemoved.length;k<lenk;++k) {
//Cache the instance to recycle it into a new instance later.
var cache = this._instancesCache.get(this._instancesRemoved[k].getName());
if ( cache.length < 128 ) cache.push(this._instancesRemoved[k]);
}
this._instancesRemoved.length = 0;
};
/**
* Tool function filling _allInstancesList member with all the living object instances.
* @private
*/
gdjs.RuntimeScene.prototype._constructListOfAllInstances = function() {
var currentListSize = 0;
for (var name in this._instances.items) {
if (this._instances.items.hasOwnProperty(name)) {
var list = this._instances.items[name];
var oldSize = currentListSize;
currentListSize += list.length;
for(var j = 0, lenj = list.length;j<lenj;++j) {
if (oldSize+j < this._allInstancesList.length)
this._allInstancesList[oldSize+j] = list[j];
else
this._allInstancesList.push(list[j]);
}
}
}
this._allInstancesList.length = currentListSize;
};
/**
* Update the objects before launching the events.
* @private
*/
gdjs.RuntimeScene.prototype._updateObjectsPreEvents = function() {
//It is *mandatory* to create and iterate on a external list of all objects, as the behaviors
//may delete the objects.
this._constructListOfAllInstances();
for( var i = 0, len = this._allInstancesList.length;i<len;++i) {
var obj = this._allInstancesList[i];
var elapsedTime = obj.getElapsedTime(this);
if (!obj.hasNoForces()) {
var averageForce = obj.getAverageForce();
var elapsedTimeInSeconds = elapsedTime / 1000;
obj.setX(obj.getX() + averageForce.getX() * elapsedTimeInSeconds);
obj.setY(obj.getY() + averageForce.getY() * elapsedTimeInSeconds);
obj.update(this);
obj.updateForces(elapsedTimeInSeconds);
} else {
obj.update(this);
}
obj.updateTimers(elapsedTime);
this._allInstancesList[i].stepBehaviorsPreEvents(this);
}
this._cacheOrClearRemovedInstances(); //Some behaviors may have request objects to be deleted.
};
/**
* Update the objects (update positions, time management...)
* @private
*/
gdjs.RuntimeScene.prototype._updateObjectsPostEvents = function() {
this._cacheOrClearRemovedInstances();
//It is *mandatory* to create and iterate on a external list of all objects, as the behaviors
//may delete the objects.
this._constructListOfAllInstances();
for( var i = 0, len = this._allInstancesList.length;i<len;++i) {
this._allInstancesList[i].stepBehaviorsPostEvents(this);
}
this._cacheOrClearRemovedInstances(); //Some behaviors may have request objects to be deleted.
};
/**
* Change the background color
*/
gdjs.RuntimeScene.prototype.setBackgroundColor = function(r,g,b) {
this._backgroundColor = parseInt(gdjs.rgbToHex(r,g,b),16);
};
gdjs.RuntimeScene.prototype.getBackgroundColor = function() {
return this._backgroundColor;
}
/**
* Get the name of the scene.
*/
gdjs.RuntimeScene.prototype.getName = function() {
return this._name;
};
/**
* Update the objects positions according to their forces
*/
gdjs.RuntimeScene.prototype.updateObjectsForces = function() {
for (var name in this._instances.items) {
if (this._instances.items.hasOwnProperty(name)) {
var list = this._instances.items[name];
for(var j = 0, listLen = list.length;j<listLen;++j) {
var obj = list[j];
if (!obj.hasNoForces()) {
var averageForce = obj.getAverageForce();
var elapsedTimeInSeconds = obj.getElapsedTime(this) / 1000;
obj.setX(obj.getX() + averageForce.getX() * elapsedTimeInSeconds);
obj.setY(obj.getY() + averageForce.getY() * elapsedTimeInSeconds);
obj.updateForces(elapsedTimeInSeconds);
}
}
}
}
};
/**
* Add an object to the instances living on the scene.
* @param obj The object to be added.
*/
gdjs.RuntimeScene.prototype.addObject = function(obj) {
if ( !this._instances.containsKey(obj.name) ) {
console.log("RuntimeScene.addObject: No objects called \""+obj.name+"\"! Adding it.");
this._instances.put(obj.name, []);
}
this._instances.get(obj.name).push(obj);
};
/**
* Get all the instances of the object called name.
* @param {string} name Name of the object for which the instances must be returned.
* @return {gdjs.RuntimeObject[]} The list of objects with the given name
*/
gdjs.RuntimeScene.prototype.getObjects = function(name){
if ( !this._instances.containsKey(name) ) {
console.log("RuntimeScene.getObjects: No instances called \""+name+"\"! Adding it.");
this._instances.put(name, []);
}
return this._instances.get(name);
};
/**
* Create a new object from its name. The object is also added to the instances
* living on the scene ( No need to call RuntimeScene.addObject )
* @param {string} objectName The name of the object to be created
* @return {gdjs.RuntimeObject} The created object
*/
gdjs.RuntimeScene.prototype.createObject = function(objectName){
if ( !this._objectsCtor.containsKey(objectName) ||
!this._objects.containsKey(objectName) )
return null; //There is no such object in this scene.
//Create a new object using the object constructor ( cached during loading )
//and the stored object's data:
var cache = this._instancesCache.get(objectName);
var ctor = this._objectsCtor.get(objectName);
var obj = null;
if ( cache.length === 0 ) {
obj = new ctor(this, this._objects.get(objectName));
}
else {
//Reuse an objet destroyed before:
obj = cache.pop();
ctor.call(obj, this, this._objects.get(objectName));
}
this.addObject(obj);
return obj;
};
/**
* Must be called whenever an object must be removed from the scene.
* @param {gdjs.RuntimeObject} object The object to be removed.
*/
gdjs.RuntimeScene.prototype.markObjectForDeletion = function(obj) {
//Add to the objects removed list.
//The objects will be sent to the instances cache or really deleted from memory later.
if ( this._instancesRemoved.indexOf(obj) === -1 ) this._instancesRemoved.push(obj);
//Delete from the living instances.
if ( this._instances.containsKey(obj.getName()) ) {
var objId = obj.id;
var allInstances = this._instances.get(obj.getName());
for(var i = 0, len = allInstances.length;i<len;++i) {
if (allInstances[i].id == objId) {
allInstances.remove(i);
break;
}
}
}
//Notify the object it was removed from the scene
obj.onDestroyFromScene(this);
// Notify the global callbacks
for(var j = 0;j<gdjs.callbacksObjectDeletedFromScene.length;++j) {
gdjs.callbacksObjectDeletedFromScene[j](this, obj);
}
return;
};
/**
* Create an identifier for a new object of the scene.
*/
gdjs.RuntimeScene.prototype.createNewUniqueId = function() {
this._lastId++;
return this._lastId;
};
/**
* Get the renderer associated to the RuntimeScene.
*/
gdjs.RuntimeScene.prototype.getRenderer = function() {
return this._renderer;
};
/**
* Get the runtimeGame associated to the RuntimeScene.
*/
gdjs.RuntimeScene.prototype.getGame = function() {
return this._runtimeGame;
};
/**
* Get the variables of the runtimeScene.
* @return The container holding the variables of the scene.
*/
gdjs.RuntimeScene.prototype.getVariables = function() {
return this._variables;
};
/**
* Get the data representing the initial shared data of the scene for the specified behavior.
* @param {string} name The name of the behavior
*/
gdjs.RuntimeScene.prototype.getInitialSharedDataForBehavior = function(name) {
if ( this._initialBehaviorSharedData.containsKey(name) ) {
return this._initialBehaviorSharedData.get(name);
}
console.error("Can't find shared data for behavior with name:", name);
return null;
};
/**
* Get the layer with the given name
* @param {string} name The name of the layer
* @returns {gdjs.Layer} The layer, or the base layer if not found
*/
gdjs.RuntimeScene.prototype.getLayer = function(name) {
if ( this._layers.containsKey(name) )
return this._layers.get(name);
return this._layers.get("");
};
/**
* Check if a layer exists
* @param {string} name The name of the layer
*/
gdjs.RuntimeScene.prototype.hasLayer = function(name) {
return this._layers.containsKey(name);
};
gdjs.RuntimeScene.prototype.getAllLayerNames = function(result) {
this._layers.keys(result);
};
/**
* Get the TimeManager of the scene.
* @return {gdjs.TimeManager} The gdjs.TimeManager of the scene.
*/
gdjs.RuntimeScene.prototype.getTimeManager = function() {
return this._timeManager;
};
/**
* Shortcut to get the SoundManager of the game.
* @return {gdjs.SoundManager} The gdjs.SoundManager of the game.
*/
gdjs.RuntimeScene.prototype.getSoundManager = function() {
return this._runtimeGame.getSoundManager();
};
//The flags to describe the change request by a scene:
gdjs.RuntimeScene.CONTINUE = 0;
gdjs.RuntimeScene.PUSH_SCENE = 1;
gdjs.RuntimeScene.POP_SCENE = 2;
gdjs.RuntimeScene.REPLACE_SCENE = 3;
gdjs.RuntimeScene.CLEAR_SCENES = 4;
gdjs.RuntimeScene.STOP_GAME = 5;
/**
* Return the value of the scene change that is requested.
*/
gdjs.RuntimeScene.prototype.getRequestedChange = function() {
return this._requestedChange;
};
/**
* Return the name of the new scene to be launched.
*
* See requestChange.
*/
gdjs.RuntimeScene.prototype.getRequestedScene = function() {
return this._requestedScene;
};
/**
* Request a scene change to be made. The change is handled externally (see gdjs.SceneStack)
* thanks to getRequestedChange and getRequestedScene methods.
* @param {number} change One of gdjs.RuntimeScene.CONTINUE|PUSH_SCENE|POP_SCENE|REPLACE_SCENE|CLEAR_SCENES|STOP_GAME.
* @param {string} sceneName The name of the new scene to launch, if applicable.
*/
gdjs.RuntimeScene.prototype.requestChange = function(change, sceneName) {
this._requestedChange = change;
this._requestedScene = sceneName;
};
/**
* Get the profiler associated with the scene, or null if none.
*/
gdjs.RuntimeScene.prototype.getProfiler = function() {
return this._profiler;
}
/**
* Start a new profiler to measures the time passed in sections of the engine
* in the scene.
* @param {Function} onProfilerStopped Function to be called when the profiler is stopped. Will be passed the profiler as argument.
*/
gdjs.RuntimeScene.prototype.startProfiler = function(onProfilerStopped) {
if (this._profiler) return;
this._profiler = new gdjs.Profiler();
this._onProfilerStopped = onProfilerStopped;
}
/**
* Stop the profiler being run on the scene.
*/
gdjs.RuntimeScene.prototype.stopProfiler = function() {
if (!this._profiler) return null;
var oldProfiler = this._profiler;
var onProfilerStopped = this._onProfilerStopped;
this._profiler = null;
this._onProfilerStopped = null;
if (onProfilerStopped) {
onProfilerStopped(oldProfiler);
}
}
/**
* Get the structure containing the triggers for "Trigger once" conditions.
*/
gdjs.RuntimeScene.prototype.getOnceTriggers = function() {
return this._onceTriggers;
}
/**
* Get a list of all gdjs.RuntimeObject living on the scene.
* You should not, normally, need this method at all. It's only to be used
* in exceptional use cases where you need to loop through all objects,
* and it won't be performant.
*
* @returns {gdjs.RuntimeObject[]} The list of all runtime objects on the scnee
*/
gdjs.RuntimeScene.prototype.getAdhocListOfAllInstances = function() {
this._constructListOfAllInstances();
return this._allInstancesList;
}
/**
* Check if the scene was just resumed.
* This is true during the first frame after the scene has been unpaused.
*
* @returns {boolean} true if the scene was just resumed
*/
gdjs.RuntimeScene.prototype.sceneJustResumed = function() {
return this._isJustResumed;
}

View File

@ -0,0 +1,144 @@
// @ts-check
/**
* Hold the stack of scenes (gdjs.RuntimeScene) being played.
*
* @memberof gdjs
* @param {gdjs.RuntimeGame} runtimeGame The runtime game that is using the scene stack
* @class SceneStack
*/
gdjs.SceneStack = function(runtimeGame) {
if (!runtimeGame) {
throw "SceneStack must be constructed with a gdjs.RuntimeGame."
}
this._runtimeGame = runtimeGame;
/** @type {gdjs.RuntimeScene[]} */
this._stack = [];
/** @type {boolean} */
this._wasFirstSceneLoaded = false;
};
/**
* Called by the RuntimeGame when the game resolution is changed.
* Useful to notify scene and layers that resolution is changed, as they
* might be caching it.
*/
gdjs.SceneStack.prototype.onGameResolutionResized = function() {
for(var i = 0;i < this._stack.length; ++i) {
this._stack[i].onGameResolutionResized();
}
};
gdjs.SceneStack.prototype.step = function(elapsedTime) {
if (this._stack.length === 0) return false;
var currentScene = this._stack[this._stack.length - 1];
if (currentScene.renderAndStep(elapsedTime)) {
var request = currentScene.getRequestedChange();
//Something special was requested by the current scene.
if (request === gdjs.RuntimeScene.STOP_GAME) {
this._runtimeGame.getRenderer().stopGame();
return true;
} else if (request === gdjs.RuntimeScene.POP_SCENE) {
this.pop();
} else if (request === gdjs.RuntimeScene.PUSH_SCENE) {
this.push(currentScene.getRequestedScene());
} else if (request === gdjs.RuntimeScene.REPLACE_SCENE) {
this.replace(currentScene.getRequestedScene());
} else if (request === gdjs.RuntimeScene.CLEAR_SCENES) {
this.replace(currentScene.getRequestedScene(), true);
} else {
console.error("Unrecognized change in scene stack.");
return false;
}
}
return true;
};
gdjs.SceneStack.prototype.renderWithoutStep = function() {
if (this._stack.length === 0) return false;
var currentScene = this._stack[this._stack.length - 1];
currentScene.render();
return true;
};
gdjs.SceneStack.prototype.pop = function() {
if (this._stack.length <= 1) return null;
// Unload the current scene
var scene = this._stack.pop();
if (!scene) return null;
scene.unloadScene();
// Tell the new current scene it's being resumed
var currentScene = this._stack[this._stack.length - 1];
if (currentScene) {
currentScene.onResume();
}
return scene;
};
gdjs.SceneStack.prototype.push = function(newSceneName, externalLayoutName) {
// Tell the scene it's being paused
var currentScene = this._stack[this._stack.length - 1];
if (currentScene) {
currentScene.onPause();
}
// Load the new one
var newScene = new gdjs.RuntimeScene(this._runtimeGame);
newScene.loadFromScene(this._runtimeGame.getSceneData(newSceneName));
this._wasFirstSceneLoaded = true;
//Optionally create the objects from an external layout.
if (externalLayoutName) {
var externalLayoutData = this._runtimeGame.getExternalLayoutData(externalLayoutName);
if (externalLayoutData)
newScene.createObjectsFrom(externalLayoutData.instances, 0, 0);
}
this._stack.push(newScene);
return newScene;
};
gdjs.SceneStack.prototype.replace = function(newSceneName, clear) {
if (!!clear) {
// Unload all the scenes
while (this._stack.length !== 0) {
var scene = this._stack.pop();
if (scene) scene.unloadScene();
}
} else {
// Unload the current scene
if (this._stack.length !== 0) {
var scene = this._stack.pop();
if (scene) scene.unloadScene();
}
}
return this.push(newSceneName);
};
/**
* Return the current gdjs.RuntimeScene being played, or null if none is run.
*/
gdjs.SceneStack.prototype.getCurrentScene = function() {
if (this._stack.length === 0) return null;
return this._stack[this._stack.length - 1];
};
/**
* Return true if a scene was loaded, false otherwise (i.e: game not yet started).
*/
gdjs.SceneStack.prototype.wasFirstSceneLoaded = function() {
return this._wasFirstSceneLoaded;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,101 @@
/*
* GDevelop JS Platform
* Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
* This project is released under the MIT License.
*/
/**
* Manage the timers and times elapsed during last
* frame, since the beginning of the scene and other time related values.
*
* @class TimeManager
* @memberof gdjs
*/
gdjs.TimeManager = function()
{
this.reset();
}
gdjs.TimeManager.prototype.reset = function() {
this._elapsedTime = 0;
this._timeScale = 1;
this._timeFromStart = 0;
this._firstFrame = true;
this._timers = new Hashtable();
}
gdjs.TimeManager.prototype.update = function(elapsedTime, minimumFPS) {
if (this._firstUpdateDone) this._firstFrame = false;
this._firstUpdateDone = true;
//Compute the elapsed time since last frame
this._elapsedTime = Math.min(elapsedTime, 1000/minimumFPS);
this._elapsedTime *= this._timeScale;
//Update timers and others members
for(var name in this._timers.items) {
if (this._timers.items.hasOwnProperty(name)) {
this._timers.items[name].updateTime(this._elapsedTime);
}
}
this._timeFromStart += this._elapsedTime;
};
/**
* Set the time scale: time will be slower if time scale is < 1,
* faster if > 1.
* @param {number} timeScale The new time scale (must be positive).
*/
gdjs.TimeManager.prototype.setTimeScale = function(timeScale) {
if ( timeScale >= 0 ) this._timeScale = timeScale;
};
/**
* Get the time scale.
* @return {number} The time scale (positive, 1 is normal speed).
*/
gdjs.TimeManager.prototype.getTimeScale = function() {
return this._timeScale;
};
/**
* Get the time since the instanciation of the manager (i.e: since
* the beginning of the scene most of the time), in milliseconds.
*/
gdjs.TimeManager.prototype.getTimeFromStart = function() {
return this._timeFromStart;
};
/**
* Return true if update was called only once (i.e: if the scene
* is rendering its first frame).
*/
gdjs.TimeManager.prototype.isFirstFrame = function() {
return this._firstFrame;
};
/**
* Return the time elapsed since the last call to update
* (i.e: the last frame), in milliseconds.
*/
gdjs.TimeManager.prototype.getElapsedTime = function() {
return this._elapsedTime;
};
gdjs.TimeManager.prototype.addTimer = function(name) {
this._timers.put(name, new gdjs.Timer(name));
};
gdjs.TimeManager.prototype.hasTimer = function(name) {
return this._timers.containsKey(name);
};
gdjs.TimeManager.prototype.getTimer = function(name) {
return this._timers.get(name);
};
gdjs.TimeManager.prototype.removeTimer = function(name) {
if (this._timers.containsKey(name)) this._timers.remove(name);
};

Some files were not shown because too many files have changed in this diff Show More