mirror of
https://github.com/4ian/GDevelop.git
synced 2026-10-12 02:01:17 +00:00
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
#include "ProjectStripper.h"
|
||||
|
||||
#include "GDCore/Project/EventsFunctionsContainer.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
@@ -12,7 +14,7 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project& project) {
|
||||
void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
|
||||
project.GetObjectGroups().Clear();
|
||||
while (project.GetExternalEventsCount() > 0)
|
||||
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
|
||||
@@ -22,7 +24,28 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project& project) {
|
||||
project.GetLayout(i).GetEvents().Clear();
|
||||
}
|
||||
|
||||
project.ClearEventsFunctionsExtensions();
|
||||
// Keep the EventsBasedObject object list because it's useful for the Runtime
|
||||
// to create the child-object.
|
||||
for (unsigned int extensionIndex = 0;
|
||||
extensionIndex < project.GetEventsFunctionsExtensionsCount();
|
||||
++extensionIndex) {
|
||||
auto &extension = project.GetEventsFunctionsExtension(extensionIndex);
|
||||
auto &eventsBasedObjects = extension.GetEventsBasedObjects();
|
||||
if (eventsBasedObjects.size() == 0) {
|
||||
project.RemoveEventsFunctionsExtension(extension.GetName());
|
||||
extensionIndex--;
|
||||
continue;
|
||||
}
|
||||
for (unsigned int objectIndex = 0; objectIndex < eventsBasedObjects.size();
|
||||
++objectIndex) {
|
||||
auto &eventsBasedObject = eventsBasedObjects.at(objectIndex);
|
||||
eventsBasedObject.SetFullName("");
|
||||
eventsBasedObject.SetDescription("");
|
||||
eventsBasedObject.GetEventsFunctions().GetInternalVector().clear();
|
||||
eventsBasedObject.GetPropertyDescriptors().GetInternalVector().clear();
|
||||
}
|
||||
extension.GetEventsBasedBehaviors().Clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
||||
@@ -49,7 +49,7 @@ gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(
|
||||
if (configurationPosition == childObjectConfigurations.end()) {
|
||||
childObjectConfigurations.insert(std::make_pair(
|
||||
objectName,
|
||||
project->CreateObjectConfiguration(childObject.GetType())));
|
||||
childObject.GetConfiguration().Clone()));
|
||||
return *(childObjectConfigurations[objectName]);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
// TODO EBO Add a test where a child is removed form the EventsBasedObject
|
||||
// and check the configuration still gives access to other child configuration.
|
||||
namespace {
|
||||
|
||||
const gd::StandardEvent &EnsureStandardEvent(const gd::BaseEvent &baseEvent) {
|
||||
|
||||
@@ -17,8 +17,12 @@ namespace gdjs {
|
||||
_bottomEdgeDistance: number = 0;
|
||||
_useLegacyBottomAndRightAnchors: boolean = false;
|
||||
|
||||
constructor(runtimeScene, behaviorData, owner) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._relativeToOriginalWindowSize = !!behaviorData.relativeToOriginalWindowSize;
|
||||
this._leftEdgeAnchor = behaviorData.leftEdgeAnchor;
|
||||
this._rightEdgeAnchor = behaviorData.rightEdgeAnchor;
|
||||
@@ -65,11 +69,15 @@ namespace gdjs {
|
||||
this._invalidDistances = true;
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene) {
|
||||
const game = runtimeScene.getGame();
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
gdjs.AnchorRuntimeBehavior.prototype.doStepPreEvents
|
||||
) as FloatPoint;
|
||||
// TODO EBO Make it work with event based objects or hide this behavior for them.
|
||||
const game = instanceContainer.getGame();
|
||||
let rendererWidth = game.getGameResolutionWidth();
|
||||
let rendererHeight = game.getGameResolutionHeight();
|
||||
const layer = runtimeScene.getLayer(this.owner.getLayer());
|
||||
const layer = instanceContainer.getLayer(this.owner.getLayer());
|
||||
if (this._invalidDistances) {
|
||||
if (this._relativeToOriginalWindowSize) {
|
||||
rendererWidth = game.getOriginalWidth();
|
||||
@@ -79,7 +87,9 @@ namespace gdjs {
|
||||
//Calculate the distances from the window's bounds.
|
||||
const topLeftPixel = layer.convertCoords(
|
||||
this.owner.getDrawableX(),
|
||||
this.owner.getDrawableY()
|
||||
this.owner.getDrawableY(),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
//Left edge
|
||||
@@ -125,9 +135,12 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
}
|
||||
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
|
||||
const bottomRightPixel = layer.convertCoords(
|
||||
this.owner.getDrawableX() + this.owner.getWidth(),
|
||||
this.owner.getDrawableY() + this.owner.getHeight()
|
||||
this.owner.getDrawableY() + this.owner.getHeight(),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
//Right edge
|
||||
@@ -268,11 +281,24 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
}
|
||||
const topLeftCoord = layer.convertInverseCoords(leftPixel, topPixel);
|
||||
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
|
||||
const topLeftCoord = layer.convertInverseCoords(
|
||||
leftPixel,
|
||||
topPixel,
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
const left = topLeftCoord[0];
|
||||
const top = topLeftCoord[1];
|
||||
|
||||
const bottomRightCoord = layer.convertInverseCoords(
|
||||
rightPixel,
|
||||
bottomPixel
|
||||
bottomPixel,
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
const right = bottomRightCoord[0];
|
||||
const bottom = bottomRightCoord[1];
|
||||
|
||||
// Compatibility with GD <= 5.0.133
|
||||
if (this._useLegacyBottomAndRightAnchors) {
|
||||
@@ -281,25 +307,25 @@ namespace gdjs {
|
||||
this._rightEdgeAnchor !==
|
||||
AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setWidth(bottomRightCoord[0] - topLeftCoord[0]);
|
||||
this.owner.setWidth(right - left);
|
||||
}
|
||||
if (
|
||||
this._bottomEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setHeight(bottomRightCoord[1] - topLeftCoord[1]);
|
||||
this.owner.setHeight(bottom - top);
|
||||
}
|
||||
if (
|
||||
this._leftEdgeAnchor !== AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setX(
|
||||
topLeftCoord[0] + this.owner.getX() - this.owner.getDrawableX()
|
||||
left + this.owner.getX() - this.owner.getDrawableX()
|
||||
);
|
||||
}
|
||||
if (
|
||||
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setY(
|
||||
topLeftCoord[1] + this.owner.getY() - this.owner.getDrawableY()
|
||||
top + this.owner.getY() - this.owner.getDrawableY()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -311,15 +337,15 @@ namespace gdjs {
|
||||
AnchorRuntimeBehavior.HorizontalAnchor.NONE &&
|
||||
this._leftEdgeAnchor !== AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setWidth(bottomRightCoord[0] - topLeftCoord[0]);
|
||||
this.owner.setX(topLeftCoord[0]);
|
||||
this.owner.setWidth(right - left);
|
||||
this.owner.setX(left);
|
||||
} else {
|
||||
if (
|
||||
this._leftEdgeAnchor !==
|
||||
AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setX(
|
||||
topLeftCoord[0] + this.owner.getX() - this.owner.getDrawableX()
|
||||
left + this.owner.getX() - this.owner.getDrawableX()
|
||||
);
|
||||
}
|
||||
if (
|
||||
@@ -327,7 +353,7 @@ namespace gdjs {
|
||||
AnchorRuntimeBehavior.HorizontalAnchor.NONE
|
||||
) {
|
||||
this.owner.setX(
|
||||
bottomRightCoord[0] +
|
||||
right +
|
||||
this.owner.getX() -
|
||||
this.owner.getDrawableX() -
|
||||
this.owner.getWidth()
|
||||
@@ -340,14 +366,14 @@ namespace gdjs {
|
||||
AnchorRuntimeBehavior.VerticalAnchor.NONE &&
|
||||
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setHeight(bottomRightCoord[1] - topLeftCoord[1]);
|
||||
this.owner.setY(topLeftCoord[1]);
|
||||
this.owner.setHeight(bottom - top);
|
||||
this.owner.setY(top);
|
||||
} else {
|
||||
if (
|
||||
this._topEdgeAnchor !== AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setY(
|
||||
topLeftCoord[1] + this.owner.getY() - this.owner.getDrawableY()
|
||||
top + this.owner.getY() - this.owner.getDrawableY()
|
||||
);
|
||||
}
|
||||
if (
|
||||
@@ -355,7 +381,7 @@ namespace gdjs {
|
||||
AnchorRuntimeBehavior.VerticalAnchor.NONE
|
||||
) {
|
||||
this.owner.setY(
|
||||
bottomRightCoord[1] +
|
||||
bottom +
|
||||
this.owner.getY() -
|
||||
this.owner.getDrawableY() -
|
||||
this.owner.getHeight()
|
||||
@@ -366,7 +392,7 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene) {}
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
static HorizontalAnchor = {
|
||||
NONE: 0,
|
||||
|
||||
@@ -10,11 +10,11 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* @param runtimeObject The object to render
|
||||
* @param runtimeScene The gdjs.RuntimeScene in which the object is
|
||||
* @param instanceContainer The gdjs.RuntimeInstanceContainer in which the object is
|
||||
*/
|
||||
constructor(
|
||||
runtimeObject: gdjs.BBTextRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace gdjs {
|
||||
if (this._pixiObject === undefined) {
|
||||
this._pixiObject = new MultiStyleText(runtimeObject._text, {
|
||||
default: {
|
||||
fontFamily: runtimeScene
|
||||
fontFamily: instanceContainer
|
||||
.getGame()
|
||||
.getFontManager()
|
||||
.getFontFamily(runtimeObject._fontFamily),
|
||||
@@ -44,7 +44,7 @@ namespace gdjs {
|
||||
this.updateFontFamily();
|
||||
this.updateFontSize();
|
||||
}
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._pixiObject, runtimeObject.getZOrder());
|
||||
@@ -95,7 +95,8 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
updateFontFamily(): void {
|
||||
this._pixiObject.textStyles.default.fontFamily = this._object._runtimeScene
|
||||
this._pixiObject.textStyles.default.fontFamily = this._object
|
||||
.getInstanceContainer()
|
||||
.getGame()
|
||||
.getFontManager()
|
||||
.getFontFamily(this._object._fontFamily);
|
||||
|
||||
@@ -48,11 +48,14 @@ namespace gdjs {
|
||||
hidden: boolean;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
* @param objectData The object data used to initialize the object
|
||||
*/
|
||||
constructor(runtimeScene: gdjs.RuntimeScene, objectData: BBTextObjectData) {
|
||||
super(runtimeScene, objectData);
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectData: BBTextObjectData
|
||||
) {
|
||||
super(instanceContainer, objectData);
|
||||
// @ts-ignore - parseFloat should not be required, but GDevelop 5.0 beta 92 and below were storing it as a string.
|
||||
this._opacity = parseFloat(objectData.content.opacity);
|
||||
this._text = objectData.content.text;
|
||||
@@ -62,7 +65,10 @@ namespace gdjs {
|
||||
this._fontSize = parseFloat(objectData.content.fontSize);
|
||||
this._wordWrap = objectData.content.wordWrap;
|
||||
this._align = objectData.content.align;
|
||||
this._renderer = new gdjs.BBTextRuntimeObjectRenderer(this, runtimeScene);
|
||||
this._renderer = new gdjs.BBTextRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
this.hidden = !objectData.content.visible;
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
@@ -122,8 +128,8 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
onDestroyFromScene(runtimeScene): void {
|
||||
super.onDestroyFromScene(runtimeScene);
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +245,7 @@ namespace gdjs {
|
||||
|
||||
this._wrappingWidth = width;
|
||||
this._renderer.updateWrappingWidth();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,7 +260,7 @@ namespace gdjs {
|
||||
|
||||
this._wordWrap = wordWrap;
|
||||
this._renderer.updateWordWrap();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
getWordWrap() {
|
||||
|
||||
@@ -10,16 +10,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* @param runtimeObject The object to render
|
||||
* @param runtimeScene The gdjs.RuntimeScene in which the object is
|
||||
* @param instanceContainer The container in which the object is
|
||||
*/
|
||||
constructor(
|
||||
runtimeObject: gdjs.BitmapTextRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
|
||||
// Obtain the bitmap font to use in the object.
|
||||
const bitmapFont = runtimeScene
|
||||
const bitmapFont = instanceContainer
|
||||
.getGame()
|
||||
.getBitmapFontManager()
|
||||
.obtainBitmapFont(
|
||||
@@ -32,7 +32,7 @@ namespace gdjs {
|
||||
});
|
||||
|
||||
// Set the object on the scene
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._pixiObject, runtimeObject.getZOrder());
|
||||
@@ -59,7 +59,8 @@ namespace gdjs {
|
||||
|
||||
onDestroy() {
|
||||
// Mark the font from the object as not used anymore.
|
||||
this._object._runtimeScene
|
||||
this._object
|
||||
.getInstanceContainer()
|
||||
.getGame()
|
||||
.getBitmapFontManager()
|
||||
.releaseBitmapFont(this._pixiObject.fontName);
|
||||
@@ -73,7 +74,8 @@ namespace gdjs {
|
||||
|
||||
updateFont(): void {
|
||||
// Get the new bitmap font to use
|
||||
const bitmapFont = this._object._runtimeScene
|
||||
const bitmapFont = this._object
|
||||
.getInstanceContainer()
|
||||
.getGame()
|
||||
.getBitmapFontManager()
|
||||
.obtainBitmapFont(
|
||||
@@ -82,7 +84,8 @@ namespace gdjs {
|
||||
);
|
||||
|
||||
// Mark the old font as not used anymore
|
||||
this._object._runtimeScene
|
||||
this._object
|
||||
.getInstanceContainer()
|
||||
.getGame()
|
||||
.getBitmapFontManager()
|
||||
.releaseBitmapFont(this._pixiObject.fontName);
|
||||
|
||||
@@ -50,14 +50,14 @@ namespace gdjs {
|
||||
_renderer: gdjs.BitmapTextRuntimeObjectPixiRenderer;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
* @param objectData The object data used to initialize the object
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectData: BitmapTextObjectData
|
||||
) {
|
||||
super(runtimeScene, objectData);
|
||||
super(instanceContainer, objectData);
|
||||
|
||||
this._opacity = objectData.content.opacity;
|
||||
this._text = objectData.content.text;
|
||||
@@ -73,7 +73,7 @@ namespace gdjs {
|
||||
|
||||
this._renderer = new gdjs.BitmapTextRuntimeObjectRenderer(
|
||||
this,
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
@@ -137,8 +137,8 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
onDestroyFromScene(runtimeScene: gdjs.RuntimeScene): void {
|
||||
super.onDestroyFromScene(runtimeScene);
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
this._renderer.onDestroy();
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace gdjs {
|
||||
setText(text: string): void {
|
||||
this._text = text;
|
||||
this._renderer.updateTextContent();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,7 +170,7 @@ namespace gdjs {
|
||||
setScale(scale: float): void {
|
||||
this._scale = scale;
|
||||
this._renderer.updateScale();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
getScale(): float {
|
||||
@@ -276,7 +276,7 @@ namespace gdjs {
|
||||
setWrappingWidth(width: float): void {
|
||||
this._wrappingWidth = width;
|
||||
this._renderer.updateWrappingWidth();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,7 +289,7 @@ namespace gdjs {
|
||||
setWordWrap(wordWrap: boolean): void {
|
||||
this._wordWrap = wordWrap;
|
||||
this._renderer.updateWrappingWidth();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
getWordWrap(): boolean {
|
||||
|
||||
@@ -7,10 +7,12 @@ namespace gdjs {
|
||||
export namespace debuggerTools {
|
||||
/**
|
||||
* Stop the game execution.
|
||||
* @param runtimeScene - The current scene.
|
||||
* @param instanceContainer - The current container.
|
||||
*/
|
||||
export const pause = function (runtimeScene: gdjs.RuntimeScene) {
|
||||
runtimeScene.getGame().pause(true);
|
||||
export const pause = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
instanceContainer.getGame().pause(true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -29,20 +31,20 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Enable or disable the debug draw.
|
||||
* @param runtimeScene - The current scene.
|
||||
* @param instanceContainer - The current container.
|
||||
* @param enableDebugDraw - true to enable the debug draw, false to disable it.
|
||||
* @param showHiddenInstances - true to apply the debug draw to hidden objects.
|
||||
* @param showPointsNames - true to show point names.
|
||||
* @param showCustomPoints - true to show custom points of Sprite objects.
|
||||
*/
|
||||
export const enableDebugDraw = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
enableDebugDraw: boolean,
|
||||
showHiddenInstances: boolean,
|
||||
showPointsNames: boolean,
|
||||
showCustomPoints: boolean
|
||||
) {
|
||||
runtimeScene.enableDebugDraw(
|
||||
instanceContainer.enableDebugDraw(
|
||||
enableDebugDraw,
|
||||
showHiddenInstances,
|
||||
showPointsNames,
|
||||
|
||||
@@ -11,8 +11,12 @@ namespace gdjs {
|
||||
export class DestroyOutsideRuntimeBehavior extends gdjs.RuntimeBehavior {
|
||||
_extraBorder: any;
|
||||
|
||||
constructor(runtimeScene, behaviorData, owner) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner
|
||||
) {
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._extraBorder = behaviorData.extraBorder || 0;
|
||||
}
|
||||
|
||||
@@ -23,14 +27,14 @@ namespace gdjs {
|
||||
return true;
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene) {
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// 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).
|
||||
const ow = this.owner.getWidth();
|
||||
const oh = this.owner.getHeight();
|
||||
const ocx = this.owner.getDrawableX() + this.owner.getCenterX();
|
||||
const ocy = this.owner.getDrawableY() + this.owner.getCenterY();
|
||||
const layer = runtimeScene.getLayer(this.owner.getLayer());
|
||||
const layer = instanceContainer.getLayer(this.owner.getLayer());
|
||||
const boundingCircleRadius = Math.sqrt(ow * ow + oh * oh) / 2.0;
|
||||
if (
|
||||
ocx + boundingCircleRadius + this._extraBorder <
|
||||
@@ -43,7 +47,7 @@ namespace gdjs {
|
||||
layer.getCameraY() + layer.getCameraHeight() / 2
|
||||
) {
|
||||
//We are outside the camera area.
|
||||
this.owner.deleteFromScene(runtimeScene);
|
||||
this.owner.deleteFromScene(instanceContainer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,16 +30,16 @@ namespace gdjs {
|
||||
/**
|
||||
* Load the Dialogue Tree data from a JSON resource.
|
||||
*
|
||||
* @param runtimeScene The scene where the dialogue is running.
|
||||
* @param instanceContainer The scene where the dialogue is running.
|
||||
* @param jsonResourceName The JSON resource where to load the Dialogue Tree data from. The data is a JSON string usually created with [Yarn Dialogue Editor](https://github.com/InfiniteAmmoInc/Yarn).
|
||||
* @param startDialogueNode The Dialogue Branch to start the Dialogue Tree from. If left empty, the data will only be loaded, but can later be initialized via another action
|
||||
*/
|
||||
gdjs.dialogueTree.loadFromJsonFile = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
jsonResourceName: string,
|
||||
startDialogueNode: string
|
||||
) {
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getGame()
|
||||
.getJsonManager()
|
||||
.loadJson(jsonResourceName, function (error, content) {
|
||||
|
||||
@@ -16,8 +16,12 @@ namespace gdjs {
|
||||
_draggedByDraggableManager: DraggableManager | null = null;
|
||||
_checkCollisionMask: boolean;
|
||||
|
||||
constructor(runtimeScene, behaviorData, owner) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner
|
||||
) {
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._checkCollisionMask = behaviorData.checkCollisionMask ? true : false;
|
||||
}
|
||||
|
||||
@@ -45,21 +49,21 @@ namespace gdjs {
|
||||
this._draggedByDraggableManager = null;
|
||||
}
|
||||
|
||||
_tryBeginDrag(runtimeScene) {
|
||||
_tryBeginDrag(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
if (this._draggedByDraggableManager) {
|
||||
return false;
|
||||
}
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
const inputManager = instanceContainer.getGame().getInputManager();
|
||||
|
||||
//Try mouse
|
||||
const mouseDraggableManager = DraggableManager.getMouseManager(
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
if (
|
||||
inputManager.isMouseButtonPressed(0) &&
|
||||
!mouseDraggableManager.isDragging(this)
|
||||
) {
|
||||
if (mouseDraggableManager.tryAndTakeDragging(runtimeScene, this)) {
|
||||
if (mouseDraggableManager.tryAndTakeDragging(instanceContainer, this)) {
|
||||
this._draggedByDraggableManager = mouseDraggableManager;
|
||||
return true;
|
||||
}
|
||||
@@ -68,13 +72,15 @@ namespace gdjs {
|
||||
const touchIds = inputManager.getStartedTouchIdentifiers();
|
||||
for (let i = 0; i < touchIds.length; ++i) {
|
||||
const touchDraggableManager = DraggableManager.getTouchManager(
|
||||
runtimeScene,
|
||||
instanceContainer,
|
||||
touchIds[i]
|
||||
);
|
||||
if (touchDraggableManager.isDragging(this)) {
|
||||
continue;
|
||||
}
|
||||
if (touchDraggableManager.tryAndTakeDragging(runtimeScene, this)) {
|
||||
if (
|
||||
touchDraggableManager.tryAndTakeDragging(instanceContainer, this)
|
||||
) {
|
||||
this._draggedByDraggableManager = touchDraggableManager;
|
||||
return true;
|
||||
}
|
||||
@@ -83,40 +89,46 @@ namespace gdjs {
|
||||
return false;
|
||||
}
|
||||
|
||||
_shouldEndDrag(runtimeScene) {
|
||||
_shouldEndDrag(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
if (!this._draggedByDraggableManager) {
|
||||
return false;
|
||||
}
|
||||
return this._draggedByDraggableManager.shouldEndDrag(runtimeScene, this);
|
||||
return this._draggedByDraggableManager.shouldEndDrag(
|
||||
instanceContainer,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
_updateObjectPosition(runtimeScene) {
|
||||
_updateObjectPosition(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
if (!this._draggedByDraggableManager) {
|
||||
return false;
|
||||
}
|
||||
this._draggedByDraggableManager.updateObjectPosition(runtimeScene, this);
|
||||
this._draggedByDraggableManager.updateObjectPosition(
|
||||
instanceContainer,
|
||||
this
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene) {
|
||||
this._tryBeginDrag(runtimeScene);
|
||||
if (this._shouldEndDrag(runtimeScene)) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
this._tryBeginDrag(instanceContainer);
|
||||
if (this._shouldEndDrag(instanceContainer)) {
|
||||
this._endDrag();
|
||||
}
|
||||
this._updateObjectPosition(runtimeScene);
|
||||
this._updateObjectPosition(instanceContainer);
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene) {
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
const mouseDraggableManager = DraggableManager.getMouseManager(
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
mouseDraggableManager.leftPressedLastFrame = runtimeScene
|
||||
mouseDraggableManager.leftPressedLastFrame = instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonPressed(0);
|
||||
}
|
||||
|
||||
isDragged(runtimeScene): boolean {
|
||||
isDragged(instanceContainer: gdjs.RuntimeInstanceContainer): boolean {
|
||||
return !!this._draggedByDraggableManager;
|
||||
}
|
||||
}
|
||||
@@ -137,53 +149,53 @@ namespace gdjs {
|
||||
protected _xOffset: number = 0;
|
||||
protected _yOffset: number = 0;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene) {}
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
/**
|
||||
* Get the platforms manager of a scene.
|
||||
* Get the platforms manager of an instance container.
|
||||
*/
|
||||
static getMouseManager(
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): MouseDraggableManager {
|
||||
// @ts-ignore
|
||||
if (!runtimeScene.mouseDraggableManager) {
|
||||
if (!instanceContainer.mouseDraggableManager) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.mouseDraggableManager = new MouseDraggableManager(
|
||||
runtimeScene
|
||||
instanceContainer.mouseDraggableManager = new MouseDraggableManager(
|
||||
instanceContainer
|
||||
);
|
||||
}
|
||||
// @ts-ignore
|
||||
return runtimeScene.mouseDraggableManager;
|
||||
return instanceContainer.mouseDraggableManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the platforms manager of a scene.
|
||||
* Get the platforms manager of an instance container.
|
||||
*/
|
||||
static getTouchManager(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
touchId: integer
|
||||
): DraggableManager {
|
||||
// @ts-ignore
|
||||
if (!runtimeScene.touchDraggableManagers) {
|
||||
if (!instanceContainer.touchDraggableManagers) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.touchDraggableManagers = [];
|
||||
instanceContainer.touchDraggableManagers = [];
|
||||
}
|
||||
// @ts-ignore
|
||||
if (!runtimeScene.touchDraggableManagers[touchId]) {
|
||||
if (!instanceContainer.touchDraggableManagers[touchId]) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.touchDraggableManagers[
|
||||
instanceContainer.touchDraggableManagers[
|
||||
touchId
|
||||
] = new TouchDraggableManager(runtimeScene, touchId);
|
||||
] = new TouchDraggableManager(instanceContainer, touchId);
|
||||
}
|
||||
// @ts-ignore
|
||||
return runtimeScene.touchDraggableManagers[touchId];
|
||||
return instanceContainer.touchDraggableManagers[touchId];
|
||||
}
|
||||
|
||||
tryAndTakeDragging(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
) {
|
||||
if (
|
||||
@@ -193,7 +205,10 @@ namespace gdjs {
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const position = this.getPosition(runtimeScene, draggableRuntimeBehavior);
|
||||
const position = this.getPosition(
|
||||
instanceContainer,
|
||||
draggableRuntimeBehavior
|
||||
);
|
||||
if (
|
||||
!draggableRuntimeBehavior.owner.insideObject(position[0], position[1])
|
||||
) {
|
||||
@@ -218,10 +233,13 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
updateObjectPosition(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
) {
|
||||
const position = this.getPosition(runtimeScene, draggableRuntimeBehavior);
|
||||
const position = this.getPosition(
|
||||
instanceContainer,
|
||||
draggableRuntimeBehavior
|
||||
);
|
||||
if (
|
||||
draggableRuntimeBehavior.owner.getX() != position[0] - this._xOffset ||
|
||||
draggableRuntimeBehavior.owner.getY() != position[1] - this._yOffset
|
||||
@@ -241,11 +259,11 @@ namespace gdjs {
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): boolean;
|
||||
abstract shouldEndDrag(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): boolean;
|
||||
abstract getPosition(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): FloatPoint;
|
||||
}
|
||||
@@ -257,8 +275,8 @@ namespace gdjs {
|
||||
/** Used to only start dragging when clicking. */
|
||||
leftPressedLastFrame = false;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene) {
|
||||
super(runtimeScene);
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
super(instanceContainer);
|
||||
}
|
||||
|
||||
isDragging(draggableRuntimeBehavior: DraggableRuntimeBehavior): boolean {
|
||||
@@ -266,20 +284,28 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
getPosition(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): FloatPoint {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
return runtimeScene
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
MouseDraggableManager.prototype.getPosition
|
||||
) as FloatPoint;
|
||||
const inputManager = instanceContainer.getGame().getInputManager();
|
||||
return instanceContainer
|
||||
.getLayer(draggableRuntimeBehavior.owner.getLayer())
|
||||
.convertCoords(inputManager.getMouseX(), inputManager.getMouseY());
|
||||
.convertCoords(
|
||||
inputManager.getMouseX(),
|
||||
inputManager.getMouseY(),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
}
|
||||
|
||||
shouldEndDrag(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): boolean {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
const inputManager = instanceContainer.getGame().getInputManager();
|
||||
return !inputManager.isMouseButtonPressed(0);
|
||||
}
|
||||
}
|
||||
@@ -290,8 +316,11 @@ namespace gdjs {
|
||||
class TouchDraggableManager extends DraggableManager {
|
||||
private _touchId: integer;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene, touchId: integer) {
|
||||
super(runtimeScene);
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
touchId: integer
|
||||
) {
|
||||
super(instanceContainer);
|
||||
this._touchId = touchId;
|
||||
}
|
||||
|
||||
@@ -300,23 +329,28 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
getPosition(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): FloatPoint {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
return runtimeScene
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
TouchDraggableManager.prototype.getPosition
|
||||
) as FloatPoint;
|
||||
const inputManager = instanceContainer.getGame().getInputManager();
|
||||
return instanceContainer
|
||||
.getLayer(draggableRuntimeBehavior.owner.getLayer())
|
||||
.convertCoords(
|
||||
inputManager.getTouchX(this._touchId),
|
||||
inputManager.getTouchY(this._touchId)
|
||||
inputManager.getTouchY(this._touchId),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
}
|
||||
|
||||
shouldEndDrag(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
draggableRuntimeBehavior: DraggableRuntimeBehavior
|
||||
): boolean {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
const inputManager = instanceContainer.getGame().getInputManager();
|
||||
return (
|
||||
inputManager.getAllTouchIdentifiers().indexOf(this._touchId) === -1
|
||||
);
|
||||
|
||||
@@ -11,11 +11,11 @@ namespace gdjs {
|
||||
_textToSet: string;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData: any,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
|
||||
// Here you can access to the behavior data (JSON declared in JsExtension.js)
|
||||
// using behaviorData:
|
||||
@@ -37,7 +37,7 @@ namespace gdjs {
|
||||
|
||||
onDeActivate() {}
|
||||
|
||||
doStepPreEvents(runtimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// This is run at every frame, before events are launched.
|
||||
this.owner
|
||||
.getVariables()
|
||||
@@ -45,7 +45,7 @@ namespace gdjs {
|
||||
.setString(this._textToSet);
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene) {
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// This is run at every frame, after events are launched.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* @param runtimeObject The object to render
|
||||
* @param runtimeScene The gdjs.RuntimeScene in which the object is
|
||||
* @param instanceContainer The gdjs.RuntimeScene in which the object is
|
||||
*/
|
||||
constructor(
|
||||
runtimeObject: gdjs.DummyRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
|
||||
@@ -27,12 +27,12 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
// You can also create a PIXI sprite or other PIXI object
|
||||
// this._imageManager = runtimeScene.getGame().getImageManager();
|
||||
// this._imageManager = instanceContainer.getGame().getImageManager();
|
||||
// if ( this._sprite === undefined )
|
||||
// this._sprite = new PIXI.Sprite(this._imageManager.getInvalidPIXITexture());
|
||||
this._text.anchor.x = 0.5;
|
||||
this._text.anchor.y = 0.5;
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._text, runtimeObject.getZOrder());
|
||||
|
||||
@@ -14,11 +14,14 @@ namespace gdjs {
|
||||
// @ts-expect-error ts-migrate(2564) FIXME: Property 'opacity' has no initializer and is not d... Remove this comment to see the full error message
|
||||
opacity: float;
|
||||
|
||||
constructor(runtimeScene, objectData) {
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer, objectData) {
|
||||
// *ALWAYS* call the base gdjs.RuntimeObject constructor.
|
||||
super(runtimeScene, objectData);
|
||||
super(instanceContainer, objectData);
|
||||
this._property1 = objectData.content.property1;
|
||||
this._renderer = new gdjs.DummyRuntimeObjectRenderer(this, runtimeScene);
|
||||
this._renderer = new gdjs.DummyRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
@@ -40,9 +43,9 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Called once during the game loop, before events and rendering.
|
||||
* @param runtimeScene The gdjs.RuntimeScene the object belongs to.
|
||||
* @param instanceContainer The gdjs.RuntimeScene the object belongs to.
|
||||
*/
|
||||
update(runtimeScene: gdjs.RuntimeScene): void {
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
// This is an example: typically you want to make sure the renderer
|
||||
// is up to date with the object.
|
||||
this._renderer.ensureUpToDate();
|
||||
|
||||
@@ -4,20 +4,20 @@ namespace gdjs {
|
||||
_textToSet: string;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData: any,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
|
||||
// Here you can access to the behavior data (JSON declared in JsExtension.js)
|
||||
// using behaviorData:
|
||||
this._textToSet = behaviorData.property1;
|
||||
|
||||
// You can also access to the shared data:
|
||||
const sharedData = runtimeScene.getInitialSharedDataForBehavior(
|
||||
behaviorData.name
|
||||
);
|
||||
const sharedData = instanceContainer
|
||||
.getScene()
|
||||
.getInitialSharedDataForBehavior(behaviorData.name);
|
||||
this._textToSet = (sharedData as any).sharedProperty1;
|
||||
|
||||
// You can also run arbitrary code at the creation of the behavior:
|
||||
@@ -40,7 +40,7 @@ namespace gdjs {
|
||||
|
||||
onDeActivate() {}
|
||||
|
||||
doStepPreEvents(runtimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// This is run at every frame, before events are launched.
|
||||
this.owner
|
||||
.getVariables()
|
||||
@@ -48,7 +48,7 @@ namespace gdjs {
|
||||
.setString(this._textToSet);
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene) {
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// This is run at every frame, after events are launched.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,9 @@ namespace gdjs {
|
||||
* In **rare cases** you may want to run code at the start of the scene. You can define a callback
|
||||
* that will be called at this moment.
|
||||
*/
|
||||
gdjs.registerRuntimeSceneLoadedCallback(function (runtimeScene) {
|
||||
gdjs.registerRuntimeSceneLoadedCallback(function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
logger.log('A gdjs.RuntimeScene was loaded:', runtimeScene);
|
||||
});
|
||||
|
||||
@@ -33,7 +35,9 @@ namespace gdjs {
|
||||
* In **rare cases** you may want to run code at the end of a scene. You can define a callback
|
||||
* that will be called at this moment.
|
||||
*/
|
||||
gdjs.registerRuntimeSceneUnloadedCallback(function (runtimeScene) {
|
||||
gdjs.registerRuntimeSceneUnloadedCallback(function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
logger.log('A gdjs.RuntimeScene was unloaded:', runtimeScene);
|
||||
});
|
||||
|
||||
@@ -41,12 +45,12 @@ namespace gdjs {
|
||||
* In **very rare cases** you may want to run code whenever an object is deleted.
|
||||
*/
|
||||
gdjs.registerObjectDeletedFromSceneCallback(function (
|
||||
runtimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
runtimeObject
|
||||
) {
|
||||
logger.log(
|
||||
'A gdjs.RuntimeObject was deleted from a gdjs.RuntimeScene:',
|
||||
runtimeScene,
|
||||
instanceContainer,
|
||||
runtimeObject
|
||||
);
|
||||
});
|
||||
|
||||
@@ -48,13 +48,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Get the path to 'Desktop' folder.
|
||||
* @param runtimeScene The current scene
|
||||
* @param instanceContainer The current container
|
||||
* @return The path to the desktop folder
|
||||
*/
|
||||
export const getDesktopPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): string {
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const remote = instanceContainer
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('desktop') || '';
|
||||
@@ -65,13 +68,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Get the path to 'Documents' folder.
|
||||
* @param runtimeScene The current scene
|
||||
* @param instanceContainer The current container
|
||||
* @return The path to the documents folder
|
||||
*/
|
||||
export const getDocumentsPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): string {
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const remote = instanceContainer
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('documents') || '';
|
||||
@@ -82,13 +88,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Get the path to 'Pictures' folder.
|
||||
* @param runtimeScene The current scene
|
||||
* @param instanceContainer The current container
|
||||
* @return The path to the pictures folder
|
||||
*/
|
||||
export const getPicturesPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): string {
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const remote = instanceContainer
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('pictures') || '';
|
||||
@@ -99,13 +108,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Get the path to this application 'Executable' file.
|
||||
* @param runtimeScene The current scene
|
||||
* @param instanceContainer The current container
|
||||
* @return The path to this applications executable file
|
||||
*/
|
||||
export const getExecutablePath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): string {
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const remote = instanceContainer
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('exe') || '';
|
||||
@@ -116,14 +128,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Get the path to this application 'Executable' folder.
|
||||
* @param runtimeScene The current scene
|
||||
* @param instanceContainer The current container
|
||||
* @return The path to this applications executable folder
|
||||
*/
|
||||
export const getExecutableFolderPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): string {
|
||||
const path = gdjs.fileSystem._getPath();
|
||||
const executablePath = gdjs.fileSystem.getExecutablePath(runtimeScene);
|
||||
const executablePath = gdjs.fileSystem.getExecutablePath(
|
||||
instanceContainer
|
||||
);
|
||||
if (!path) {
|
||||
return '';
|
||||
}
|
||||
@@ -132,13 +146,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Get the path to 'UserData' folder.
|
||||
* @param runtimeScene The current scene
|
||||
* @param instanceContainer The current container
|
||||
* @return The path to userdata folder
|
||||
*/
|
||||
export const getUserdataPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): string {
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const remote = instanceContainer
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('userData') || '';
|
||||
@@ -152,9 +169,12 @@ namespace gdjs {
|
||||
* @return The path to user's "home" folder
|
||||
*/
|
||||
export const getUserHomePath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): string {
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const remote = instanceContainer
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('home') || '';
|
||||
@@ -165,13 +185,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Get the path to 'Temp' folder.
|
||||
* @param runtimeScene The current scene
|
||||
* @param instanceContainer The current container
|
||||
* @return The path to temp folder
|
||||
*/
|
||||
export const getTempPath = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): string {
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
const remote = instanceContainer
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
const app = remote ? remote.app : null;
|
||||
if (app) {
|
||||
return app.getPath('temp') || '';
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
namespace gdjs {
|
||||
export interface RuntimeGame {
|
||||
inventories: { [name: string]: gdjs.Inventory };
|
||||
}
|
||||
export class InventoryManager {
|
||||
static get(runtimeScene, name): gdjs.Inventory {
|
||||
const game = runtimeScene.getGame();
|
||||
static get(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
name: string
|
||||
): gdjs.Inventory {
|
||||
const game = instanceContainer.getGame();
|
||||
if (!game.inventories) {
|
||||
game.inventories = {};
|
||||
}
|
||||
@@ -15,70 +21,106 @@ namespace gdjs {
|
||||
|
||||
export namespace evtTools {
|
||||
export namespace inventory {
|
||||
export const add = function (runtimeScene, inventoryName, name) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).add(name);
|
||||
export const add = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string
|
||||
) {
|
||||
return InventoryManager.get(instanceContainer, inventoryName).add(name);
|
||||
};
|
||||
|
||||
export const remove = function (runtimeScene, inventoryName, name) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).remove(name);
|
||||
export const remove = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string
|
||||
) {
|
||||
return InventoryManager.get(instanceContainer, inventoryName).remove(
|
||||
name
|
||||
);
|
||||
};
|
||||
|
||||
export const count = function (runtimeScene, inventoryName, name) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).count(name);
|
||||
export const count = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string
|
||||
) {
|
||||
return InventoryManager.get(instanceContainer, inventoryName).count(
|
||||
name
|
||||
);
|
||||
};
|
||||
|
||||
export const has = function (runtimeScene, inventoryName, name) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).has(name);
|
||||
export const has = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string
|
||||
) {
|
||||
return InventoryManager.get(instanceContainer, inventoryName).has(name);
|
||||
};
|
||||
|
||||
export const setMaximum = function (
|
||||
runtimeScene,
|
||||
inventoryName,
|
||||
name,
|
||||
maxCount
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string,
|
||||
maxCount: number
|
||||
) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).setMaximum(
|
||||
name,
|
||||
maxCount
|
||||
);
|
||||
return InventoryManager.get(
|
||||
instanceContainer,
|
||||
inventoryName
|
||||
).setMaximum(name, maxCount);
|
||||
};
|
||||
|
||||
export const setUnlimited = function (
|
||||
runtimeScene,
|
||||
inventoryName,
|
||||
name,
|
||||
enable
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string,
|
||||
enable: boolean
|
||||
) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).setUnlimited(
|
||||
name,
|
||||
enable
|
||||
return InventoryManager.get(
|
||||
instanceContainer,
|
||||
inventoryName
|
||||
).setUnlimited(name, enable);
|
||||
};
|
||||
|
||||
export const isFull = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string
|
||||
) {
|
||||
return InventoryManager.get(instanceContainer, inventoryName).isFull(
|
||||
name
|
||||
);
|
||||
};
|
||||
|
||||
export const isFull = function (runtimeScene, inventoryName, name) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).isFull(name);
|
||||
};
|
||||
|
||||
export const equip = function (runtimeScene, inventoryName, name, equip) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).equip(
|
||||
export const equip = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string,
|
||||
equip: boolean
|
||||
) {
|
||||
return InventoryManager.get(instanceContainer, inventoryName).equip(
|
||||
name,
|
||||
equip
|
||||
);
|
||||
};
|
||||
|
||||
export const isEquipped = function (runtimeScene, inventoryName, name) {
|
||||
return InventoryManager.get(runtimeScene, inventoryName).isEquipped(
|
||||
name
|
||||
);
|
||||
export const isEquipped = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
name: string
|
||||
) {
|
||||
return InventoryManager.get(
|
||||
instanceContainer,
|
||||
inventoryName
|
||||
).isEquipped(name);
|
||||
};
|
||||
|
||||
export const serializeToVariable = function (
|
||||
runtimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
variable: gdjs.Variable
|
||||
) {
|
||||
const allItems = gdjs.InventoryManager.get(
|
||||
runtimeScene,
|
||||
instanceContainer,
|
||||
inventoryName
|
||||
).getAllItems();
|
||||
for (const name in allItems) {
|
||||
@@ -92,12 +134,12 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const unserializeFromVariable = function (
|
||||
runtimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
inventoryName: string,
|
||||
variable: gdjs.Variable
|
||||
) {
|
||||
const inventory = gdjs.InventoryManager.get(
|
||||
runtimeScene,
|
||||
instanceContainer,
|
||||
inventoryName
|
||||
);
|
||||
inventory.clear();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/// <reference path="sha256.d.ts" />
|
||||
|
||||
// TODO EBO Replace runtimeScene to instanceContainer.
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('Leaderboards');
|
||||
export namespace evtTools {
|
||||
|
||||
@@ -4,26 +4,26 @@ namespace gdjs {
|
||||
export class LightObstaclesManager {
|
||||
_obstacleRBush: any;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene) {
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
this._obstacleRBush = new rbush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the light obstacles manager of a scene.
|
||||
* Get the light obstacles manager of an instance container.
|
||||
*/
|
||||
static getManager(
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): gdjs.LightObstaclesManager {
|
||||
// @ts-ignore
|
||||
if (!runtimeScene._lightObstaclesManager) {
|
||||
if (!instanceContainer._lightObstaclesManager) {
|
||||
// Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene._lightObstaclesManager = new gdjs.LightObstaclesManager(
|
||||
runtimeScene
|
||||
instanceContainer._lightObstaclesManager = new gdjs.LightObstaclesManager(
|
||||
instanceContainer
|
||||
);
|
||||
}
|
||||
// @ts-ignore
|
||||
return runtimeScene._lightObstaclesManager;
|
||||
return instanceContainer._lightObstaclesManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,15 +92,15 @@ namespace gdjs {
|
||||
_registeredInManager: boolean = false;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
this._manager = LightObstaclesManager.getManager(runtimeScene);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._manager = LightObstaclesManager.getManager(instanceContainer);
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// Make sure the obstacle is or is not in the obstacles manager.
|
||||
if (!this.activated() && this._registeredInManager) {
|
||||
this._manager.removeObstacle(this);
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace gdjs {
|
||||
*/
|
||||
export class LightRuntimeObjectPixiRenderer {
|
||||
_object: gdjs.LightRuntimeObject;
|
||||
_runtimeScene: gdjs.RuntimeScene;
|
||||
_instanceContainer: gdjs.RuntimeInstanceContainer;
|
||||
_manager: gdjs.LightObstaclesManager;
|
||||
_radius: number;
|
||||
_color: [number, number, number];
|
||||
@@ -30,10 +30,10 @@ namespace gdjs {
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.LightRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._runtimeScene = runtimeScene;
|
||||
this._instanceContainer = instanceContainer;
|
||||
this._manager = runtimeObject.getObstaclesManager();
|
||||
this._radius = runtimeObject.getRadius();
|
||||
const objectColor = runtimeObject._color;
|
||||
@@ -57,14 +57,14 @@ namespace gdjs {
|
||||
]);
|
||||
this._indexBuffer = new Uint16Array([0, 1, 2, 0, 2, 3]);
|
||||
this.updateMesh();
|
||||
this._isPreview = runtimeScene.getGame().isPreview();
|
||||
this._isPreview = instanceContainer.getGame().isPreview();
|
||||
this._lightBoundingPoly = gdjs.Polygon.createRectangle(0, 0);
|
||||
|
||||
this.updateDebugMode();
|
||||
|
||||
// Objects will be added in lighting layer, this is just to maintain consistency.
|
||||
if (this._light) {
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(
|
||||
@@ -198,7 +198,7 @@ namespace gdjs {
|
||||
const texture = this._object.getTexture();
|
||||
this._texture =
|
||||
texture !== ''
|
||||
? (this._runtimeScene
|
||||
? (this._instanceContainer
|
||||
.getGame()
|
||||
.getImageManager() as gdjs.PixiImageManager).getPIXITexture(
|
||||
texture
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace gdjs {
|
||||
_texture: string;
|
||||
_obstaclesManager: gdjs.LightObstaclesManager;
|
||||
_renderer: gdjs.LightRuntimeObjectRenderer;
|
||||
_runtimeScene: gdjs.RuntimeScene;
|
||||
_instanceContainer: gdjs.RuntimeScene;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
@@ -43,7 +43,7 @@ namespace gdjs {
|
||||
runtimeScene
|
||||
);
|
||||
this._renderer = new gdjs.LightRuntimeObjectRenderer(this, runtimeScene);
|
||||
this._runtimeScene = runtimeScene;
|
||||
this._instanceContainer = runtimeScene;
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
|
||||
@@ -12,15 +12,17 @@ namespace gdjs {
|
||||
/**
|
||||
* Get the links manager of a scene.
|
||||
*/
|
||||
static getManager(runtimeScene: gdjs.RuntimeScene): gdjs.LinksManager {
|
||||
static getManager(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): gdjs.LinksManager {
|
||||
// @ts-ignore
|
||||
if (!runtimeScene.linkedObjectsManager) {
|
||||
if (!instanceContainer.linkedObjectsManager) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.linkedObjectsManager = new gdjs.LinksManager();
|
||||
instanceContainer.linkedObjectsManager = new gdjs.LinksManager();
|
||||
}
|
||||
// @ts-ignore
|
||||
return runtimeScene.linkedObjectsManager;
|
||||
return instanceContainer.linkedObjectsManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,44 +186,50 @@ namespace gdjs {
|
||||
|
||||
export namespace evtTools {
|
||||
export namespace linkedObjects {
|
||||
gdjs.registerObjectDeletedFromSceneCallback(function (runtimeScene, obj) {
|
||||
LinksManager.getManager(runtimeScene).removeAllLinksOf(obj);
|
||||
gdjs.registerObjectDeletedFromSceneCallback(function (
|
||||
instanceContainer,
|
||||
obj
|
||||
) {
|
||||
LinksManager.getManager(instanceContainer).removeAllLinksOf(obj);
|
||||
});
|
||||
|
||||
export const linkObjects = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objA: gdjs.RuntimeObject,
|
||||
objB: gdjs.RuntimeObject
|
||||
) {
|
||||
if (objA === null || objB === null) {
|
||||
return;
|
||||
}
|
||||
LinksManager.getManager(runtimeScene).linkObjects(objA, objB);
|
||||
LinksManager.getManager(instanceContainer).linkObjects(objA, objB);
|
||||
};
|
||||
|
||||
export const removeLinkBetween = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objA: gdjs.RuntimeObject,
|
||||
objB: gdjs.RuntimeObject
|
||||
) {
|
||||
if (objA === null || objB === null) {
|
||||
return;
|
||||
}
|
||||
LinksManager.getManager(runtimeScene).removeLinkBetween(objA, objB);
|
||||
LinksManager.getManager(instanceContainer).removeLinkBetween(
|
||||
objA,
|
||||
objB
|
||||
);
|
||||
};
|
||||
|
||||
export const removeAllLinksOf = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objA: gdjs.RuntimeObject
|
||||
) {
|
||||
if (objA === null) {
|
||||
return;
|
||||
}
|
||||
LinksManager.getManager(runtimeScene).removeAllLinksOf(objA);
|
||||
LinksManager.getManager(instanceContainer).removeAllLinksOf(objA);
|
||||
};
|
||||
|
||||
export const pickObjectsLinkedTo = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectsLists: Hashtable<gdjs.RuntimeObject[]>,
|
||||
obj: gdjs.RuntimeObject,
|
||||
eventsFunctionContext: EventsFunctionContext | undefined
|
||||
@@ -230,7 +238,7 @@ namespace gdjs {
|
||||
return false;
|
||||
}
|
||||
const linkedObjectMap = LinksManager.getManager(
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
)._getMapOfObjectsLinkedWith(obj);
|
||||
|
||||
let pickedSomething = false;
|
||||
@@ -273,7 +281,7 @@ namespace gdjs {
|
||||
// avoid running an intersection with the picked objects later.
|
||||
let objectCount = 0;
|
||||
for (const objectName of parentEventPickedObjectNames) {
|
||||
objectCount += runtimeScene.getObjects(objectName).length;
|
||||
objectCount += instanceContainer.getObjects(objectName)!.length;
|
||||
}
|
||||
|
||||
if (parentEventPickedObjects.length === objectCount) {
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace gdjs {
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.PanelSpriteRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
textureName: string,
|
||||
tiled: boolean
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
const texture = (runtimeScene
|
||||
const texture = (instanceContainer
|
||||
.getGame()
|
||||
.getImageManager() as gdjs.PixiImageManager).getPIXITexture(
|
||||
textureName
|
||||
@@ -58,14 +58,14 @@ namespace gdjs {
|
||||
];
|
||||
|
||||
//Bottom-Right
|
||||
this.setTexture(textureName, runtimeScene);
|
||||
this.setTexture(textureName, instanceContainer);
|
||||
this._spritesContainer.removeChildren();
|
||||
this._spritesContainer.addChild(this._centerSprite);
|
||||
for (let i = 0; i < this._borderSprites.length; ++i) {
|
||||
this._spritesContainer.addChild(this._borderSprites[i]);
|
||||
}
|
||||
this._wrapperContainer.addChild(this._spritesContainer);
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._wrapperContainer, runtimeObject.getZOrder());
|
||||
@@ -188,12 +188,19 @@ namespace gdjs {
|
||||
this._spritesContainer.cacheAsBitmap = false;
|
||||
}
|
||||
|
||||
setTexture(textureName, runtimeScene): void {
|
||||
setTexture(
|
||||
textureName: string,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
const obj = this._object;
|
||||
const texture = runtimeScene
|
||||
// @ts-ignore
|
||||
const texture = instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getPIXITexture(textureName);
|
||||
.getPIXITexture(textureName) as PIXI.BaseTexture<
|
||||
PIXI.Resource,
|
||||
PIXI.IAutoDetectOptions
|
||||
>;
|
||||
this._textureWidth = texture.width;
|
||||
this._textureHeight = texture.height;
|
||||
|
||||
|
||||
@@ -43,14 +43,14 @@ namespace gdjs {
|
||||
_renderer: gdjs.PanelSpriteRuntimeObjectRenderer;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
* @param panelSpriteObjectData The initial properties of the object
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
panelSpriteObjectData: PanelSpriteObjectData
|
||||
) {
|
||||
super(runtimeScene, panelSpriteObjectData);
|
||||
super(instanceContainer, panelSpriteObjectData);
|
||||
this._rBorder = panelSpriteObjectData.rightMargin;
|
||||
this._lBorder = panelSpriteObjectData.leftMargin;
|
||||
this._tBorder = panelSpriteObjectData.topMargin;
|
||||
@@ -60,7 +60,7 @@ namespace gdjs {
|
||||
this._height = panelSpriteObjectData.height;
|
||||
this._renderer = new gdjs.PanelSpriteRuntimeObjectRenderer(
|
||||
this,
|
||||
runtimeScene,
|
||||
instanceContainer,
|
||||
panelSpriteObjectData.texture,
|
||||
panelSpriteObjectData.tiled
|
||||
);
|
||||
@@ -100,7 +100,7 @@ namespace gdjs {
|
||||
updateTexture = true;
|
||||
}
|
||||
if (updateTexture) {
|
||||
this.setTexture(newObjectData.texture, this._runtimeScene);
|
||||
this.setTexture(newObjectData.texture, this.getRuntimeScene());
|
||||
}
|
||||
if (oldObjectData.tiled !== newObjectData.tiled) {
|
||||
return false;
|
||||
@@ -112,8 +112,8 @@ namespace gdjs {
|
||||
return this._renderer.getRendererObject();
|
||||
}
|
||||
|
||||
onDestroyFromScene(runtimeScene): void {
|
||||
super.onDestroyFromScene(runtimeScene);
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
// @ts-ignore
|
||||
if (this._renderer.onDestroy) {
|
||||
// @ts-ignore
|
||||
@@ -121,7 +121,7 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
update(runtimeScene: gdjs.RuntimeScene): void {
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
this._renderer.ensureUpToDate();
|
||||
}
|
||||
|
||||
@@ -156,10 +156,13 @@ namespace gdjs {
|
||||
/**
|
||||
* Set the texture of the panel sprite.
|
||||
* @param textureName The name of the texture.
|
||||
* @param runtimeScene The scene the object lives in.
|
||||
* @param instanceContainer The container the object lives in.
|
||||
*/
|
||||
setTexture(textureName: string, runtimeScene: gdjs.RuntimeScene): void {
|
||||
this._renderer.setTexture(textureName, runtimeScene);
|
||||
setTexture(
|
||||
textureName: string,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
this._renderer.setTexture(textureName, instanceContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +199,7 @@ namespace gdjs {
|
||||
|
||||
this._width = width;
|
||||
this._renderer.updateWidth();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +211,7 @@ namespace gdjs {
|
||||
|
||||
this._height = height;
|
||||
this._renderer.updateHeight();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace gdjs {
|
||||
started: boolean = false;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
runtimeObject: gdjs.RuntimeObject,
|
||||
objectData: any
|
||||
) {
|
||||
@@ -40,7 +40,7 @@ namespace gdjs {
|
||||
);
|
||||
} else if (objectData.textureParticleName) {
|
||||
const sprite = new PIXI.Sprite(
|
||||
(runtimeScene
|
||||
(instanceContainer
|
||||
.getGame()
|
||||
.getImageManager() as gdjs.PixiImageManager).getPIXITexture(
|
||||
objectData.textureParticleName
|
||||
@@ -62,7 +62,7 @@ namespace gdjs {
|
||||
// Render the texture from graphics using the PIXI Renderer.
|
||||
// TODO: could be optimized by generating the texture only once per object type,
|
||||
// instead of at each object creation.
|
||||
const pixiRenderer = runtimeScene
|
||||
const pixiRenderer = instanceContainer
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getPIXIRenderer();
|
||||
@@ -167,7 +167,7 @@ namespace gdjs {
|
||||
// @ts-ignore
|
||||
this.emitter = new PIXI.particles.Emitter(this.renderer, texture, config);
|
||||
this.start();
|
||||
const layer = runtimeScene.getLayer(runtimeObject.getLayer());
|
||||
const layer = instanceContainer.getLayer(runtimeObject.getLayer());
|
||||
if (layer) {
|
||||
layer
|
||||
.getRenderer()
|
||||
@@ -267,25 +267,28 @@ namespace gdjs {
|
||||
|
||||
isTextureNameValid(
|
||||
texture: string,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): boolean {
|
||||
const invalidPixiTexture = runtimeScene
|
||||
const invalidPixiTexture = instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getInvalidPIXITexture();
|
||||
const pixiTexture = runtimeScene
|
||||
const pixiTexture = instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getPIXITexture(texture);
|
||||
return pixiTexture.valid && pixiTexture !== invalidPixiTexture;
|
||||
}
|
||||
|
||||
setTextureName(texture: string, runtimeScene: gdjs.RuntimeScene): void {
|
||||
const invalidPixiTexture = runtimeScene
|
||||
setTextureName(
|
||||
texture: string,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
const invalidPixiTexture = instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getInvalidPIXITexture();
|
||||
const pixiTexture = runtimeScene
|
||||
const pixiTexture = instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getPIXITexture(texture);
|
||||
|
||||
@@ -97,12 +97,12 @@ namespace gdjs {
|
||||
* @param particleObjectData The initial properties of the object
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
particleObjectData: ParticleEmitterObjectData
|
||||
) {
|
||||
super(runtimeScene, particleObjectData);
|
||||
super(instanceContainer, particleObjectData);
|
||||
this._renderer = new gdjs.ParticleEmitterObjectRenderer(
|
||||
runtimeScene,
|
||||
instanceContainer,
|
||||
this,
|
||||
particleObjectData
|
||||
);
|
||||
@@ -231,7 +231,10 @@ namespace gdjs {
|
||||
if (
|
||||
oldObjectData.textureParticleName !== newObjectData.textureParticleName
|
||||
) {
|
||||
this.setTexture(newObjectData.textureParticleName, this._runtimeScene);
|
||||
this.setTexture(
|
||||
newObjectData.textureParticleName,
|
||||
this.getRuntimeScene()
|
||||
);
|
||||
}
|
||||
if (oldObjectData.flow !== newObjectData.flow) {
|
||||
this.setFlow(newObjectData.flow);
|
||||
@@ -259,7 +262,7 @@ namespace gdjs {
|
||||
oldObjectData.rendererParam2 !== newObjectData.rendererParam2
|
||||
) {
|
||||
// Destroy the renderer, ensure it's removed from the layer.
|
||||
const layer = this._runtimeScene.getLayer(this.layer);
|
||||
const layer = this.getInstanceContainer().getLayer(this.layer);
|
||||
layer
|
||||
.getRenderer()
|
||||
.removeRendererObject(this._renderer.getRendererObject());
|
||||
@@ -267,7 +270,7 @@ namespace gdjs {
|
||||
|
||||
// and recreate the renderer, which will add itself to the layer.
|
||||
this._renderer = new gdjs.ParticleEmitterObjectRenderer(
|
||||
this._runtimeScene,
|
||||
this.getInstanceContainer(),
|
||||
this,
|
||||
newObjectData
|
||||
);
|
||||
@@ -281,7 +284,7 @@ namespace gdjs {
|
||||
return true;
|
||||
}
|
||||
|
||||
update(runtimeScene): void {
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if (this._posDirty) {
|
||||
this._renderer.setPosition(this.getX(), this.getY());
|
||||
}
|
||||
@@ -324,24 +327,24 @@ namespace gdjs {
|
||||
this._renderer.resetEmission(this.flow, this.tank);
|
||||
}
|
||||
if (this._textureDirty) {
|
||||
this._renderer.setTextureName(this.texture, runtimeScene);
|
||||
this._renderer.setTextureName(this.texture, instanceContainer);
|
||||
}
|
||||
this._posDirty = this._angleDirty = this._forceDirty = this._zoneRadiusDirty = false;
|
||||
this._lifeTimeDirty = this._gravityDirty = this._colorDirty = this._sizeDirty = false;
|
||||
this._alphaDirty = this._flowDirty = this._textureDirty = this._tankDirty = false;
|
||||
this._renderer.update(this.getElapsedTime(runtimeScene) / 1000.0);
|
||||
this._renderer.update(this.getElapsedTime() / 1000.0);
|
||||
if (
|
||||
this._renderer.hasStarted() &&
|
||||
this.getParticleCount() === 0 &&
|
||||
this.destroyWhenNoParticles
|
||||
) {
|
||||
this.deleteFromScene(runtimeScene);
|
||||
this.deleteFromScene(instanceContainer);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroyFromScene(runtimeScene: gdjs.RuntimeScene): void {
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
this._renderer.destroy();
|
||||
super.onDestroyFromScene(runtimeScene);
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
}
|
||||
|
||||
getEmitterForceMin(): number {
|
||||
@@ -734,9 +737,12 @@ namespace gdjs {
|
||||
return this.texture;
|
||||
}
|
||||
|
||||
setTexture(texture: string, runtimeScene: gdjs.RuntimeScene): void {
|
||||
setTexture(
|
||||
texture: string,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
if (this.texture !== texture) {
|
||||
if (this._renderer.isTextureNameValid(texture, runtimeScene)) {
|
||||
if (this._renderer.isTextureNameValid(texture, instanceContainer)) {
|
||||
this.texture = texture;
|
||||
this._textureDirty = true;
|
||||
}
|
||||
|
||||
@@ -4,35 +4,37 @@ Copyright (c) 2013-2016 Florian Rival ([email protected])
|
||||
*/
|
||||
|
||||
namespace gdjs {
|
||||
export interface RuntimeInstanceContainer {
|
||||
pathfindingObstaclesManager: gdjs.PathfindingObstaclesManager;
|
||||
}
|
||||
declare var rbush: any;
|
||||
|
||||
/**
|
||||
* PathfindingObstaclesManager manages the common objects shared by objects having a
|
||||
* pathfinding behavior: In particular, the obstacles behaviors are required to declare
|
||||
* themselves (see `PathfindingObstaclesManager.addObstacle`) to the manager of their associated scene
|
||||
* (see `gdjs.PathfindingRuntimeBehavior.obstaclesManagers`).
|
||||
* PathfindingObstaclesManager manages the common objects shared by objects
|
||||
* having a pathfinding behavior: In particular, the obstacles behaviors are
|
||||
* required to declare themselves (see
|
||||
* `PathfindingObstaclesManager.addObstacle`) to the manager of their
|
||||
* associated container (see
|
||||
* `gdjs.PathfindingRuntimeBehavior.obstaclesManagers`).
|
||||
*/
|
||||
export class PathfindingObstaclesManager {
|
||||
_obstaclesRBush: any;
|
||||
|
||||
/**
|
||||
* @param object The object
|
||||
*/
|
||||
constructor(runtimeScene: gdjs.RuntimeScene) {
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
this._obstaclesRBush = new rbush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the obstacles manager of a scene.
|
||||
* Get the obstacles manager of an instance container.
|
||||
*/
|
||||
static getManager(runtimeScene) {
|
||||
if (!runtimeScene.pathfindingObstaclesManager) {
|
||||
static getManager(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
if (!instanceContainer.pathfindingObstaclesManager) {
|
||||
//Create the shared manager if necessary.
|
||||
runtimeScene.pathfindingObstaclesManager = new gdjs.PathfindingObstaclesManager(
|
||||
runtimeScene
|
||||
instanceContainer.pathfindingObstaclesManager = new gdjs.PathfindingObstaclesManager(
|
||||
instanceContainer
|
||||
);
|
||||
}
|
||||
return runtimeScene.pathfindingObstaclesManager;
|
||||
return instanceContainer.pathfindingObstaclesManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,14 +113,14 @@ namespace gdjs {
|
||||
> | null = null;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._impassable = behaviorData.impassable;
|
||||
this._cost = behaviorData.cost;
|
||||
this._manager = PathfindingObstaclesManager.getManager(runtimeScene);
|
||||
this._manager = PathfindingObstaclesManager.getManager(instanceContainer);
|
||||
|
||||
//Note that we can't use getX(), getWidth()... of owner here:
|
||||
//The owner is not yet fully constructed.
|
||||
@@ -140,7 +142,7 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
//Make sure the obstacle is or is not in the obstacles manager.
|
||||
if (!this.activated() && this._registeredInManager) {
|
||||
this._manager.removeObstacle(this);
|
||||
@@ -170,7 +172,7 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene: gdjs.RuntimeScene) {}
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
getAABB() {
|
||||
return this.owner.getAABB();
|
||||
|
||||
@@ -38,11 +38,11 @@ namespace gdjs {
|
||||
_movementAngle: float = 0;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
|
||||
//The path computed and followed by the object (Array of arrays containing x and y position)
|
||||
if (this._path === undefined) {
|
||||
@@ -60,7 +60,9 @@ namespace gdjs {
|
||||
this._gridOffsetX = behaviorData.gridOffsetX || 0;
|
||||
this._gridOffsetY = behaviorData.gridOffsetY || 0;
|
||||
this._extraBorder = behaviorData.extraBorder;
|
||||
this._manager = gdjs.PathfindingObstaclesManager.getManager(runtimeScene);
|
||||
this._manager = gdjs.PathfindingObstaclesManager.getManager(
|
||||
instanceContainer
|
||||
);
|
||||
this._searchContext = new gdjs.PathfindingRuntimeBehavior.SearchContext(
|
||||
this._manager
|
||||
);
|
||||
@@ -313,7 +315,11 @@ namespace gdjs {
|
||||
/**
|
||||
* Compute and move on the path to the specified destination.
|
||||
*/
|
||||
moveTo(runtimeScene: gdjs.RuntimeScene, x: float, y: float) {
|
||||
moveTo(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
x: float,
|
||||
y: float
|
||||
) {
|
||||
const owner = this.owner;
|
||||
|
||||
//First be sure that there is a path to compute.
|
||||
@@ -403,13 +409,13 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
if (this._path.length === 0 || this._reachedEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the speed of the object
|
||||
const timeDelta = this.owner.getElapsedTime(runtimeScene) / 1000;
|
||||
const timeDelta = this.owner.getElapsedTime() / 1000;
|
||||
const previousSpeed = this._speed;
|
||||
if (this._speed !== this._maxSpeed) {
|
||||
this._speed += this._acceleration * timeDelta;
|
||||
@@ -452,8 +458,7 @@ namespace gdjs {
|
||||
) {
|
||||
this.owner.rotateTowardAngle(
|
||||
this._movementAngle + this._angleOffset,
|
||||
this._angularSpeed,
|
||||
runtimeScene
|
||||
this._angularSpeed
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -463,7 +468,7 @@ namespace gdjs {
|
||||
this.owner.setY(newPos[1]);
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene: gdjs.RuntimeScene) {}
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
/**
|
||||
* Compute the euclidean distance between two positions.
|
||||
|
||||
@@ -61,9 +61,14 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
sprites: [
|
||||
{
|
||||
originPoint: objectCenteredOnCells
|
||||
? { x: 80, y: 80 }
|
||||
: { x: 87, y: 87 },
|
||||
centerPoint: { x: 80, y: 80 },
|
||||
? { name: 'Origin', x: 80, y: 80 }
|
||||
: { name: 'Origin', x: 87, y: 87 },
|
||||
centerPoint: {
|
||||
name: 'Center',
|
||||
x: 80,
|
||||
y: 80,
|
||||
automatic: false,
|
||||
},
|
||||
points: [
|
||||
{ name: 'Center', x: 80, y: 80 },
|
||||
objectCenteredOnCells
|
||||
@@ -71,13 +76,17 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
: { name: 'Origin', x: 87, y: 87 },
|
||||
],
|
||||
hasCustomCollisionMask: false,
|
||||
customCollisionMask: [],
|
||||
image: '',
|
||||
},
|
||||
],
|
||||
timeBetweenFrames: 0,
|
||||
looping: false,
|
||||
},
|
||||
],
|
||||
useMultipleDirections: false,
|
||||
},
|
||||
],
|
||||
effects: [],
|
||||
behaviors: [
|
||||
{
|
||||
type: 'PathfindingBehavior::PathfindingBehavior',
|
||||
@@ -93,6 +102,9 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
extraBorder: 0,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
effects: [],
|
||||
updateIfNotVisible: true,
|
||||
});
|
||||
player.getWidth = function () {
|
||||
return 160;
|
||||
@@ -116,9 +128,14 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
sprites: [
|
||||
{
|
||||
originPoint: objectCenteredOnCells
|
||||
? { x: 80, y: 80 }
|
||||
: { x: 87, y: 87 },
|
||||
centerPoint: { x: 80, y: 80 },
|
||||
? { name: 'Origin', x: 80, y: 80 }
|
||||
: { name: 'Origin', x: 87, y: 87 },
|
||||
centerPoint: {
|
||||
name: 'Center',
|
||||
x: 80,
|
||||
y: 80,
|
||||
automatic: false,
|
||||
},
|
||||
points: [
|
||||
{ name: 'Center', x: 80, y: 80 },
|
||||
objectCenteredOnCells
|
||||
@@ -126,13 +143,17 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
: { name: 'Origin', x: 87, y: 87 },
|
||||
],
|
||||
hasCustomCollisionMask: false,
|
||||
customCollisionMask: [],
|
||||
image: '',
|
||||
},
|
||||
],
|
||||
timeBetweenFrames: 0,
|
||||
looping: false,
|
||||
},
|
||||
],
|
||||
useMultipleDirections: false,
|
||||
},
|
||||
],
|
||||
effects: [],
|
||||
behaviors: [
|
||||
{
|
||||
type: 'PathfindingBehavior::PathfindingObstacleBehavior',
|
||||
@@ -140,6 +161,9 @@ describe('gdjs.PathfindingRuntimeBehavior', function () {
|
||||
cost: 2,
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
effects: [],
|
||||
updateIfNotVisible: true,
|
||||
});
|
||||
obstacle.getWidth = function () {
|
||||
return 160;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace gdjs {
|
||||
*/
|
||||
_registeredBehaviors: Set<Physics2RuntimeBehavior>;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene, sharedData) {
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer, sharedData) {
|
||||
this._registeredBehaviors = new Set();
|
||||
this.gravityX = sharedData.gravityX;
|
||||
this.gravityY = sharedData.gravityY;
|
||||
@@ -349,11 +349,11 @@ namespace gdjs {
|
||||
_verticesBuffer: integer = 0;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this.bodyType = behaviorData.bodyType;
|
||||
this.bullet = behaviorData.bullet;
|
||||
this.fixedRotation = behaviorData.fixedRotation;
|
||||
@@ -382,7 +382,7 @@ namespace gdjs {
|
||||
this.currentContacts.length = 0;
|
||||
this.destroyedDuringFrameLogic = false;
|
||||
this._sharedData = Physics2SharedData.getSharedData(
|
||||
runtimeScene,
|
||||
instanceContainer.getScene(),
|
||||
behaviorData.name
|
||||
);
|
||||
this._tempb2Vec2 = new Box2D.b2Vec2();
|
||||
@@ -824,14 +824,15 @@ namespace gdjs {
|
||||
return true;
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// Step the world if not done this frame yet
|
||||
if (!this._sharedData.stepped) {
|
||||
// Reset started and ended contacts array for all physics instances.
|
||||
this._sharedData.resetStartedAndEndedCollisions();
|
||||
this._sharedData.updateBodiesFromObjects();
|
||||
this._sharedData.step(
|
||||
runtimeScene.getTimeManager().getElapsedTime() / 1000.0
|
||||
instanceContainer.getScene().getTimeManager().getElapsedTime() /
|
||||
1000.0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -862,7 +863,7 @@ namespace gdjs {
|
||||
this._objectOldAngle = this.owner.getAngle();
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// Reset world step to update next frame
|
||||
this._sharedData.stepped = false;
|
||||
}
|
||||
|
||||
@@ -117,11 +117,11 @@ namespace gdjs {
|
||||
private _manager: gdjs.PlatformObjectsManager;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._gravity = behaviorData.gravity;
|
||||
this._maxFallingSpeed = behaviorData.maxFallingSpeed;
|
||||
this._ladderClimbingSpeed = behaviorData.ladderClimbingSpeed || 150;
|
||||
@@ -146,7 +146,7 @@ namespace gdjs {
|
||||
this._potentialCollidingObjects = [];
|
||||
this._overlappedJumpThru = [];
|
||||
|
||||
this._manager = gdjs.PlatformObjectsManager.getManager(runtimeScene);
|
||||
this._manager = gdjs.PlatformObjectsManager.getManager(instanceContainer);
|
||||
|
||||
this._falling = new Falling(this);
|
||||
this._onFloor = new OnFloor(this);
|
||||
@@ -210,7 +210,7 @@ namespace gdjs {
|
||||
return true;
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
const LEFTKEY = 37;
|
||||
const UPKEY = 38;
|
||||
const RIGHTKEY = 39;
|
||||
@@ -219,13 +219,13 @@ namespace gdjs {
|
||||
const RSHIFTKEY = 2016;
|
||||
const SPACEKEY = 32;
|
||||
const object = this.owner;
|
||||
const timeDelta = this.owner.getElapsedTime(runtimeScene) / 1000;
|
||||
const timeDelta = this.owner.getElapsedTime() / 1000;
|
||||
|
||||
//0.1) Get the player input:
|
||||
this._requestedDeltaX = 0;
|
||||
this._requestedDeltaY = 0;
|
||||
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
const inputManager = instanceContainer.getGame().getInputManager();
|
||||
this._leftKey ||
|
||||
(this._leftKey =
|
||||
!this._ignoreDefaultControls && inputManager.isKeyPressed(LEFTKEY));
|
||||
@@ -329,7 +329,7 @@ namespace gdjs {
|
||||
this._lastDeltaY = object.getY() - oldY;
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene: gdjs.RuntimeScene) {}
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
private _updateSpeed(timeDelta: float): float {
|
||||
const previousSpeed = this._currentSpeed;
|
||||
|
||||
@@ -8,34 +8,31 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Manages the common objects shared by objects having a
|
||||
* platform behavior: in particular, the platforms behaviors are required to declare
|
||||
* themselves (see PlatformObjectsManager.addPlatform) to the manager of their associated scene
|
||||
* (see PlatformRuntimeBehavior.getManager).
|
||||
* platform behavior: in particular, the platforms behaviors are required to
|
||||
* declare themselves (see PlatformObjectsManager.addPlatform) to the manager
|
||||
* of their associated container (see PlatformRuntimeBehavior.getManager).
|
||||
*/
|
||||
export class PlatformObjectsManager {
|
||||
private _platformRBush: any;
|
||||
|
||||
/**
|
||||
* @param object The object
|
||||
*/
|
||||
constructor(runtimeScene: gdjs.RuntimeScene) {
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
this._platformRBush = new rbush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the platforms manager of a scene.
|
||||
* Get the platforms manager of an instance container.
|
||||
*/
|
||||
static getManager(runtimeScene: gdjs.RuntimeScene) {
|
||||
static getManager(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
// @ts-ignore
|
||||
if (!runtimeScene.platformsObjectsManager) {
|
||||
if (!instanceContainer.platformsObjectsManager) {
|
||||
//Create the shared manager if necessary.
|
||||
// @ts-ignore
|
||||
runtimeScene.platformsObjectsManager = new gdjs.PlatformObjectsManager(
|
||||
runtimeScene
|
||||
instanceContainer.platformsObjectsManager = new gdjs.PlatformObjectsManager(
|
||||
instanceContainer
|
||||
);
|
||||
}
|
||||
// @ts-ignore
|
||||
return runtimeScene.platformsObjectsManager;
|
||||
return instanceContainer.platformsObjectsManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,11 +129,11 @@ namespace gdjs {
|
||||
_registeredInManager: boolean = false;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._platformType = behaviorData.platformType;
|
||||
if (behaviorData.platformType === 'Ladder') {
|
||||
this._platformType = PlatformRuntimeBehavior.LADDER;
|
||||
@@ -147,7 +144,7 @@ namespace gdjs {
|
||||
}
|
||||
this._canBeGrabbed = behaviorData.canBeGrabbed || false;
|
||||
this._yGrabOffset = behaviorData.yGrabOffset || 0;
|
||||
this._manager = PlatformObjectsManager.getManager(runtimeScene);
|
||||
this._manager = PlatformObjectsManager.getManager(instanceContainer);
|
||||
}
|
||||
|
||||
updateFromBehaviorData(oldBehaviorData, newBehaviorData): boolean {
|
||||
@@ -169,7 +166,7 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
//Scene change is not supported
|
||||
/*if ( parentScene != &scene ) //Parent scene has changed
|
||||
{
|
||||
@@ -211,7 +208,7 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
doStepPostEvents(runtimeScene: gdjs.RuntimeScene) {}
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
onActivate() {
|
||||
if (this._registeredInManager) {
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace gdjs {
|
||||
|
||||
const logger = new gdjs.Logger('Player Authentication');
|
||||
const authComponents = gdjs.playerAuthenticationComponents;
|
||||
// TODO EBO Replace runtimeScene to instanceContainer.
|
||||
export namespace playerAuthentication {
|
||||
// Authentication information.
|
||||
let _username: string | null = null;
|
||||
|
||||
@@ -27,11 +27,11 @@ namespace gdjs {
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.ShapePainterRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._graphics = new PIXI.Graphics();
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._graphics, runtimeObject.getZOrder());
|
||||
|
||||
@@ -57,14 +57,14 @@ namespace gdjs {
|
||||
private static readonly _pointForTransformation: FloatPoint = [0, 0];
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
* @param shapePainterObjectData The initial properties of the object
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
shapePainterObjectData: ShapePainterObjectData
|
||||
) {
|
||||
super(runtimeScene, shapePainterObjectData);
|
||||
super(instanceContainer, shapePainterObjectData);
|
||||
this._fillColor = parseInt(
|
||||
gdjs.rgbToHex(
|
||||
shapePainterObjectData.fillColor.r,
|
||||
@@ -88,7 +88,7 @@ namespace gdjs {
|
||||
this._clearBetweenFrames = shapePainterObjectData.clearBetweenFrames;
|
||||
this._renderer = new gdjs.ShapePainterRuntimeObjectRenderer(
|
||||
this,
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
@@ -158,12 +158,12 @@ namespace gdjs {
|
||||
return true;
|
||||
}
|
||||
|
||||
stepBehaviorsPreEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
stepBehaviorsPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
//We redefine stepBehaviorsPreEvents just to clear the graphics before running events.
|
||||
if (this._clearBetweenFrames) {
|
||||
this.clear();
|
||||
}
|
||||
super.stepBehaviorsPreEvents(runtimeScene);
|
||||
super.stepBehaviorsPreEvents(instanceContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -468,7 +468,7 @@ namespace gdjs {
|
||||
}
|
||||
super.setAngle(angle);
|
||||
this._renderer.updateAngle();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -584,7 +584,7 @@ namespace gdjs {
|
||||
}
|
||||
this._scaleX = newScale * (this._flippedX ? -1 : 1);
|
||||
this._renderer.updateScaleX();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -601,7 +601,7 @@ namespace gdjs {
|
||||
}
|
||||
this._scaleY = newScale * (this._flippedY ? -1 : 1);
|
||||
this._renderer.updateScaleY();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
flipX(enable: boolean): void {
|
||||
@@ -609,7 +609,7 @@ namespace gdjs {
|
||||
this._scaleX *= -1;
|
||||
this._flippedX = enable;
|
||||
this._renderer.updateScaleX();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,7 +618,7 @@ namespace gdjs {
|
||||
this._scaleY *= -1;
|
||||
this._flippedY = enable;
|
||||
this._renderer.updateScaleY();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,7 +660,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
invalidateBounds() {
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
getDrawableX(): float {
|
||||
@@ -679,7 +679,7 @@ namespace gdjs {
|
||||
return this._renderer.getHeight();
|
||||
}
|
||||
|
||||
updatePreRender(runtimeScene: gdjs.RuntimeScene): void {
|
||||
updatePreRender(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
this._renderer.updatePreRender();
|
||||
}
|
||||
|
||||
@@ -741,7 +741,7 @@ namespace gdjs {
|
||||
rectangle[3][0] = left;
|
||||
rectangle[3][1] = bottom;
|
||||
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
updateHitBoxes(): void {
|
||||
|
||||
@@ -4,16 +4,16 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Save a screenshot of the game.
|
||||
* @param runtimeScene The scene
|
||||
* @param instanceContainer The container
|
||||
* @param savePath The path where to save the screenshot
|
||||
*/
|
||||
export const takeScreenshot = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
savePath: string
|
||||
) {
|
||||
const fs = typeof require !== 'undefined' ? require('fs') : null;
|
||||
if (fs) {
|
||||
const canvas = runtimeScene.getGame().getRenderer().getCanvas();
|
||||
const canvas = instanceContainer.getGame().getRenderer().getCanvas();
|
||||
if (canvas) {
|
||||
const content = canvas
|
||||
.toDataURL('image/png')
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
namespace gdjs {
|
||||
export interface RuntimeGame {
|
||||
shopifyClients: { [name: string]: any };
|
||||
}
|
||||
declare var ShopifyBuy: any;
|
||||
|
||||
export class ShopifyClientsManager {
|
||||
static set(runtimeScene, name, shopifyClient) {
|
||||
const game = runtimeScene.getGame();
|
||||
static set(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
name: string,
|
||||
shopifyClient
|
||||
) {
|
||||
const game = instanceContainer.getGame();
|
||||
if (!game.shopifyClients) {
|
||||
game.shopifyClients = {};
|
||||
}
|
||||
game.shopifyClients[name] = shopifyClient;
|
||||
}
|
||||
|
||||
static get(runtimeScene, name) {
|
||||
const game = runtimeScene.getGame();
|
||||
static get(instanceContainer: gdjs.RuntimeInstanceContainer, name: string) {
|
||||
const game = instanceContainer.getGame();
|
||||
if (!game.shopifyClients) {
|
||||
game.shopifyClients = {};
|
||||
}
|
||||
@@ -22,11 +29,11 @@ namespace gdjs {
|
||||
export namespace evtTools {
|
||||
export namespace shopify {
|
||||
export const buildClient = function (
|
||||
runtimeScene,
|
||||
name,
|
||||
domain,
|
||||
appId,
|
||||
accessToken
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
name: string,
|
||||
domain: string,
|
||||
appId: string,
|
||||
accessToken: string
|
||||
) {
|
||||
if (typeof ShopifyBuy === 'undefined') {
|
||||
return;
|
||||
@@ -37,21 +44,24 @@ namespace gdjs {
|
||||
appId: appId,
|
||||
});
|
||||
const shopifyClient = ShopifyBuy.buildClient(config);
|
||||
ShopifyClientsManager.set(runtimeScene, name, shopifyClient);
|
||||
ShopifyClientsManager.set(instanceContainer, name, shopifyClient);
|
||||
};
|
||||
|
||||
export const getCheckoutUrlForProduct = function (
|
||||
runtimeScene,
|
||||
name,
|
||||
productId,
|
||||
quantity,
|
||||
variantIndex,
|
||||
successVariable,
|
||||
errorVariable
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
name: string,
|
||||
productId: string,
|
||||
quantity: number,
|
||||
variantIndex: number,
|
||||
successVariable: gdjs.Variable,
|
||||
errorVariable: gdjs.Variable
|
||||
) {
|
||||
errorVariable.setString('');
|
||||
successVariable.setString('');
|
||||
const shopifyClient = ShopifyClientsManager.get(runtimeScene, name);
|
||||
const shopifyClient = ShopifyClientsManager.get(
|
||||
instanceContainer,
|
||||
name
|
||||
);
|
||||
shopifyClient.fetchProduct(productId).then(
|
||||
function (product) {
|
||||
if (variantIndex < 0 || variantIndex >= product.variants.length) {
|
||||
|
||||
@@ -3,13 +3,17 @@ namespace gdjs {
|
||||
export namespace spatialSound {
|
||||
const logger = new gdjs.Logger('Spatial Sound');
|
||||
export const setSoundPosition = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
channel: integer,
|
||||
x: float,
|
||||
y: float,
|
||||
z: float
|
||||
) => {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
// TODO EBO The position must be transform to the scene position when it comes from a custom object.
|
||||
const sound = instanceContainer
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) sound.setSpatialPosition(x, y, z);
|
||||
else
|
||||
logger.error(
|
||||
|
||||
@@ -83,18 +83,20 @@ namespace gdjs {
|
||||
* @returns true if WebGL is supported
|
||||
*/
|
||||
export const isWebGLSupported = (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): boolean => {
|
||||
return runtimeScene.getGame().getRenderer().isWebGLSupported();
|
||||
return instanceContainer.getGame().getRenderer().isWebGLSupported();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the game is running as a preview, launched from an editor.
|
||||
* @param runtimeScene The current scene.
|
||||
* @param instanceContainer The current container.
|
||||
* @returns true if the game is running as a preview.
|
||||
*/
|
||||
export const isPreview = (runtimeScene: gdjs.RuntimeScene): boolean => {
|
||||
return runtimeScene.getGame().isPreview();
|
||||
export const isPreview = (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): boolean => {
|
||||
return instanceContainer.getGame().isPreview();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
namespace gdjs {
|
||||
class TextEntryRuntimeObjectPixiRenderer {
|
||||
_object: any;
|
||||
_object: gdjs.TextEntryRuntimeObject;
|
||||
_pressHandler: any;
|
||||
_upHandler: any;
|
||||
_downHandler: any;
|
||||
|
||||
constructor(runtimeObject) {
|
||||
constructor(runtimeObject: gdjs.TextEntryRuntimeObject) {
|
||||
this._object = runtimeObject;
|
||||
this._pressHandler = function (evt) {
|
||||
if (!runtimeObject.isActivated()) {
|
||||
|
||||
@@ -12,14 +12,14 @@ namespace gdjs {
|
||||
_renderer: gdjs.TextEntryRuntimeObjectRenderer;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
* @param textEntryObjectData The initial properties of the object
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
textEntryObjectData: ObjectData
|
||||
) {
|
||||
super(runtimeScene, textEntryObjectData);
|
||||
super(instanceContainer, textEntryObjectData);
|
||||
this._renderer = new gdjs.TextEntryRuntimeObjectRenderer(this);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
@@ -31,14 +31,14 @@ namespace gdjs {
|
||||
return true;
|
||||
}
|
||||
|
||||
onDestroyFromScene(runtimeScene): void {
|
||||
super.onDestroyFromScene(runtimeScene);
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
if (this._renderer.onDestroy) {
|
||||
this._renderer.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
update(runtimeScene: gdjs.RuntimeScene): void {
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if ((this._renderer as any).getString) {
|
||||
this._str = (this._renderer as any).getString();
|
||||
}
|
||||
|
||||
@@ -29,13 +29,16 @@ namespace gdjs {
|
||||
class TextInputRuntimeObjectPixiRenderer {
|
||||
private _object: gdjs.TextInputRuntimeObject;
|
||||
private _input: HTMLInputElement | HTMLTextAreaElement | null = null;
|
||||
private _runtimeScene: gdjs.RuntimeScene;
|
||||
private _instanceContainer: gdjs.RuntimeInstanceContainer;
|
||||
private _runtimeGame: gdjs.RuntimeGame;
|
||||
|
||||
constructor(runtimeObject: gdjs.TextInputRuntimeObject) {
|
||||
constructor(
|
||||
runtimeObject: gdjs.TextInputRuntimeObject,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._runtimeScene = runtimeObject.getRuntimeScene();
|
||||
this._runtimeGame = this._runtimeScene.getGame();
|
||||
this._instanceContainer = instanceContainer;
|
||||
this._runtimeGame = this._instanceContainer.getGame();
|
||||
|
||||
this._createElement();
|
||||
}
|
||||
@@ -123,51 +126,71 @@ namespace gdjs {
|
||||
// Hide the input entirely if the layer is not visible.
|
||||
// Because this object is rendered as a DOM element (and not part of the PixiJS
|
||||
// scene graph), we have to do this manually.
|
||||
const layer = this._runtimeScene.getLayer(this._object.getLayer());
|
||||
const layer = this._instanceContainer.getLayer(this._object.getLayer());
|
||||
if (!layer.isVisible()) {
|
||||
this._input.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const runtimeGame = this._runtimeScene.getGame();
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
TextInputRuntimeObjectPixiRenderer.prototype.updatePreRender
|
||||
) as FloatPoint;
|
||||
|
||||
const runtimeGame = this._instanceContainer.getGame();
|
||||
const runtimeGameRenderer = runtimeGame.getRenderer();
|
||||
const topLeftCanvasCoordinates = layer.convertInverseCoords(
|
||||
this._object.x,
|
||||
this._object.y,
|
||||
0
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
const canvasLeft = topLeftCanvasCoordinates[0];
|
||||
const canvasTop = topLeftCanvasCoordinates[1];
|
||||
|
||||
const bottomRightCanvasCoordinates = layer.convertInverseCoords(
|
||||
this._object.x + this._object.getWidth(),
|
||||
this._object.y + this._object.getHeight(),
|
||||
0
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
const canvasRight = bottomRightCanvasCoordinates[0];
|
||||
const canvasBottom = bottomRightCanvasCoordinates[1];
|
||||
|
||||
// Hide the input entirely if not visible at all.
|
||||
const isOutsideCanvas =
|
||||
bottomRightCanvasCoordinates[0] < 0 ||
|
||||
bottomRightCanvasCoordinates[1] < 0 ||
|
||||
topLeftCanvasCoordinates[0] > runtimeGame.getGameResolutionWidth() ||
|
||||
topLeftCanvasCoordinates[1] > runtimeGame.getGameResolutionHeight();
|
||||
canvasRight < 0 ||
|
||||
canvasBottom < 0 ||
|
||||
canvasLeft > runtimeGame.getGameResolutionWidth() ||
|
||||
canvasTop > runtimeGame.getGameResolutionHeight();
|
||||
if (isOutsideCanvas) {
|
||||
this._input.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
// Position the input on the container on top of the canvas.
|
||||
workingPoint[0] = canvasLeft;
|
||||
workingPoint[1] = canvasRight;
|
||||
const topLeftPageCoordinates = runtimeGameRenderer.convertCanvasToDomElementContainerCoords(
|
||||
topLeftCanvasCoordinates
|
||||
workingPoint,
|
||||
workingPoint
|
||||
);
|
||||
const pageLeft = workingPoint[0];
|
||||
const pageTop = workingPoint[1];
|
||||
|
||||
workingPoint[0] = canvasRight;
|
||||
workingPoint[1] = canvasBottom;
|
||||
const bottomRightPageCoordinates = runtimeGameRenderer.convertCanvasToDomElementContainerCoords(
|
||||
bottomRightCanvasCoordinates
|
||||
workingPoint,
|
||||
workingPoint
|
||||
);
|
||||
const pageRight = workingPoint[0];
|
||||
const pageBottom = workingPoint[1];
|
||||
|
||||
const widthInContainer =
|
||||
bottomRightPageCoordinates[0] - topLeftPageCoordinates[0];
|
||||
const heightInContainer =
|
||||
bottomRightPageCoordinates[1] - topLeftPageCoordinates[1];
|
||||
const widthInContainer = pageRight - pageLeft;
|
||||
const heightInContainer = pageBottom - pageTop;
|
||||
|
||||
this._input.style.left = topLeftPageCoordinates[0] + 'px';
|
||||
this._input.style.top = topLeftPageCoordinates[1] + 'px';
|
||||
this._input.style.left = pageLeft + 'px';
|
||||
this._input.style.top = pageTop + 'px';
|
||||
this._input.style.width = widthInContainer + 'px';
|
||||
this._input.style.height = heightInContainer + 'px';
|
||||
this._input.style.transform =
|
||||
@@ -195,7 +218,7 @@ namespace gdjs {
|
||||
|
||||
updateFont() {
|
||||
if (!this._input) return;
|
||||
this._input.style.fontFamily = this._runtimeScene
|
||||
this._input.style.fontFamily = this._instanceContainer
|
||||
.getGame()
|
||||
.getFontManager()
|
||||
.getFontFamily(this._object.getFontResourceName());
|
||||
|
||||
@@ -71,10 +71,10 @@ namespace gdjs {
|
||||
_renderer: TextInputRuntimeObjectRenderer;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectData: TextInputObjectData
|
||||
) {
|
||||
super(runtimeScene, objectData);
|
||||
super(instanceContainer, objectData);
|
||||
|
||||
this._string = objectData.content.initialValue;
|
||||
this._placeholder = objectData.content.placeholder;
|
||||
@@ -92,7 +92,10 @@ namespace gdjs {
|
||||
this._disabled = objectData.content.disabled;
|
||||
this._readOnly = objectData.content.readOnly;
|
||||
|
||||
this._renderer = new gdjs.TextInputRuntimeObjectRenderer(this);
|
||||
this._renderer = new gdjs.TextInputRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
@@ -167,7 +170,7 @@ namespace gdjs {
|
||||
return true;
|
||||
}
|
||||
|
||||
updatePreRender(runtimeScene: RuntimeScene): void {
|
||||
updatePreRender(instanceContainer: RuntimeInstanceContainer): void {
|
||||
this._renderer.updatePreRender();
|
||||
}
|
||||
|
||||
@@ -196,8 +199,8 @@ namespace gdjs {
|
||||
this._renderer.onSceneResumed();
|
||||
}
|
||||
|
||||
onDestroyFromScene(runtimeScene: gdjs.RuntimeScene): void {
|
||||
super.onDestroyFromScene(runtimeScene);
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
this._renderer.onDestroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ namespace gdjs {
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.TextRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._fontManager = runtimeScene.getGame().getFontManager();
|
||||
this._fontManager = instanceContainer.getGame().getFontManager();
|
||||
this._text = new PIXI.Text(' ', { align: 'left' });
|
||||
this._text.anchor.x = 0.5;
|
||||
this._text.anchor.y = 0.5;
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._text, runtimeObject.getZOrder());
|
||||
|
||||
@@ -63,14 +63,14 @@ namespace gdjs {
|
||||
_scaleY: number = 1;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
* @param textObjectData The initial properties of the object
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
textObjectData: TextObjectData
|
||||
) {
|
||||
super(runtimeScene, textObjectData);
|
||||
super(instanceContainer, textObjectData);
|
||||
this._characterSize = Math.max(1, textObjectData.characterSize);
|
||||
this._fontName = textObjectData.font;
|
||||
this._bold = textObjectData.bold;
|
||||
@@ -82,7 +82,10 @@ namespace gdjs {
|
||||
textObjectData.color.b,
|
||||
];
|
||||
this._str = textObjectData.string;
|
||||
this._renderer = new gdjs.TextRuntimeObjectRenderer(this, runtimeScene);
|
||||
this._renderer = new gdjs.TextRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
@@ -131,7 +134,7 @@ namespace gdjs {
|
||||
return this._renderer.getRendererObject();
|
||||
}
|
||||
|
||||
update(runtimeScene: gdjs.RuntimeScene): void {
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
this._renderer.ensureUpToDate();
|
||||
}
|
||||
|
||||
@@ -151,7 +154,7 @@ namespace gdjs {
|
||||
* Update the rendered object position.
|
||||
*/
|
||||
private _updateTextPosition() {
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
this._renderer.updatePosition();
|
||||
}
|
||||
|
||||
@@ -326,7 +329,7 @@ namespace gdjs {
|
||||
this._scaleX = newScale;
|
||||
this._scaleY = newScale;
|
||||
this._renderer.setScale(newScale);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -338,7 +341,7 @@ namespace gdjs {
|
||||
|
||||
this._scaleX = newScale;
|
||||
this._renderer.setScaleX(newScale);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,7 +353,7 @@ namespace gdjs {
|
||||
|
||||
this._scaleY = newScale;
|
||||
this._renderer.setScaleY(newScale);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -410,7 +413,7 @@ namespace gdjs {
|
||||
|
||||
this._wrapping = enable;
|
||||
this._renderer.updateStyle();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -432,7 +435,7 @@ namespace gdjs {
|
||||
|
||||
this._wrappingWidth = width;
|
||||
this._renderer.updateStyle();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference path="helper/TileMapHelper.d.ts" />
|
||||
namespace gdjs {
|
||||
export interface RuntimeScene {
|
||||
export interface RuntimeInstanceContainer {
|
||||
tileMapCollisionMaskManager: gdjs.TileMap.TileMapRuntimeManager;
|
||||
}
|
||||
export namespace TileMap {
|
||||
@@ -26,7 +26,7 @@ namespace gdjs {
|
||||
* @see {@link TileMapManager}
|
||||
*/
|
||||
export class TileMapRuntimeManager {
|
||||
private _runtimeScene: gdjs.RuntimeScene;
|
||||
private _instanceContainer: gdjs.RuntimeInstanceContainer;
|
||||
/**
|
||||
* Delegate that actually manage the caches without anything specific to
|
||||
* GDJS.
|
||||
@@ -34,27 +34,27 @@ namespace gdjs {
|
||||
*/
|
||||
private _manager: TileMapHelper.TileMapManager;
|
||||
/**
|
||||
* @param runtimeScene The scene.
|
||||
* @param instanceContainer The instance container.
|
||||
*/
|
||||
private constructor(runtimeScene: gdjs.RuntimeScene) {
|
||||
this._runtimeScene = runtimeScene;
|
||||
private constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
this._instanceContainer = instanceContainer;
|
||||
this._manager = new TileMapHelper.TileMapManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param runtimeScene Where to set the manager instance.
|
||||
* @param instanceContainer Where to set the manager instance.
|
||||
* @returns The shared manager.
|
||||
*/
|
||||
static getManager(
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): TileMapRuntimeManager {
|
||||
if (!runtimeScene.tileMapCollisionMaskManager) {
|
||||
if (!instanceContainer.tileMapCollisionMaskManager) {
|
||||
// Create the shared manager if necessary.
|
||||
runtimeScene.tileMapCollisionMaskManager = new TileMapRuntimeManager(
|
||||
runtimeScene
|
||||
instanceContainer.tileMapCollisionMaskManager = new TileMapRuntimeManager(
|
||||
instanceContainer
|
||||
);
|
||||
}
|
||||
return runtimeScene.tileMapCollisionMaskManager;
|
||||
return instanceContainer.tileMapCollisionMaskManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +109,7 @@ namespace gdjs {
|
||||
tileSetJsonResourceName: string,
|
||||
callback: (tiledMap: TileMapHelper.TiledMap | null) => void
|
||||
): void {
|
||||
this._runtimeScene
|
||||
this._instanceContainer
|
||||
.getGame()
|
||||
.getJsonManager()
|
||||
.loadJson(tileMapJsonResourceName, (error, tileMapJsonData) => {
|
||||
@@ -123,7 +123,7 @@ namespace gdjs {
|
||||
}
|
||||
const tiledMap = tileMapJsonData as TileMapHelper.TiledMap;
|
||||
if (tileSetJsonResourceName) {
|
||||
this._runtimeScene
|
||||
this._instanceContainer
|
||||
.getGame()
|
||||
.getJsonManager()
|
||||
.loadJson(tileSetJsonResourceName, (error, tileSetJsonData) => {
|
||||
|
||||
@@ -12,11 +12,11 @@ namespace gdjs {
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.TileMapCollisionMaskRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._graphics = new PIXI.Graphics();
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._graphics, runtimeObject.getZOrder());
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace gdjs {
|
||||
*/
|
||||
private _transformationIsUpToDate: boolean = false;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene, objectData) {
|
||||
super(runtimeScene, objectData);
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer, objectData) {
|
||||
super(instanceContainer, objectData);
|
||||
this._tilemapJsonFile = objectData.content.tilemapJsonFile;
|
||||
this._tilesetJsonFile = objectData.content.tilesetJsonFile;
|
||||
this._collisionMaskTag = objectData.content.collisionMaskTag;
|
||||
@@ -58,7 +58,7 @@ namespace gdjs {
|
||||
this._outlineOpacity = objectData.content.outlineOpacity;
|
||||
this._outlineSize = objectData.content.outlineSize;
|
||||
this._tileMapManager = gdjs.TileMap.TileMapRuntimeManager.getManager(
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
|
||||
// The actual size is set when the tile map file is loaded.
|
||||
@@ -80,7 +80,7 @@ namespace gdjs {
|
||||
|
||||
this._renderer = new gdjs.TileMap.TileMapCollisionMaskRenderer(
|
||||
this,
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
this._updateTileMap();
|
||||
|
||||
@@ -88,8 +88,8 @@ namespace gdjs {
|
||||
this.onCreated();
|
||||
}
|
||||
|
||||
updatePreRender(runtimeScene: gdjs.RuntimeScene) {
|
||||
super.updatePreRender(runtimeScene);
|
||||
updatePreRender(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
super.updatePreRender(instanceContainer);
|
||||
|
||||
if (this._debugMode && this.hitBoxesDirty) {
|
||||
this.updateHitBoxes();
|
||||
@@ -472,8 +472,8 @@ namespace gdjs {
|
||||
}
|
||||
this._scaleX = width / this._collisionTileMap.getWidth();
|
||||
this._width = width;
|
||||
this.hitBoxesDirty = true;
|
||||
this._transformationIsUpToDate = false;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -487,8 +487,8 @@ namespace gdjs {
|
||||
}
|
||||
this._scaleY = height / this._collisionTileMap.getHeight();
|
||||
this._height = height;
|
||||
this.hitBoxesDirty = true;
|
||||
this._transformationIsUpToDate = false;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -515,8 +515,8 @@ namespace gdjs {
|
||||
}
|
||||
this._scaleX = scaleX;
|
||||
this._width = scaleX * this._collisionTileMap.getWidth();
|
||||
this.hitBoxesDirty = true;
|
||||
this._transformationIsUpToDate = false;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -533,8 +533,8 @@ namespace gdjs {
|
||||
}
|
||||
this._scaleY = scaleY;
|
||||
this._height = scaleY * this._collisionTileMap.getHeight();
|
||||
this.hitBoxesDirty = true;
|
||||
this._transformationIsUpToDate = false;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
getWidth(): float {
|
||||
|
||||
@@ -16,11 +16,11 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* @param runtimeObject The object to render
|
||||
* @param runtimeScene The gdjs.RuntimeScene in which the object is
|
||||
* @param instanceContainer The gdjs.RuntimeScene in which the object is
|
||||
*/
|
||||
constructor(
|
||||
runtimeObject: gdjs.TileMapRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace gdjs {
|
||||
this._pixiObject = new PIXI.tilemap.CompositeTilemap();
|
||||
this._pixiObject.tileAnim = [0, 0];
|
||||
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._pixiObject, runtimeObject.getZOrder());
|
||||
@@ -44,7 +44,7 @@ namespace gdjs {
|
||||
return this._pixiObject;
|
||||
}
|
||||
|
||||
incrementAnimationFrameX(runtimeScene: gdjs.RuntimeScene) {
|
||||
incrementAnimationFrameX(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
this._pixiObject.tileAnim[0] += 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace gdjs {
|
||||
_tileMapManager: gdjs.TileMap.TileMapRuntimeManager;
|
||||
_renderer: gdjs.TileMapRuntimeObjectPixiRenderer;
|
||||
|
||||
constructor(runtimeScene: gdjs.RuntimeScene, objectData) {
|
||||
super(runtimeScene, objectData);
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer, objectData) {
|
||||
super(instanceContainer, objectData);
|
||||
this._opacity = objectData.content.opacity;
|
||||
this._tilemapJsonFile = objectData.content.tilemapJsonFile;
|
||||
this._tilesetJsonFile = objectData.content.tilesetJsonFile;
|
||||
@@ -30,11 +30,11 @@ namespace gdjs {
|
||||
this._animationSpeedScale = objectData.content.animationSpeedScale;
|
||||
this._animationFps = objectData.content.animationFps;
|
||||
this._tileMapManager = gdjs.TileMap.TileMapRuntimeManager.getManager(
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
this._renderer = new gdjs.TileMapRuntimeObjectRenderer(
|
||||
this,
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
this._updateTileMap();
|
||||
|
||||
@@ -46,14 +46,14 @@ namespace gdjs {
|
||||
return this._renderer.getRendererObject();
|
||||
}
|
||||
|
||||
update(runtimeScene: gdjs.RuntimeScene): void {
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if (this._animationSpeedScale <= 0 || this._animationFps === 0) {
|
||||
return;
|
||||
}
|
||||
const elapsedTime = this.getElapsedTime(runtimeScene) / 1000;
|
||||
const elapsedTime = this.getElapsedTime() / 1000;
|
||||
this._frameElapsedTime += elapsedTime * this._animationSpeedScale;
|
||||
while (this._frameElapsedTime > 1 / this._animationFps) {
|
||||
this._renderer.incrementAnimationFrameX(runtimeScene);
|
||||
this._renderer.incrementAnimationFrameX(instanceContainer);
|
||||
this._frameElapsedTime -= 1 / this._animationFps;
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ namespace gdjs {
|
||||
}
|
||||
this._tileMapManager.getOrLoadTextureCache(
|
||||
(textureName) =>
|
||||
(this._runtimeScene
|
||||
(this.getInstanceContainer()
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getPIXITexture(textureName) as unknown) as PIXI.BaseTexture<
|
||||
@@ -221,7 +221,7 @@ namespace gdjs {
|
||||
if (this.getWidth() === width) return;
|
||||
|
||||
this._renderer.setWidth(width);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,7 +233,7 @@ namespace gdjs {
|
||||
if (this.getHeight() === height) return;
|
||||
|
||||
this._renderer.setHeight(height);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,7 +258,7 @@ namespace gdjs {
|
||||
if (this.getScaleX() === scaleX) return;
|
||||
|
||||
this._renderer.setScaleX(scaleX);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -273,7 +273,7 @@ namespace gdjs {
|
||||
if (this.getScaleY() === scaleY) return;
|
||||
|
||||
this._renderer.setScaleY(scaleY);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
setX(x: float): void {
|
||||
|
||||
@@ -7,17 +7,17 @@ namespace gdjs {
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.TiledSpriteRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
textureName: string
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
const texture = runtimeScene
|
||||
const texture = instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getPIXITexture(textureName);
|
||||
this._tiledSprite = new PIXI.TilingSprite(texture, 1024, 1024);
|
||||
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._tiledSprite, runtimeObject.getZOrder());
|
||||
@@ -42,8 +42,11 @@ namespace gdjs {
|
||||
this._object.y + this._tiledSprite.height / 2;
|
||||
}
|
||||
|
||||
setTexture(textureName, runtimeScene): void {
|
||||
const texture = runtimeScene
|
||||
setTexture(
|
||||
textureName: string,
|
||||
instanceContainer: RuntimeInstanceContainer
|
||||
): void {
|
||||
const texture = instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getPIXITexture(textureName);
|
||||
|
||||
@@ -30,17 +30,17 @@ namespace gdjs {
|
||||
_renderer: gdjs.TiledSpriteRuntimeObjectRenderer;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
* @param tiledSpriteObjectData The initial properties of the object
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
tiledSpriteObjectData: TiledSpriteObjectData
|
||||
) {
|
||||
super(runtimeScene, tiledSpriteObjectData);
|
||||
super(instanceContainer, tiledSpriteObjectData);
|
||||
this._renderer = new gdjs.TiledSpriteRuntimeObjectRenderer(
|
||||
this,
|
||||
runtimeScene,
|
||||
instanceContainer,
|
||||
tiledSpriteObjectData.texture
|
||||
);
|
||||
this._width = 0;
|
||||
@@ -54,7 +54,7 @@ namespace gdjs {
|
||||
|
||||
updateFromObjectData(oldObjectData, newObjectData): boolean {
|
||||
if (oldObjectData.texture !== newObjectData.texture) {
|
||||
this.setTexture(newObjectData.texture, this._runtimeScene);
|
||||
this.setTexture(newObjectData.texture, this.getRuntimeScene());
|
||||
}
|
||||
if (oldObjectData.width !== newObjectData.width) {
|
||||
this.setWidth(newObjectData.width);
|
||||
@@ -69,8 +69,8 @@ namespace gdjs {
|
||||
return this._renderer.getRendererObject();
|
||||
}
|
||||
|
||||
onDestroyFromScene(runtimeScene): void {
|
||||
super.onDestroyFromScene(runtimeScene);
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
if ((this._renderer as any).onDestroy) {
|
||||
(this._renderer as any).onDestroy();
|
||||
}
|
||||
@@ -106,11 +106,14 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Assign a new texture to the Tiled Sprite object.
|
||||
* @param textureName The name of the image texture ressource.
|
||||
* @param runtimeScene The scene in which the texture is used.
|
||||
* @param textureName The name of the image texture resource.
|
||||
* @param instanceContainer The container in which the texture is used.
|
||||
*/
|
||||
setTexture(textureName: string, runtimeScene: gdjs.RuntimeScene): void {
|
||||
this._renderer.setTexture(textureName, runtimeScene);
|
||||
setTexture(
|
||||
textureName: string,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
this._renderer.setTexture(textureName, instanceContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +150,7 @@ namespace gdjs {
|
||||
|
||||
this._width = width;
|
||||
this._renderer.setWidth(width);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,7 +162,7 @@ namespace gdjs {
|
||||
|
||||
this._height = height;
|
||||
this._renderer.setHeight(height);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,11 +48,11 @@ namespace gdjs {
|
||||
private _temporaryPointForTransformations: FloatPoint = [0, 0];
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._allowDiagonals = behaviorData.allowDiagonals;
|
||||
this._acceleration = behaviorData.acceleration;
|
||||
this._deceleration = behaviorData.deceleration;
|
||||
@@ -227,7 +227,7 @@ namespace gdjs {
|
||||
return this._movementAngleOffset;
|
||||
}
|
||||
|
||||
doStepPreEvents(runtimeScene: gdjs.RuntimeScene) {
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
const LEFTKEY = 37;
|
||||
const UPKEY = 38;
|
||||
const RIGHTKEY = 39;
|
||||
@@ -237,21 +237,21 @@ namespace gdjs {
|
||||
// @ts-ignore
|
||||
this._leftKey |=
|
||||
!this._ignoreDefaultControls &&
|
||||
runtimeScene.getGame().getInputManager().isKeyPressed(LEFTKEY);
|
||||
instanceContainer.getGame().getInputManager().isKeyPressed(LEFTKEY);
|
||||
// @ts-ignore
|
||||
this._rightKey |=
|
||||
!this._ignoreDefaultControls &&
|
||||
runtimeScene.getGame().getInputManager().isKeyPressed(RIGHTKEY);
|
||||
instanceContainer.getGame().getInputManager().isKeyPressed(RIGHTKEY);
|
||||
// @ts-ignore
|
||||
this._downKey |=
|
||||
!this._ignoreDefaultControls &&
|
||||
runtimeScene.getGame().getInputManager().isKeyPressed(DOWNKEY);
|
||||
instanceContainer.getGame().getInputManager().isKeyPressed(DOWNKEY);
|
||||
// @ts-ignore
|
||||
this._upKey |=
|
||||
!this._ignoreDefaultControls &&
|
||||
runtimeScene.getGame().getInputManager().isKeyPressed(UPKEY);
|
||||
instanceContainer.getGame().getInputManager().isKeyPressed(UPKEY);
|
||||
|
||||
const elapsedTime = this.owner.getElapsedTime(runtimeScene);
|
||||
const elapsedTime = this.owner.getElapsedTime();
|
||||
|
||||
if (!this._leftKey) {
|
||||
this._leftKeyPressedDuration = 0;
|
||||
@@ -330,7 +330,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
const object = this.owner;
|
||||
const timeDelta = this.owner.getElapsedTime(runtimeScene) / 1000;
|
||||
const timeDelta = this.owner.getElapsedTime() / 1000;
|
||||
const previousVelocityX = this._xVelocity;
|
||||
const previousVelocityY = this._yVelocity;
|
||||
this._wasStickUsed = false;
|
||||
@@ -443,8 +443,7 @@ namespace gdjs {
|
||||
if (this._rotateObject) {
|
||||
object.rotateTowardAngle(
|
||||
directionInDeg + this._angleOffset,
|
||||
this._angularSpeed,
|
||||
runtimeScene
|
||||
this._angularSpeed
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,23 +76,25 @@ namespace gdjs {
|
||||
];
|
||||
}
|
||||
|
||||
// TODO EBO Rewrite this behavior to use standard method to step.
|
||||
// This could also fix layer time scale that seems to be ignored.
|
||||
export class TweenRuntimeBehavior extends gdjs.RuntimeBehavior {
|
||||
private _tweens: Record<string, TweenRuntimeBehavior.TweenInstance> = {};
|
||||
private _runtimeScene: gdjs.RuntimeScene;
|
||||
private _isActive: boolean = true;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The runtime scene the behavior belongs to.
|
||||
* @param instanceContainer The instance container the behavior belongs to.
|
||||
* @param behaviorData The data to initialize the behavior
|
||||
* @param owner The runtime object the behavior belongs to.
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData: BehaviorData,
|
||||
owner: gdjs.RuntimeObject
|
||||
) {
|
||||
super(runtimeScene, behaviorData, owner);
|
||||
this._runtimeScene = runtimeScene;
|
||||
super(instanceContainer, behaviorData, owner);
|
||||
this._runtimeScene = instanceContainer.getScene();
|
||||
}
|
||||
|
||||
updateFromBehaviorData(
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace gdjs {
|
||||
* The PIXI.js renderer for the VideoRuntimeObject.
|
||||
*/
|
||||
export class VideoRuntimeObjectPixiRenderer {
|
||||
_object: any;
|
||||
_object: gdjs.VideoRuntimeObject;
|
||||
|
||||
// Load (or reset) the video
|
||||
_pixiObject: any;
|
||||
@@ -15,15 +15,15 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* @param runtimeObject The object to render
|
||||
* @param runtimeScene The gdjs.RuntimeScene in which the object is
|
||||
* @param instanceContainer The gdjs.RuntimeScene in which the object is
|
||||
*/
|
||||
constructor(
|
||||
runtimeObject: gdjs.VideoRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._pixiObject = new PIXI.Sprite(
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getPIXIVideoTexture(this._object._videoResource)
|
||||
@@ -36,7 +36,7 @@ namespace gdjs {
|
||||
this._pixiObject._texture.baseTexture.resource.source.autoload = true;
|
||||
|
||||
// Will be set to true when video texture is loaded.
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.addRendererObject(this._pixiObject, runtimeObject.getZOrder());
|
||||
|
||||
@@ -37,19 +37,22 @@ namespace gdjs {
|
||||
_playbackSpeed: any;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene the object belongs to.
|
||||
* @param instanceContainer The scene the object belongs to.
|
||||
* @param videoObjectData The data defining the object
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
videoObjectData: VideoObjectData
|
||||
) {
|
||||
super(runtimeScene, videoObjectData);
|
||||
super(instanceContainer, videoObjectData);
|
||||
this._opacity = videoObjectData.content.opacity;
|
||||
this._loop = videoObjectData.content.loop;
|
||||
this._volume = videoObjectData.content.volume;
|
||||
this._videoResource = videoObjectData.content.videoResource;
|
||||
this._renderer = new gdjs.VideoRuntimeObjectRenderer(this, runtimeScene);
|
||||
this._renderer = new gdjs.VideoRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
@@ -92,12 +95,12 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
onDestroyFromScene(runtimeScene): void {
|
||||
super.onDestroyFromScene(runtimeScene);
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
this._renderer.onDestroy();
|
||||
}
|
||||
|
||||
update(runtimeScene): void {
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
this._renderer.ensureUpToDate();
|
||||
}
|
||||
|
||||
@@ -153,7 +156,7 @@ namespace gdjs {
|
||||
if (this._renderer.getWidth() === width) return;
|
||||
|
||||
this._renderer.setWidth(width);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +167,7 @@ namespace gdjs {
|
||||
if (this._renderer.getHeight() === height) return;
|
||||
|
||||
this._renderer.setHeight(height);
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "GDCore/IDE/SceneNameMangler.h"
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunction.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
@@ -38,6 +39,7 @@ gd::String EventsCodeGenerator::GenerateEventsListCompleteFunctionCode(
|
||||
gd::String functionArgumentsCode,
|
||||
gd::String functionPreEventsCode,
|
||||
const gd::EventsList& events,
|
||||
gd::String functionPostEventsCode,
|
||||
gd::String functionReturnCode) {
|
||||
// Prepare the global context
|
||||
unsigned int maxDepthLevelReached = 0;
|
||||
@@ -80,6 +82,7 @@ gd::String EventsCodeGenerator::GenerateEventsListCompleteFunctionCode(
|
||||
functionPreEventsCode + "\n" +
|
||||
globalObjectListsReset + "\n" +
|
||||
wholeEventsCode + "\n" +
|
||||
functionPostEventsCode + "\n" +
|
||||
functionReturnCode + "\n" +
|
||||
"}\n";
|
||||
// clang-format on
|
||||
@@ -103,6 +106,7 @@ gd::String EventsCodeGenerator::GenerateLayoutCode(
|
||||
"runtimeScene",
|
||||
"runtimeScene.getOnceTriggers().startNewFrame();\n",
|
||||
scene.GetEvents(),
|
||||
"",
|
||||
"return;\n");
|
||||
|
||||
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
|
||||
@@ -129,10 +133,11 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
codeGenerator,
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "func",
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParameters(), false),
|
||||
eventsFunction.GetParameters(), 0, true),
|
||||
codeGenerator.GenerateFreeEventsFunctionContext(
|
||||
eventsFunction.GetParameters(), "runtimeScene.getOnceTriggers()"),
|
||||
eventsFunction.GetEvents(),
|
||||
"",
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
|
||||
@@ -191,9 +196,83 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
codeGenerator,
|
||||
fullyQualifiedFunctionName,
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParameters(), true),
|
||||
eventsFunction.GetParameters(), 2, false),
|
||||
fullPreludeCode,
|
||||
eventsFunction.GetEvents(),
|
||||
"",
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
|
||||
codeGenerator.GetIncludeFiles().end());
|
||||
return output;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
const gd::String& fullyQualifiedFunctionName,
|
||||
const gd::String& onceTriggersVariable,
|
||||
const gd::String& preludeCode,
|
||||
const gd::String& endingCode,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project,
|
||||
eventsBasedObject,
|
||||
eventsFunction,
|
||||
globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
|
||||
EventsCodeGenerator codeGenerator(globalObjectsAndGroups, objectsAndGroups);
|
||||
codeGenerator.SetCodeNamespace(codeNamespace);
|
||||
codeGenerator.SetGenerateCodeForRuntime(compilationForRuntime);
|
||||
|
||||
// Generate the code setting up the context of the function.
|
||||
gd::String fullPreludeCode =
|
||||
preludeCode + "\n" + "var that = this;\n" +
|
||||
// runtimeScene is supposed to be always accessible, read
|
||||
// it from the object
|
||||
"var runtimeScene = this._instanceContainer;\n" +
|
||||
// By convention of Object Events Function, the object is accessible
|
||||
// as a parameter called "Object", and thisObjectList is an array
|
||||
// containing it (for faster access, without having to go through the
|
||||
// hashmap).
|
||||
"var thisObjectList = [this];\n" +
|
||||
"var Object = Hashtable.newFrom({Object: thisObjectList});\n";
|
||||
|
||||
// Add child-objects
|
||||
for (auto &childObject : eventsBasedObject.GetObjects()) {
|
||||
// child-object are never picked because they are not parameters.
|
||||
const auto &childName = ManObjListName(childObject->GetName());
|
||||
fullPreludeCode +=
|
||||
"var this" + childName + "List = [...runtimeScene.getObjects(" +
|
||||
ConvertToStringExplicit(childObject->GetName()) + ")];\n" +
|
||||
"var " + childName + " = Hashtable.newFrom({" +
|
||||
ConvertToStringExplicit(childObject->GetName()) +
|
||||
": this" + childName + "List});\n";
|
||||
}
|
||||
|
||||
fullPreludeCode += codeGenerator.GenerateObjectEventsFunctionContext(
|
||||
eventsBasedObject,
|
||||
eventsFunction.GetParameters(),
|
||||
onceTriggersVariable,
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
"Object");
|
||||
|
||||
gd::String output = GenerateEventsListCompleteFunctionCode(
|
||||
codeGenerator,
|
||||
fullyQualifiedFunctionName,
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
// TODO EBO use constants for firstParameterIndex
|
||||
eventsFunction.GetParameters(), 1, false),
|
||||
fullPreludeCode,
|
||||
eventsFunction.GetEvents(),
|
||||
endingCode,
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
|
||||
includeFiles.insert(codeGenerator.GetIncludeFiles().begin(),
|
||||
@@ -203,11 +282,12 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionParameterDeclarationsList(
|
||||
const vector<gd::ParameterMetadata>& parameters,
|
||||
bool isBehaviorEventsFunction) {
|
||||
gd::String declaration = isBehaviorEventsFunction ? "" : "runtimeScene";
|
||||
int firstParameterIndex,
|
||||
bool addsSceneParameter) {
|
||||
gd::String declaration = addsSceneParameter ? "runtimeScene" : "";
|
||||
for (size_t i = 0; i < parameters.size(); ++i) {
|
||||
const auto& parameter = parameters[i];
|
||||
if (isBehaviorEventsFunction && (i == 0 || i == 1)) {
|
||||
if (i < firstParameterIndex) {
|
||||
// By convention, the first two arguments of a behavior events function
|
||||
// are the object and the behavior, which are not passed to the called
|
||||
// function in the generated JS code.
|
||||
@@ -294,6 +374,44 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionContext(
|
||||
thisBehaviorName);
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateObjectEventsFunctionContext(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::String& onceTriggersVariable,
|
||||
const gd::String& thisObjectName) {
|
||||
// See the comment at the start of the GenerateEventsFunctionContext function
|
||||
|
||||
gd::String objectsGettersMap;
|
||||
gd::String objectArraysMap;
|
||||
gd::String behaviorNamesMap;
|
||||
|
||||
// If we have an object considered as the current object ("this") (usually
|
||||
// called Object in behavior events function), generate a slightly more
|
||||
// optimized getter for it (bypassing "Object" hashmap, and directly return
|
||||
// the array containing it).
|
||||
if (!thisObjectName.empty()) {
|
||||
objectsGettersMap +=
|
||||
ConvertToStringExplicit(thisObjectName) + ": " + thisObjectName + "\n";
|
||||
objectArraysMap +=
|
||||
ConvertToStringExplicit(thisObjectName) + ": thisObjectList\n";
|
||||
|
||||
// Add child-objects
|
||||
for (auto &childObject : eventsBasedObject.GetObjects()) {
|
||||
const auto &childName = ManObjListName(childObject->GetName());
|
||||
// child-object are never picked because they are not parameters.
|
||||
objectsGettersMap += ", " + ConvertToStringExplicit(childObject->GetName()) + ": " + childName + "\n";
|
||||
objectArraysMap += ", " + ConvertToStringExplicit(childObject->GetName()) + ": this" + childName + "List\n";
|
||||
}
|
||||
}
|
||||
|
||||
return GenerateEventsFunctionContext(parameters,
|
||||
onceTriggersVariable,
|
||||
objectsGettersMap,
|
||||
objectArraysMap,
|
||||
behaviorNamesMap,
|
||||
thisObjectName);
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
const vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::String& onceTriggersVariable,
|
||||
@@ -379,7 +497,8 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
// can be different between the parameter name vs the actual behavior
|
||||
// name passed as argument).
|
||||
" getBehaviorName: function(behaviorName) {\n" +
|
||||
" return eventsFunctionContext._behaviorNamesMap[behaviorName];\n"
|
||||
// TODO EBO Handle behavior name collision between parameters and children
|
||||
" return eventsFunctionContext._behaviorNamesMap[behaviorName] || behaviorName;\n"
|
||||
" },\n" +
|
||||
// Creator function that will be used to create new objects. We
|
||||
// need to check if the function was given the context of the calling
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace gd {
|
||||
class ObjectsContainer;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
class ObjectMetadata;
|
||||
class BehaviorMetadata;
|
||||
class InstructionMetadata;
|
||||
@@ -76,10 +77,13 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
* \param project Project used.
|
||||
* \param eventsFunction The events function to be compiled.
|
||||
* \param codeNamespace Where to store the context used by the function.
|
||||
* \param includeFiles Will be filled with the necessary include files.
|
||||
* \param fullyQualifiedFunctionName The function name with its namespace.
|
||||
* \param onceTriggersVariable The code to access the variable holding
|
||||
* OnceTriggers. \param preludeCode The code to run just before the events
|
||||
* generated code. \param compilationForRuntime Set this to true if the code
|
||||
* OnceTriggers.
|
||||
* \param preludeCode The code to run just before the events
|
||||
* generated code.
|
||||
* \param includeFiles Will be filled with the necessary include files.
|
||||
* \param compilationForRuntime Set this to true if the code
|
||||
* is generated for runtime.
|
||||
*
|
||||
* \return JavaScript code
|
||||
@@ -95,6 +99,39 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime = false);
|
||||
|
||||
/**
|
||||
* Generate JavaScript for executing events of a events based object
|
||||
* function.
|
||||
*
|
||||
* \param project Project used.
|
||||
* \param eventsBasedObject The object that contains the function to be compiled.
|
||||
* \param eventsFunction The events function to be compiled.
|
||||
* \param codeNamespace Where to store the context used by the function.
|
||||
* \param fullyQualifiedFunctionName The function name with its namespace.
|
||||
* \param onceTriggersVariable The code to access the variable holding
|
||||
* OnceTriggers.
|
||||
* \param preludeCode The code to run right before the events
|
||||
* generated code.
|
||||
* \param endingCode The code to run right after the events
|
||||
* generated code.
|
||||
* \param includeFiles Will be filled with the necessary include files.
|
||||
* \param compilationForRuntime Set this to true if the code
|
||||
* is generated for runtime.
|
||||
*
|
||||
* \return JavaScript code
|
||||
*/
|
||||
static gd::String GenerateObjectEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
const gd::String& fullyQualifiedFunctionName,
|
||||
const gd::String& onceTriggersVariable,
|
||||
const gd::String& preludeCode,
|
||||
const gd::String& endingCode,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime = false);
|
||||
|
||||
/**
|
||||
* \brief Generate code for executing an event list
|
||||
* \note To reduce the stress on JS engines, the code is generated inside
|
||||
@@ -296,6 +333,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
gd::String functionArgumentsCode,
|
||||
gd::String functionPreEventsCode,
|
||||
const gd::EventsList& events,
|
||||
gd::String functionPostEventsCode,
|
||||
gd::String functionReturnCode);
|
||||
|
||||
/**
|
||||
@@ -324,7 +362,8 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
*/
|
||||
gd::String GenerateEventsFunctionParameterDeclarationsList(
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
bool isBehaviorEventsFunction);
|
||||
int firstParameterIndex,
|
||||
bool addsSceneParameter);
|
||||
|
||||
/**
|
||||
* \brief Generate the "eventsFunctionContext" object that allow a free
|
||||
@@ -347,6 +386,17 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
const gd::String& thisObjectName,
|
||||
const gd::String& thisBehaviorName);
|
||||
|
||||
/**
|
||||
* \brief Generate the "eventsFunctionContext" object that allow an object
|
||||
* function to provides access objects, object creation and access to
|
||||
* arguments from the rest of the events.
|
||||
*/
|
||||
gd::String GenerateObjectEventsFunctionContext(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const std::vector<gd::ParameterMetadata>& parameters,
|
||||
const gd::String& onceTriggersVariable,
|
||||
const gd::String& thisObjectName);
|
||||
|
||||
gd::String GenerateEventsFunctionReturn(
|
||||
const gd::EventsFunction& eventFunction);
|
||||
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2008-2016 Florian Rival ([email protected]). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ObjectCodeGenerator.h"
|
||||
|
||||
#include "EventsCodeGenerator.h"
|
||||
|
||||
namespace gdjs {
|
||||
|
||||
gd::String ObjectCodeGenerator::onCreatedFunctionName =
|
||||
"onCreated";
|
||||
|
||||
gd::String ObjectCodeGenerator::doStepPreEventsFunctionName =
|
||||
"doStepPreEvents";
|
||||
|
||||
gd::String ObjectCodeGenerator::GenerateRuntimeObjectCompleteCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace,
|
||||
const std::map<gd::String, gd::String>& objectMethodMangledNames,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime) {
|
||||
auto& eventsFunctionsVector =
|
||||
eventsBasedObject.GetEventsFunctions().GetInternalVector();
|
||||
|
||||
return GenerateRuntimeObjectTemplateCode(
|
||||
extensionName,
|
||||
eventsBasedObject,
|
||||
codeNamespace,
|
||||
[&]() {
|
||||
gd::String runtimeObjectDataInitializationCode;
|
||||
for (auto& property :
|
||||
eventsBasedObject.GetPropertyDescriptors().GetInternalVector()) {
|
||||
runtimeObjectDataInitializationCode +=
|
||||
property->IsHidden()
|
||||
? GenerateInitializePropertyFromDefaultValueCode(*property)
|
||||
: GenerateInitializePropertyFromDataCode(*property);
|
||||
}
|
||||
|
||||
return runtimeObjectDataInitializationCode;
|
||||
},
|
||||
[&]() {
|
||||
gd::String runtimeObjectPropertyMethodsCode;
|
||||
for (auto& property :
|
||||
eventsBasedObject.GetPropertyDescriptors().GetInternalVector()) {
|
||||
runtimeObjectPropertyMethodsCode +=
|
||||
GenerateRuntimeObjectPropertyTemplateCode(
|
||||
eventsBasedObject, *property);
|
||||
}
|
||||
|
||||
return runtimeObjectPropertyMethodsCode;
|
||||
},
|
||||
// TODO: Update code generation to be able to generate methods (which would allow
|
||||
// for a cleaner output, not having to add methods to the prototype).
|
||||
[&]() {
|
||||
gd::String runtimeObjectMethodsCode;
|
||||
for (auto& eventsFunction : eventsFunctionsVector) {
|
||||
const gd::String& functionName =
|
||||
objectMethodMangledNames.find(eventsFunction->GetName()) !=
|
||||
objectMethodMangledNames.end()
|
||||
? objectMethodMangledNames.find(eventsFunction->GetName())
|
||||
->second
|
||||
: "UNKNOWN_FUNCTION_fix_objectMethodMangledNames_please";
|
||||
gd::String methodCodeNamespace =
|
||||
codeNamespace + "." + eventsBasedObject.GetName() +
|
||||
".prototype." + functionName + "Context";
|
||||
gd::String methodFullyQualifiedName = codeNamespace + "." +
|
||||
eventsBasedObject.GetName() +
|
||||
".prototype." + functionName;
|
||||
runtimeObjectMethodsCode +=
|
||||
EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
project,
|
||||
eventsBasedObject,
|
||||
*eventsFunction,
|
||||
methodCodeNamespace,
|
||||
methodFullyQualifiedName,
|
||||
"that._onceTriggers",
|
||||
functionName == doStepPreEventsFunctionName
|
||||
? GenerateDoStepPreEventsPreludeCode()
|
||||
: "",
|
||||
functionName == onCreatedFunctionName
|
||||
? "gdjs.CustomRuntimeObject.prototype.onCreated.call(this);\n"
|
||||
: "",
|
||||
includeFiles,
|
||||
compilationForRuntime);
|
||||
}
|
||||
|
||||
bool hasDoStepPreEventsFunction =
|
||||
eventsBasedObject.GetEventsFunctions().HasEventsFunctionNamed(
|
||||
doStepPreEventsFunctionName);
|
||||
if (!hasDoStepPreEventsFunction) {
|
||||
runtimeObjectMethodsCode +=
|
||||
GenerateDefaultDoStepPreEventsFunctionCode(eventsBasedObject,
|
||||
codeNamespace);
|
||||
}
|
||||
|
||||
return runtimeObjectMethodsCode;
|
||||
},
|
||||
[&]() {
|
||||
gd::String updateFromObjectCode;
|
||||
updateFromObjectCode += "super.updateFromObjectData(oldObjectData, newObjectData);";
|
||||
for (auto& property :
|
||||
eventsBasedObject.GetPropertyDescriptors().GetInternalVector()) {
|
||||
updateFromObjectCode +=
|
||||
GenerateUpdatePropertyFromObjectDataCode(
|
||||
eventsBasedObject, *property);
|
||||
}
|
||||
|
||||
return updateFromObjectCode;
|
||||
});
|
||||
}
|
||||
|
||||
gd::String ObjectCodeGenerator::GenerateRuntimeObjectTemplateCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace,
|
||||
std::function<gd::String()> generateInitializePropertiesCode,
|
||||
std::function<gd::String()> generatePropertiesCode,
|
||||
std::function<gd::String()> generateMethodsCode,
|
||||
std::function<gd::String()> generateUpdateFromObjectDataCode) {
|
||||
return gd::String(R"jscode_template(
|
||||
CODE_NAMESPACE = CODE_NAMESPACE || {};
|
||||
|
||||
/**
|
||||
* Object generated from OBJECT_FULL_NAME
|
||||
*/
|
||||
CODE_NAMESPACE.RUNTIME_OBJECT_CLASSNAME = class RUNTIME_OBJECT_CLASSNAME extends gdjs.CustomRuntimeObject {
|
||||
constructor(runtimeScene, objectData) {
|
||||
super(runtimeScene, objectData);
|
||||
this._runtimeScene = runtimeScene;
|
||||
|
||||
this._onceTriggers = new gdjs.OnceTriggers();
|
||||
this._behaviorData = {};
|
||||
INITIALIZE_PROPERTIES_CODE
|
||||
}
|
||||
|
||||
// Hot-reload:
|
||||
updateFromObjectData(oldObjectData, newObjectData) {
|
||||
UPDATE_FROM_OBJECT_DATA_CODE
|
||||
|
||||
this.onHotReloading(this.getInstanceContainer());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Properties:
|
||||
PROPERTIES_CODE
|
||||
}
|
||||
|
||||
// Methods:
|
||||
METHODS_CODE
|
||||
|
||||
gdjs.registerObject("EXTENSION_NAME::OBJECT_NAME", CODE_NAMESPACE.RUNTIME_OBJECT_CLASSNAME);
|
||||
)jscode_template")
|
||||
.FindAndReplace("EXTENSION_NAME", extensionName)
|
||||
.FindAndReplace("OBJECT_NAME", eventsBasedObject.GetName())
|
||||
.FindAndReplace("OBJECT_FULL_NAME", eventsBasedObject.GetFullName())
|
||||
.FindAndReplace("RUNTIME_OBJECT_CLASSNAME",
|
||||
eventsBasedObject.GetName())
|
||||
.FindAndReplace("CODE_NAMESPACE", codeNamespace)
|
||||
.FindAndReplace("INITIALIZE_PROPERTIES_CODE",
|
||||
generateInitializePropertiesCode())
|
||||
.FindAndReplace("UPDATE_FROM_OBJECT_DATA_CODE", generateUpdateFromObjectDataCode())
|
||||
.FindAndReplace("PROPERTIES_CODE", generatePropertiesCode())
|
||||
.FindAndReplace("METHODS_CODE", generateMethodsCode());
|
||||
;
|
||||
}
|
||||
// TODO these 2 methods are probably not needed if the properties are merged by GDJS.
|
||||
gd::String ObjectCodeGenerator::GenerateInitializePropertyFromDataCode(
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
return gd::String(R"jscode_template(
|
||||
this._objectData.content.PROPERTY_NAME = objectData.content.PROPERTY_NAME !== undefined ? objectData.content.PROPERTY_NAME : DEFAULT_VALUE;)jscode_template")
|
||||
.FindAndReplace("PROPERTY_NAME", property.GetName())
|
||||
.FindAndReplace("DEFAULT_VALUE", GeneratePropertyValueCode(property));
|
||||
}
|
||||
gd::String
|
||||
ObjectCodeGenerator::GenerateInitializePropertyFromDefaultValueCode(
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
return gd::String(R"jscode_template(
|
||||
this._objectData.content.PROPERTY_NAME = DEFAULT_VALUE;)jscode_template")
|
||||
.FindAndReplace("PROPERTY_NAME", property.GetName())
|
||||
.FindAndReplace("DEFAULT_VALUE", GeneratePropertyValueCode(property));
|
||||
}
|
||||
|
||||
gd::String ObjectCodeGenerator::GenerateRuntimeObjectPropertyTemplateCode(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
return gd::String(R"jscode_template(
|
||||
GETTER_NAME() {
|
||||
return this._objectData.content.PROPERTY_NAME !== undefined ? this._objectData.content.PROPERTY_NAME : DEFAULT_VALUE;
|
||||
}
|
||||
SETTER_NAME(newValue) {
|
||||
this._objectData.content.PROPERTY_NAME = newValue;
|
||||
})jscode_template")
|
||||
.FindAndReplace("PROPERTY_NAME", property.GetName())
|
||||
.FindAndReplace("GETTER_NAME",
|
||||
GetObjectPropertyGetterName(property.GetName()))
|
||||
.FindAndReplace("SETTER_NAME",
|
||||
GetObjectPropertySetterName(property.GetName()))
|
||||
.FindAndReplace("DEFAULT_VALUE", GeneratePropertyValueCode(property))
|
||||
.FindAndReplace("RUNTIME_OBJECT_CLASSNAME",
|
||||
eventsBasedObject.GetName());
|
||||
}
|
||||
|
||||
gd::String ObjectCodeGenerator::GenerateUpdatePropertyFromObjectDataCode(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::NamedPropertyDescriptor& property) {
|
||||
return gd::String(R"jscode_template(
|
||||
if (oldObjectData.content.PROPERTY_NAME !== newObjectData.content.PROPERTY_NAME)
|
||||
this._objectData.content.PROPERTY_NAME = newObjectData.content.PROPERTY_NAME;)jscode_template")
|
||||
.FindAndReplace("PROPERTY_NAME", property.GetName());
|
||||
}
|
||||
|
||||
gd::String ObjectCodeGenerator::GeneratePropertyValueCode(
|
||||
const gd::PropertyDescriptor& property) {
|
||||
if (property.GetType() == "String" ||
|
||||
property.GetType() == "Choice" ||
|
||||
property.GetType() == "Color") {
|
||||
return EventsCodeGenerator::ConvertToStringExplicit(property.GetValue());
|
||||
} else if (property.GetType() == "Number") {
|
||||
return "Number(" +
|
||||
EventsCodeGenerator::ConvertToStringExplicit(property.GetValue()) +
|
||||
") || 0";
|
||||
} else if (property.GetType() == "Boolean") { // TODO: Check if working
|
||||
return property.GetValue() == "true" ? "true" : "false";
|
||||
}
|
||||
|
||||
return "0 /* Error: property was of an unrecognized type */";
|
||||
}
|
||||
|
||||
gd::String ObjectCodeGenerator::GenerateDefaultDoStepPreEventsFunctionCode(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace) {
|
||||
return gd::String(R"jscode_template(
|
||||
CODE_NAMESPACE.RUNTIME_OBJECT_CLASSNAME.prototype.doStepPreEvents = function() {
|
||||
PRELUDE_CODE
|
||||
};
|
||||
)jscode_template")
|
||||
.FindAndReplace("RUNTIME_OBJECT_CLASSNAME",
|
||||
eventsBasedObject.GetName())
|
||||
.FindAndReplace("CODE_NAMESPACE", codeNamespace)
|
||||
.FindAndReplace("PRELUDE_CODE", GenerateDoStepPreEventsPreludeCode());
|
||||
}
|
||||
|
||||
gd::String ObjectCodeGenerator::GenerateDoStepPreEventsPreludeCode() {
|
||||
return "this._onceTriggers.startNewFrame();";
|
||||
}
|
||||
|
||||
} // namespace gdjs
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2008-2016 Florian Rival ([email protected]). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDJS_OBJECTCODEGENERATOR_H
|
||||
#define GDJS_OBJECTCODEGENERATOR_H
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
namespace gd {
|
||||
class NamedPropertyDescriptor;
|
||||
}
|
||||
|
||||
namespace gdjs {
|
||||
|
||||
/**
|
||||
* \brief The class being responsible for generating JavaScript code for
|
||||
* EventsBasedObject.
|
||||
*
|
||||
* See also gd::EventsCodeGenerator.
|
||||
*/
|
||||
class ObjectCodeGenerator {
|
||||
public:
|
||||
ObjectCodeGenerator(gd::Project& project_) : project(project_){};
|
||||
|
||||
/**
|
||||
* \brief Generate the complete JS class (`gdjs.CustomRuntimeObject`) for the
|
||||
* object.
|
||||
*/
|
||||
gd::String GenerateRuntimeObjectCompleteCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace,
|
||||
const std::map<gd::String, gd::String>& objectMethodMangledNames,
|
||||
std::set<gd::String>& includeFiles,
|
||||
bool compilationForRuntime = false);
|
||||
|
||||
/**
|
||||
* \brief Generate the name of the method to get the value of the property
|
||||
* of a object.
|
||||
*/
|
||||
static gd::String GetObjectPropertyGetterName(
|
||||
const gd::String& propertyName) {
|
||||
return "_get" + propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Generate the name of the method to set the value of the property
|
||||
* of a object.
|
||||
*/
|
||||
static gd::String GetObjectPropertySetterName(
|
||||
const gd::String& propertyName) {
|
||||
return "_set" + propertyName;
|
||||
}
|
||||
|
||||
private:
|
||||
gd::String GenerateRuntimeObjectTemplateCode(
|
||||
const gd::String& extensionName,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace,
|
||||
std::function<gd::String()> generateInitializePropertiesCode,
|
||||
std::function<gd::String()> generateMethodsCode,
|
||||
std::function<gd::String()> generatePropertiesCode,
|
||||
std::function<gd::String()> generateUpdateFromObjectDataCode);
|
||||
gd::String GenerateRuntimeObjectPropertyTemplateCode(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
gd::String GenerateInitializePropertyFromDataCode(
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
gd::String GenerateInitializePropertyFromDefaultValueCode(
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
gd::String GeneratePropertyValueCode(const gd::PropertyDescriptor& property);
|
||||
gd::String GenerateUpdatePropertyFromObjectDataCode(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::NamedPropertyDescriptor& property);
|
||||
gd::String GenerateObjectOnDestroyToDeprecatedOnOwnerRemovedFromScene(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace);
|
||||
gd::String GenerateDefaultDoStepPreEventsFunctionCode(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& codeNamespace);
|
||||
gd::String GenerateDoStepPreEventsPreludeCode();
|
||||
|
||||
gd::Project& project;
|
||||
|
||||
static gd::String onCreatedFunctionName;
|
||||
static gd::String doStepPreEventsFunctionName;
|
||||
};
|
||||
|
||||
} // namespace gdjs
|
||||
#endif // GDJS_OBJECTCODEGENERATOR_H
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "GDCore/Project/ExternalLayout.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Project/SourceFile.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
@@ -560,10 +562,12 @@ void ExporterHelper::AddLibsInclude(bool pixiRenderers,
|
||||
InsertUnique(includesFiles, "polygon.js");
|
||||
InsertUnique(includesFiles, "runtimeobject.js");
|
||||
InsertUnique(includesFiles, "profiler.js");
|
||||
InsertUnique(includesFiles, "RuntimeInstanceContainer.js");
|
||||
InsertUnique(includesFiles, "runtimescene.js");
|
||||
InsertUnique(includesFiles, "scenestack.js");
|
||||
InsertUnique(includesFiles, "force.js");
|
||||
InsertUnique(includesFiles, "layer.js");
|
||||
InsertUnique(includesFiles, "RuntimeSceneLayer.js");
|
||||
InsertUnique(includesFiles, "timer.js");
|
||||
InsertUnique(includesFiles, "runtimegame.js");
|
||||
InsertUnique(includesFiles, "variable.js");
|
||||
@@ -572,6 +576,8 @@ void ExporterHelper::AddLibsInclude(bool pixiRenderers,
|
||||
InsertUnique(includesFiles, "runtimebehavior.js");
|
||||
InsertUnique(includesFiles, "spriteruntimeobject.js");
|
||||
InsertUnique(includesFiles, "affinetransformation.js");
|
||||
InsertUnique(includesFiles, "CustomRuntimeObjectInstanceContainer.js");
|
||||
InsertUnique(includesFiles, "CustomRuntimeObject.js");
|
||||
|
||||
// Common includes for events only.
|
||||
InsertUnique(includesFiles, "events-tools/commontools.js");
|
||||
@@ -618,6 +624,10 @@ void ExporterHelper::AddLibsInclude(bool pixiRenderers,
|
||||
InsertUnique(includesFiles, "pixi-renderers/pixi-bitmapfont-manager.js");
|
||||
InsertUnique(includesFiles,
|
||||
"pixi-renderers/spriteruntimeobject-pixi-renderer.js");
|
||||
InsertUnique(includesFiles,
|
||||
"pixi-renderers/CustomObjectPixiRenderer.js");
|
||||
InsertUnique(includesFiles,
|
||||
"pixi-renderers/DebuggerPixiRenderer.js");
|
||||
InsertUnique(includesFiles,
|
||||
"pixi-renderers/loadingscreen-pixi-renderer.js");
|
||||
InsertUnique(includesFiles, "pixi-renderers/pixi-effects-manager.js");
|
||||
@@ -819,11 +829,25 @@ void ExporterHelper::ExportObjectAndBehaviorsIncludes(
|
||||
}
|
||||
};
|
||||
|
||||
// TODO UsedExtensionsFinder should be used instead to find the file to include.
|
||||
// The Exporter class already use it.
|
||||
addObjectsIncludeFiles(project);
|
||||
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
const gd::Layout &layout = project.GetLayout(i);
|
||||
addObjectsIncludeFiles(layout);
|
||||
}
|
||||
|
||||
// Event based objects children
|
||||
for (std::size_t e = 0; e < project.GetEventsFunctionsExtensionsCount(); e++) {
|
||||
auto& eventsFunctionsExtension = project.GetEventsFunctionsExtension(e);
|
||||
for (auto&& eventsBasedObjectUniquePtr :
|
||||
eventsFunctionsExtension.GetEventsBasedObjects()
|
||||
.GetInternalVector()) {
|
||||
auto eventsBasedObject = eventsBasedObjectUniquePtr.get();
|
||||
|
||||
addObjectsIncludeFiles(*eventsBasedObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExporterHelper::ExportObjectAndBehaviorsRequiredFiles(
|
||||
|
||||
@@ -0,0 +1,591 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2013-2022 Florian Rival ([email protected]). All rights reserved.
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
namespace gdjs {
|
||||
export type ObjectConfiguration = {
|
||||
content: any;
|
||||
};
|
||||
|
||||
export type CustomObjectConfiguration = ObjectConfiguration & {
|
||||
childrenContent: { [objectName: string]: ObjectConfiguration & any };
|
||||
};
|
||||
|
||||
/**
|
||||
* An object that contains other object.
|
||||
*
|
||||
* This is the base class for objects generated from EventsBasedObject.
|
||||
*
|
||||
* @see gdjs.CustomRuntimeObjectInstanceContainer
|
||||
*/
|
||||
export class CustomRuntimeObject extends gdjs.RuntimeObject {
|
||||
/** It contains the children of this object. */
|
||||
_instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer;
|
||||
_isUntransformedHitBoxesDirty: boolean = true;
|
||||
/** It contains shallow copies of the children hitboxes */
|
||||
_untransformedHitBoxes: gdjs.Polygon[] = [];
|
||||
/** The dimension of this object is calculated from its children AABBs. */
|
||||
_unrotatedAABB: AABB = { min: [0, 0], max: [0, 0] };
|
||||
_scaleX: number = 1;
|
||||
_scaleY: number = 1;
|
||||
_flippedX: boolean = false;
|
||||
_flippedY: boolean = false;
|
||||
opacity: float = 255;
|
||||
_objectData: ObjectData & CustomObjectConfiguration;
|
||||
|
||||
/**
|
||||
* @param parent The container the object belongs to
|
||||
* @param objectData The object data used to initialize the object
|
||||
*/
|
||||
constructor(
|
||||
parent: gdjs.RuntimeInstanceContainer,
|
||||
objectData: ObjectData & CustomObjectConfiguration
|
||||
) {
|
||||
super(parent, objectData);
|
||||
this._instanceContainer = new gdjs.CustomRuntimeObjectInstanceContainer(
|
||||
parent,
|
||||
this
|
||||
);
|
||||
this._objectData = objectData;
|
||||
|
||||
this._instanceContainer.loadFrom(objectData);
|
||||
this.getRenderer().reinitialize(this, parent);
|
||||
|
||||
// The generated code calls the onCreated super implementation at the end.
|
||||
this.onCreated();
|
||||
}
|
||||
|
||||
reinitialize(objectData: ObjectData & CustomObjectConfiguration) {
|
||||
super.reinitialize(objectData);
|
||||
|
||||
this._instanceContainer.loadFrom(objectData);
|
||||
this.getRenderer().reinitialize(this, this.getParent());
|
||||
|
||||
// The generated code calls the onCreated super implementation at the end.
|
||||
this.onCreated();
|
||||
}
|
||||
|
||||
updateFromObjectData(
|
||||
oldObjectData: ObjectData & CustomObjectConfiguration,
|
||||
newObjectData: ObjectData & CustomObjectConfiguration
|
||||
): boolean {
|
||||
return this._instanceContainer.updateFrom(oldObjectData, newObjectData);
|
||||
}
|
||||
|
||||
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
|
||||
if (initialInstanceData.customSize) {
|
||||
this.setWidth(initialInstanceData.width);
|
||||
this.setHeight(initialInstanceData.height);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
// Let subclasses do something before the object is destroyed.
|
||||
this.onDestroy(instanceContainer);
|
||||
// Let behaviors do something before the object is destroyed.
|
||||
super.onDestroyFromScene(instanceContainer);
|
||||
// Destroy the children.
|
||||
this._instanceContainer.onDestroyFromScene(instanceContainer);
|
||||
}
|
||||
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
this._instanceContainer._updateObjectsPreEvents();
|
||||
|
||||
this.doStepPreEvents(instanceContainer);
|
||||
|
||||
const profiler = this.getRuntimeScene().getProfiler();
|
||||
if (profiler) {
|
||||
profiler.begin(this._objectData.type);
|
||||
}
|
||||
// This is a bit like the "scene" events for custom objects.
|
||||
this.doStepPostEvents(instanceContainer);
|
||||
if (profiler) {
|
||||
profiler.end(this._objectData.type);
|
||||
}
|
||||
|
||||
this._instanceContainer._updateObjectsPostEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when the preview is being hot-reloaded.
|
||||
*/
|
||||
onHotReloading(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
// This is only to handle trigger once.
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
/**
|
||||
* This method is called each tick after events are done.
|
||||
* @param instanceContainer The instanceContainer owning the object
|
||||
*/
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
/**
|
||||
* This method is called when the object is being removed from its parent
|
||||
* container and is about to be destroyed/reused later.
|
||||
*/
|
||||
onDestroy(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
updatePreRender(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
this._instanceContainer._updateObjectsPreRender();
|
||||
this.getRenderer().ensureUpToDate();
|
||||
}
|
||||
|
||||
getRendererObject() {
|
||||
return this.getRenderer().getRendererObject();
|
||||
}
|
||||
|
||||
getRenderer() {
|
||||
return this._instanceContainer.getRenderer();
|
||||
}
|
||||
|
||||
onChildrenLocationChanged() {
|
||||
this._isUntransformedHitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().update();
|
||||
}
|
||||
|
||||
updateHitBoxes(): void {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
|
||||
//Update the current hitboxes with the frame custom hit boxes
|
||||
//and apply transformations.
|
||||
for (let i = 0; i < this._untransformedHitBoxes.length; ++i) {
|
||||
if (i >= this.hitBoxes.length) {
|
||||
this.hitBoxes.push(new gdjs.Polygon());
|
||||
}
|
||||
for (
|
||||
let j = 0;
|
||||
j < this._untransformedHitBoxes[i].vertices.length;
|
||||
++j
|
||||
) {
|
||||
if (j >= this.hitBoxes[i].vertices.length) {
|
||||
this.hitBoxes[i].vertices.push([0, 0]);
|
||||
}
|
||||
this.applyObjectTransformation(
|
||||
this._untransformedHitBoxes[i].vertices[j][0],
|
||||
this._untransformedHitBoxes[i].vertices[j][1],
|
||||
this.hitBoxes[i].vertices[j]
|
||||
);
|
||||
}
|
||||
this.hitBoxes[i].vertices.length = this._untransformedHitBoxes[
|
||||
i
|
||||
].vertices.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the hitboxes of the children.
|
||||
*/
|
||||
_updateUntransformedHitBoxes() {
|
||||
this._isUntransformedHitBoxesDirty = false;
|
||||
|
||||
const oldUnscaledCenterX =
|
||||
(this._unrotatedAABB.max[0] + this._unrotatedAABB.min[0]) / 2;
|
||||
const oldUnscaledCenterY =
|
||||
(this._unrotatedAABB.max[1] + this._unrotatedAABB.min[1]) / 2;
|
||||
|
||||
this._untransformedHitBoxes.length = 0;
|
||||
if (this._instanceContainer.getAdhocListOfAllInstances().length === 0) {
|
||||
this._unrotatedAABB.min[0] = 0;
|
||||
this._unrotatedAABB.min[1] = 0;
|
||||
this._unrotatedAABB.max[0] = 0;
|
||||
this._unrotatedAABB.max[1] = 0;
|
||||
} else {
|
||||
let minX = Number.MAX_VALUE;
|
||||
let minY = Number.MAX_VALUE;
|
||||
let maxX = -Number.MAX_VALUE;
|
||||
let maxY = -Number.MAX_VALUE;
|
||||
for (const childInstance of this._instanceContainer.getAdhocListOfAllInstances()) {
|
||||
Array.prototype.push.apply(
|
||||
this._untransformedHitBoxes,
|
||||
childInstance.getHitBoxes()
|
||||
);
|
||||
const childAABB = childInstance.getAABB();
|
||||
minX = Math.min(minX, childAABB.min[0]);
|
||||
minY = Math.min(minY, childAABB.min[1]);
|
||||
maxX = Math.max(maxX, childAABB.max[0]);
|
||||
maxY = Math.max(maxY, childAABB.max[1]);
|
||||
}
|
||||
this._unrotatedAABB.min[0] = minX;
|
||||
this._unrotatedAABB.min[1] = minY;
|
||||
this._unrotatedAABB.max[0] = maxX;
|
||||
this._unrotatedAABB.max[1] = maxY;
|
||||
|
||||
while (this.hitBoxes.length < this._untransformedHitBoxes.length) {
|
||||
this.hitBoxes.push(new gdjs.Polygon());
|
||||
}
|
||||
this.hitBoxes.length = this._untransformedHitBoxes.length;
|
||||
}
|
||||
|
||||
if (
|
||||
this.getUnscaledCenterX() !== oldUnscaledCenterX ||
|
||||
this.getUnscaledCenterY() !== oldUnscaledCenterY
|
||||
) {
|
||||
this._instanceContainer.onObjectUnscaledCenterChanged(
|
||||
oldUnscaledCenterX,
|
||||
oldUnscaledCenterY
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Position:
|
||||
/**
|
||||
* Return an array containing the coordinates of the point passed as parameter
|
||||
* in parent coordinate coordinates (as opposed to the object local coordinates).
|
||||
*
|
||||
* All transformations (flipping, scale, rotation) are supported.
|
||||
*
|
||||
* @param x The X position of the point, in object coordinates.
|
||||
* @param y The Y position of the point, in object coordinates.
|
||||
* @param result Array that will be updated with the result
|
||||
* (x and y position of the point in parent coordinates).
|
||||
*/
|
||||
applyObjectTransformation(x: float, y: float, result: number[]) {
|
||||
let cx = this.getCenterX();
|
||||
let cy = this.getCenterY();
|
||||
|
||||
// Flipping
|
||||
if (this._flippedX) {
|
||||
x = x + (cx - x) * 2;
|
||||
}
|
||||
if (this._flippedY) {
|
||||
y = y + (cy - y) * 2;
|
||||
}
|
||||
|
||||
// Scale
|
||||
const absScaleX = Math.abs(this._scaleX);
|
||||
const absScaleY = Math.abs(this._scaleY);
|
||||
x *= absScaleX;
|
||||
y *= absScaleY;
|
||||
cx *= absScaleX;
|
||||
cy *= absScaleY;
|
||||
|
||||
// Rotation
|
||||
const oldX = x;
|
||||
const angleInRadians = (this.angle / 180) * Math.PI;
|
||||
const cosValue = Math.cos(angleInRadians);
|
||||
const sinValue = Math.sin(angleInRadians);
|
||||
const xToCenterXDelta = x - cx;
|
||||
const yToCenterYDelta = y - cy;
|
||||
x = cx + cosValue * xToCenterXDelta - sinValue * yToCenterYDelta;
|
||||
y = cy + sinValue * xToCenterXDelta + cosValue * yToCenterYDelta;
|
||||
result.length = 2;
|
||||
result[0] = x + this.x;
|
||||
result[1] = y + this.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array containing the coordinates of the point passed as parameter
|
||||
* in object local coordinates (as opposed to the parent coordinate coordinates).
|
||||
*
|
||||
* All transformations (flipping, scale, rotation) are supported.
|
||||
*
|
||||
* @param x The X position of the point, in parent coordinates.
|
||||
* @param y The Y position of the point, in parent coordinates.
|
||||
* @param result Array that will be updated with the result
|
||||
* (x and y position of the point in object coordinates).
|
||||
*/
|
||||
applyObjectInverseTransformation(x: float, y: float, result: number[]) {
|
||||
x -= this.getCenterXInScene();
|
||||
y -= this.getCenterYInScene();
|
||||
|
||||
const absScaleX = Math.abs(this._scaleX);
|
||||
const absScaleY = Math.abs(this._scaleY);
|
||||
|
||||
// Rotation
|
||||
const angleInRadians = (this.angle / 180) * Math.PI;
|
||||
const cosValue = Math.cos(-angleInRadians);
|
||||
const sinValue = Math.sin(-angleInRadians);
|
||||
const oldX = x;
|
||||
x = cosValue * x - sinValue * y;
|
||||
y = sinValue * oldX + cosValue * y;
|
||||
|
||||
// Scale
|
||||
x /= absScaleX;
|
||||
y /= absScaleY;
|
||||
|
||||
// Flipping
|
||||
if (this._flippedX) {
|
||||
x = -x;
|
||||
}
|
||||
if (this._flippedY) {
|
||||
y = -y;
|
||||
}
|
||||
|
||||
const positionToCenterX =
|
||||
this.getUnscaledWidth() / 2 + this._unrotatedAABB.min[0];
|
||||
const positionToCenterY =
|
||||
this.getUnscaledHeight() / 2 + this._unrotatedAABB.min[1];
|
||||
result[0] = x + positionToCenterX;
|
||||
result[1] = y + positionToCenterY;
|
||||
}
|
||||
|
||||
getDrawableX(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return this.x + this._unrotatedAABB.min[0] * this._scaleX;
|
||||
}
|
||||
|
||||
getDrawableY(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return this.y + this._unrotatedAABB.min[1] * this._scaleY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internal width of the object according to its children.
|
||||
*/
|
||||
getUnscaledWidth(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return this._unrotatedAABB.max[0] - this._unrotatedAABB.min[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the internal height of the object according to its children.
|
||||
*/
|
||||
getUnscaledHeight(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return this._unrotatedAABB.max[1] - this._unrotatedAABB.min[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the center X from the local origin (0;0).
|
||||
*/
|
||||
getUnscaledCenterX(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return (this._unrotatedAABB.min[0] + this._unrotatedAABB.max[0]) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the center Y from the local origin (0;0).
|
||||
*/
|
||||
getUnscaledCenterY(): float {
|
||||
if (this._isUntransformedHitBoxesDirty) {
|
||||
this._updateUntransformedHitBoxes();
|
||||
}
|
||||
return (this._unrotatedAABB.min[1] + this._unrotatedAABB.max[1]) / 2;
|
||||
}
|
||||
|
||||
getWidth(): float {
|
||||
return this.getUnscaledWidth() * this.getScaleX();
|
||||
}
|
||||
|
||||
getHeight(): float {
|
||||
return this.getUnscaledHeight() * this.getScaleY();
|
||||
}
|
||||
|
||||
setWidth(newWidth: float): void {
|
||||
const unscaledWidth = this.getUnscaledWidth();
|
||||
if (unscaledWidth !== 0) {
|
||||
this.setScaleX(newWidth / unscaledWidth);
|
||||
}
|
||||
}
|
||||
|
||||
setHeight(newHeight: float): void {
|
||||
const unscaledHeight = this.getUnscaledHeight();
|
||||
if (unscaledHeight !== 0) {
|
||||
this.setScaleY(newHeight / unscaledHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the size of the object.
|
||||
*
|
||||
* @param newWidth The new width of the object, in pixels.
|
||||
* @param newHeight The new height of the object, in pixels.
|
||||
*/
|
||||
setSize(newWidth: float, newHeight: float): void {
|
||||
this.setWidth(newWidth);
|
||||
this.setHeight(newHeight);
|
||||
}
|
||||
|
||||
setX(x: float): void {
|
||||
if (x === this.x) {
|
||||
return;
|
||||
}
|
||||
this.x = x;
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().updateX();
|
||||
}
|
||||
|
||||
setY(y: float): void {
|
||||
if (y === this.y) {
|
||||
return;
|
||||
}
|
||||
this.y = y;
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().updateY();
|
||||
}
|
||||
|
||||
setAngle(angle: float): void {
|
||||
if (this.angle === angle) {
|
||||
return;
|
||||
}
|
||||
this.angle = angle;
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().updateAngle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on X and Y axis of the object.
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScale(newScale: number): void {
|
||||
if (newScale < 0) {
|
||||
newScale = 0;
|
||||
}
|
||||
if (
|
||||
newScale === Math.abs(this._scaleX) &&
|
||||
newScale === Math.abs(this._scaleY)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this._scaleX = newScale * (this._flippedX ? -1 : 1);
|
||||
this._scaleY = newScale * (this._flippedY ? -1 : 1);
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on X axis of the object (changing its width).
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScaleX(newScale: number): void {
|
||||
if (newScale < 0) {
|
||||
newScale = 0;
|
||||
}
|
||||
if (newScale === Math.abs(this._scaleX)) {
|
||||
return;
|
||||
}
|
||||
this._scaleX = newScale * (this._flippedX ? -1 : 1);
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on Y axis of the object (changing its height).
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScaleY(newScale: number): void {
|
||||
if (newScale < 0) {
|
||||
newScale = 0;
|
||||
}
|
||||
if (newScale === Math.abs(this._scaleY)) {
|
||||
return;
|
||||
}
|
||||
this._scaleY = newScale * (this._flippedY ? -1 : 1);
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object (or the average of the X and Y scale in case
|
||||
* they are different).
|
||||
*
|
||||
* @return the scale of the object (or the average of the X and Y scale in
|
||||
* case they are different).
|
||||
*/
|
||||
getScale(): number {
|
||||
return (Math.abs(this._scaleX) + Math.abs(this._scaleY)) / 2.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object on Y axis.
|
||||
*
|
||||
* @return the scale of the object on Y axis
|
||||
*/
|
||||
getScaleY(): float {
|
||||
return Math.abs(this._scaleY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object on X axis.
|
||||
*
|
||||
* @return the scale of the object on X axis
|
||||
*/
|
||||
getScaleX(): float {
|
||||
return Math.abs(this._scaleX);
|
||||
}
|
||||
|
||||
// Visibility and display :
|
||||
/**
|
||||
* Change the transparency of the object.
|
||||
* @param opacity The new opacity, between 0 (transparent) and 255 (opaque).
|
||||
*/
|
||||
setOpacity(opacity: float): void {
|
||||
if (opacity < 0) {
|
||||
opacity = 0;
|
||||
}
|
||||
if (opacity > 255) {
|
||||
opacity = 255;
|
||||
}
|
||||
this.opacity = opacity;
|
||||
this.getRenderer().updateOpacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the transparency of the object.
|
||||
* @return The opacity, between 0 (transparent) and 255 (opaque).
|
||||
*/
|
||||
getOpacity(): number {
|
||||
return this.opacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide (or show) the object
|
||||
* @param enable true to hide the object, false to show it again.
|
||||
*/
|
||||
hide(enable: boolean): void {
|
||||
if (enable === undefined) {
|
||||
enable = true;
|
||||
}
|
||||
this.hidden = enable;
|
||||
this.getRenderer().updateVisibility();
|
||||
}
|
||||
|
||||
flipX(enable: boolean) {
|
||||
if (enable !== this._flippedX) {
|
||||
this._scaleX *= -1;
|
||||
this._flippedX = enable;
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().update();
|
||||
}
|
||||
}
|
||||
|
||||
flipY(enable: boolean) {
|
||||
if (enable !== this._flippedY) {
|
||||
this._scaleY *= -1;
|
||||
this._flippedY = enable;
|
||||
this.invalidateHitboxes();
|
||||
this.getRenderer().update();
|
||||
}
|
||||
}
|
||||
|
||||
isFlippedX(): boolean {
|
||||
return this._flippedX;
|
||||
}
|
||||
|
||||
isFlippedY(): boolean {
|
||||
return this._flippedY;
|
||||
}
|
||||
}
|
||||
|
||||
// Others initialization and internal state management :
|
||||
// TODO EBO Activate and test instance recycling.
|
||||
CustomRuntimeObject.supportsReinitialization = false;
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2013-2022 Florian Rival ([email protected]). All rights reserved.
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('CustomRuntimeObject');
|
||||
const setupWarningLogger = new gdjs.Logger(
|
||||
'CustomRuntimeObject (setup warnings)'
|
||||
);
|
||||
|
||||
/**
|
||||
* The instance container of a custom object, containing instances of objects rendered on screen.
|
||||
*
|
||||
* @see gdjs.CustomRuntimeObject
|
||||
*/
|
||||
export class CustomRuntimeObjectInstanceContainer extends gdjs.RuntimeInstanceContainer {
|
||||
_renderer: gdjs.CustomObjectRenderer;
|
||||
_debuggerRenderer: gdjs.DebuggerRenderer;
|
||||
_runtimeScene: gdjs.RuntimeScene;
|
||||
/** The parent container that contains the object associated with this container. */
|
||||
_parent: gdjs.RuntimeInstanceContainer;
|
||||
/** The object that is built with the instances of this container. */
|
||||
_customObject: gdjs.CustomRuntimeObject;
|
||||
_isLoaded: boolean = false;
|
||||
|
||||
/**
|
||||
* @param parent the parent container that contains the object associated
|
||||
* with this container.
|
||||
* @param customObject the object that is built with the instances of this
|
||||
* container.
|
||||
*/
|
||||
constructor(
|
||||
parent: gdjs.RuntimeInstanceContainer,
|
||||
customObject: gdjs.CustomRuntimeObject
|
||||
) {
|
||||
super();
|
||||
this._parent = parent;
|
||||
this._customObject = customObject;
|
||||
this._runtimeScene = parent.getScene();
|
||||
this._renderer = new gdjs.CustomObjectRenderer(
|
||||
customObject,
|
||||
this,
|
||||
parent
|
||||
);
|
||||
this._debuggerRenderer = new gdjs.DebuggerRenderer(this);
|
||||
}
|
||||
|
||||
createObject(objectName: string): gdjs.RuntimeObject | null {
|
||||
const result = super.createObject(objectName);
|
||||
this._customObject.onChildrenLocationChanged();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the container from the given initial configuration.
|
||||
* @param customObjectData An object containing the container data.
|
||||
* @see gdjs.RuntimeGame#getSceneData
|
||||
*/
|
||||
loadFrom(customObjectData: ObjectData & CustomObjectConfiguration) {
|
||||
if (this._isLoaded) {
|
||||
this.onDestroyFromScene(this._parent);
|
||||
}
|
||||
|
||||
const eventsBasedObjectData = this._runtimeScene
|
||||
.getGame()
|
||||
.getEventsBasedObjectData(customObjectData.type);
|
||||
if (!eventsBasedObjectData) {
|
||||
logger.error('loadFrom was called without an events-based object');
|
||||
return;
|
||||
}
|
||||
|
||||
// Registering objects
|
||||
for (
|
||||
let i = 0, len = eventsBasedObjectData.objects.length;
|
||||
i < len;
|
||||
++i
|
||||
) {
|
||||
const childObjectData = eventsBasedObjectData.objects[i];
|
||||
this.registerObject({
|
||||
...childObjectData,
|
||||
...customObjectData.childrenContent[childObjectData.name],
|
||||
});
|
||||
}
|
||||
|
||||
// TODO EBO Remove it when the instance editor is done.
|
||||
// Add a default layer
|
||||
this.addLayer({
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [
|
||||
{
|
||||
defaultSize: true,
|
||||
defaultViewport: true,
|
||||
height: 0,
|
||||
viewportBottom: 0,
|
||||
viewportLeft: 0,
|
||||
viewportRight: 0,
|
||||
viewportTop: 0,
|
||||
width: 0,
|
||||
},
|
||||
],
|
||||
effects: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
});
|
||||
|
||||
// Set up the default z order (for objects created from events)
|
||||
this._setLayerDefaultZOrders();
|
||||
|
||||
this._isLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the container must be updated using the specified
|
||||
* objectData. This is the case during hot-reload, and is only called if
|
||||
* the object was modified.
|
||||
*
|
||||
* @param oldCustomObjectData The previous data for the object.
|
||||
* @param newCustomObjectData The new data for the object.
|
||||
* @returns true if the object was updated, false if it could not
|
||||
* (i.e: hot-reload is not supported).
|
||||
*/
|
||||
updateFrom(
|
||||
oldCustomObjectData: ObjectData & CustomObjectConfiguration,
|
||||
newCustomObjectData: ObjectData & CustomObjectConfiguration
|
||||
): boolean {
|
||||
const eventsBasedObjectData = this._runtimeScene
|
||||
.getGame()
|
||||
.getEventsBasedObjectData(newCustomObjectData.type);
|
||||
if (!eventsBasedObjectData) {
|
||||
logger.error('updateFrom was called without an events-based object');
|
||||
return false;
|
||||
}
|
||||
|
||||
for (
|
||||
let i = 0, len = eventsBasedObjectData.objects.length;
|
||||
i < len;
|
||||
++i
|
||||
) {
|
||||
const childName = eventsBasedObjectData.objects[i].name;
|
||||
const oldChildData = {
|
||||
...eventsBasedObjectData.objects[i],
|
||||
...oldCustomObjectData.childrenContent[childName],
|
||||
};
|
||||
const newChildData = {
|
||||
...eventsBasedObjectData.objects[i],
|
||||
...newCustomObjectData.childrenContent[childName],
|
||||
};
|
||||
this.updateObject(newChildData);
|
||||
|
||||
for (const child of this.getInstancesOf(childName)) {
|
||||
child.updateFromObjectData(oldChildData, newChildData);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the associated object is destroyed (because it is removed
|
||||
* from its parent container or the scene is being unloaded).
|
||||
*
|
||||
* @param instanceContainer The container owning the object.
|
||||
*/
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if (!this._isLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify the objects they are being destroyed
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
object.onDestroyFromScene(this);
|
||||
}
|
||||
|
||||
this._destroy();
|
||||
|
||||
this._isLoaded = false;
|
||||
}
|
||||
|
||||
_destroy() {
|
||||
// It should not be necessary to reset these variables, but this help
|
||||
// ensuring that all memory related to the container is released immediately.
|
||||
super._destroy();
|
||||
// @ts-ignore We are deleting the object
|
||||
this._onceTriggers = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update visibility of the renderers of objects
|
||||
* rendered on the scene ("culling"), update effects (of visible objects)
|
||||
* and give a last chance for objects to update before rendering.
|
||||
*
|
||||
* Visibility is set to false if object is hidden, or if
|
||||
* object is too far from the camera of its layer ("culling").
|
||||
*/
|
||||
_updateObjectsPreRender() {
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (
|
||||
let i = 0, len = this.getAdhocListOfAllInstances().length;
|
||||
i < len;
|
||||
++i
|
||||
) {
|
||||
const object = this.getAdhocListOfAllInstances()[i];
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (rendererObject) {
|
||||
rendererObject.visible = !object.isHidden();
|
||||
|
||||
// Update effects, only for visible objects.
|
||||
if (rendererObject.visible) {
|
||||
this.getGame()
|
||||
.getEffectsManager()
|
||||
.updatePreRender(object.getRendererEffects(), object);
|
||||
}
|
||||
}
|
||||
|
||||
// Set to true to enable debug rendering (look for the implementation in the renderer
|
||||
// to see what is rendered).
|
||||
if (this._debugDrawEnabled) {
|
||||
this._debuggerRenderer.renderDebugDraw(
|
||||
this.getAdhocListOfAllInstances(),
|
||||
this._debugDrawShowHiddenInstances,
|
||||
this._debugDrawShowPointsNames,
|
||||
this._debugDrawShowCustomPoints
|
||||
);
|
||||
}
|
||||
|
||||
// Perform pre-render update.
|
||||
object.updatePreRender(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the objects before launching the events.
|
||||
*/
|
||||
_updateObjectsPreEvents() {
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const obj = allInstancesList[i];
|
||||
const elapsedTime = obj.getElapsedTime();
|
||||
if (!obj.hasNoForces()) {
|
||||
const averageForce = obj.getAverageForce();
|
||||
const 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);
|
||||
obj.stepBehaviorsPreEvents(this);
|
||||
}
|
||||
|
||||
// Some behaviors may have request objects to be deleted.
|
||||
this._cacheOrClearRemovedInstances();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the renderer associated to the RuntimeScene.
|
||||
*/
|
||||
getRenderer(): gdjs.CustomObjectRenderer {
|
||||
return this._renderer;
|
||||
}
|
||||
|
||||
getDebuggerRenderer() {
|
||||
return this._debuggerRenderer;
|
||||
}
|
||||
|
||||
getGame() {
|
||||
return this._runtimeScene.getGame();
|
||||
}
|
||||
|
||||
getScene() {
|
||||
return this._runtimeScene;
|
||||
}
|
||||
|
||||
getViewportWidth(): float {
|
||||
return this._customObject.getUnscaledWidth();
|
||||
}
|
||||
|
||||
getViewportHeight(): float {
|
||||
return this._customObject.getUnscaledHeight();
|
||||
}
|
||||
|
||||
getViewportOriginX(): float {
|
||||
return this._customObject.getUnscaledCenterX();
|
||||
}
|
||||
|
||||
getViewportOriginY(): float {
|
||||
return this._customObject.getUnscaledCenterY();
|
||||
}
|
||||
|
||||
onChildrenLocationChanged(): void {
|
||||
this._customObject.onChildrenLocationChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when the object dimensions are changed.
|
||||
*
|
||||
* It adapts the layers camera positions.
|
||||
*/
|
||||
onObjectUnscaledCenterChanged(oldOriginX: float, oldOriginY: float): void {
|
||||
for (const name in this._layers.items) {
|
||||
if (this._layers.items.hasOwnProperty(name)) {
|
||||
/** @type gdjs.Layer */
|
||||
const theLayer: gdjs.Layer = this._layers.items[name];
|
||||
theLayer.onGameResolutionResized(oldOriginX, oldOriginY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
convertCoords(x: float, y: float, result: FloatPoint): FloatPoint {
|
||||
// The result parameter used to be optional.
|
||||
let position = result || [0, 0];
|
||||
position = this._parent
|
||||
.getLayer(this._customObject.getLayer())
|
||||
.convertCoords(x, y, 0, position);
|
||||
this._customObject.applyObjectInverseTransformation(
|
||||
position[0],
|
||||
position[1],
|
||||
position
|
||||
);
|
||||
return position;
|
||||
}
|
||||
|
||||
convertInverseCoords(
|
||||
sceneX: float,
|
||||
sceneY: float,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
const position = result || [0, 0];
|
||||
this._customObject.applyObjectTransformation(sceneX, sceneY, position);
|
||||
return this._parent.convertInverseCoords(
|
||||
position[0],
|
||||
position[1],
|
||||
position
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time elapsed since the last frame,
|
||||
* in milliseconds, for objects on the layer.
|
||||
*/
|
||||
getElapsedTime(): float {
|
||||
return this._parent.getElapsedTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,694 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2013-2016 Florian Rival ([email protected]). All rights reserved.
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
namespace gdjs {
|
||||
const logger = new gdjs.Logger('RuntimeInstanceContainer');
|
||||
const setupWarningLogger = new gdjs.Logger(
|
||||
'RuntimeInstanceContainer (setup warnings)'
|
||||
);
|
||||
|
||||
/**
|
||||
* A container of object instances rendered on screen.
|
||||
*/
|
||||
export abstract class RuntimeInstanceContainer {
|
||||
/** Contains the instances living on the container */
|
||||
_instances: Hashtable<RuntimeObject[]>;
|
||||
|
||||
/**
|
||||
* An array used to create a list of all instance when necessary.
|
||||
* @see gdjs.RuntimeInstanceContainer#_constructListOfAllInstances}
|
||||
*/
|
||||
private _allInstancesList: gdjs.RuntimeObject[] = [];
|
||||
_allInstancesListIsUpToDate = true;
|
||||
|
||||
/** Used to recycle destroyed instance instead of creating new ones. */
|
||||
_instancesCache: Hashtable<RuntimeObject[]>;
|
||||
|
||||
/** The instances removed from the container and waiting to be sent to the cache. */
|
||||
_instancesRemoved: gdjs.RuntimeObject[] = [];
|
||||
|
||||
/** Contains the objects data stored in the project */
|
||||
_objects: Hashtable<ObjectData>;
|
||||
_objectsCtor: Hashtable<typeof RuntimeObject>;
|
||||
|
||||
_layers: Hashtable<Layer>;
|
||||
_layersCameraCoordinates: Record<string, [float, float, float, float]> = {};
|
||||
|
||||
// Options for the debug draw:
|
||||
_debugDrawEnabled: boolean = false;
|
||||
_debugDrawShowHiddenInstances: boolean = false;
|
||||
_debugDrawShowPointsNames: boolean = false;
|
||||
_debugDrawShowCustomPoints: boolean = false;
|
||||
|
||||
constructor() {
|
||||
this._instances = new Hashtable();
|
||||
this._instancesCache = new Hashtable();
|
||||
this._objects = new Hashtable();
|
||||
this._objectsCtor = new Hashtable();
|
||||
this._layers = new Hashtable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time elapsed since the last frame,
|
||||
* in milliseconds, for objects on the layer.
|
||||
*/
|
||||
abstract getElapsedTime(): float;
|
||||
|
||||
/**
|
||||
* Get the renderer associated to the container.
|
||||
*/
|
||||
abstract getRenderer(): gdjs.RuntimeInstanceContainerRenderer;
|
||||
|
||||
/**
|
||||
* Get the renderer for visual debugging associated to the container.
|
||||
*/
|
||||
abstract getDebuggerRenderer(): gdjs.DebuggerRenderer;
|
||||
|
||||
/**
|
||||
* Get the {@link gdjs.RuntimeGame} associated to this.
|
||||
*/
|
||||
abstract getGame(): gdjs.RuntimeGame;
|
||||
|
||||
/**
|
||||
* Get the {@link gdjs.RuntimeScene} associated to this.
|
||||
*/
|
||||
abstract getScene(): gdjs.RuntimeScene;
|
||||
|
||||
/**
|
||||
* Convert a point from the canvas coordinates (for example,
|
||||
* the mouse position) to the container coordinates.
|
||||
*
|
||||
* @param x The x position, in container coordinates.
|
||||
* @param y The y position, in container coordinates.
|
||||
* @param result The point instance that is used to return the result.
|
||||
*/
|
||||
abstract convertCoords(x: float, y: float, result?: FloatPoint): FloatPoint;
|
||||
|
||||
/**
|
||||
* Convert a point from the container coordinates (for example,
|
||||
* an object position) to the canvas coordinates.
|
||||
*
|
||||
* @param sceneX The x position, in container coordinates.
|
||||
* @param sceneY The y position, in container coordinates.
|
||||
* @param result The point instance that is used to return the result.
|
||||
*/
|
||||
abstract convertInverseCoords(
|
||||
sceneX: float,
|
||||
sceneY: float,
|
||||
result: FloatPoint
|
||||
): FloatPoint;
|
||||
|
||||
/**
|
||||
* @return the width of:
|
||||
* - the game resolution for a {@link gdjs.RuntimeScene}
|
||||
* - the default dimensions (the AABB of all its children) for a
|
||||
* {@link gdjs.CustomRuntimeObject}.
|
||||
*/
|
||||
abstract getViewportWidth(): float;
|
||||
|
||||
/**
|
||||
* @return the height of:
|
||||
* - the game resolution for a {@link gdjs.RuntimeScene}
|
||||
* - the default dimensions (the AABB of all its children) for a
|
||||
* {@link gdjs.CustomRuntimeObject}.
|
||||
*/
|
||||
abstract getViewportHeight(): float;
|
||||
|
||||
/**
|
||||
* @return the center X of:
|
||||
* - the game resolution for a {@link gdjs.RuntimeScene}
|
||||
* - the default dimensions (the AABB of all its children) for a
|
||||
* {@link gdjs.CustomRuntimeObject}.
|
||||
*/
|
||||
abstract getViewportOriginX(): float;
|
||||
|
||||
/**
|
||||
* @return the center Y of:
|
||||
* - the game resolution for a {@link gdjs.RuntimeScene}
|
||||
* - the default dimensions (the AABB of all its children) for a
|
||||
* {@link gdjs.CustomRuntimeObject}.
|
||||
*/
|
||||
abstract getViewportOriginY(): float;
|
||||
|
||||
/**
|
||||
* Triggered when the AABB of a child of the container could have changed.
|
||||
*/
|
||||
abstract onChildrenLocationChanged(): void;
|
||||
|
||||
/**
|
||||
* Activate or deactivate the debug visualization for collisions and points.
|
||||
*/
|
||||
enableDebugDraw(
|
||||
enableDebugDraw: boolean,
|
||||
showHiddenInstances: boolean,
|
||||
showPointsNames: boolean,
|
||||
showCustomPoints: boolean
|
||||
): void {
|
||||
if (this._debugDrawEnabled && !enableDebugDraw) {
|
||||
this.getDebuggerRenderer().clearDebugDraw();
|
||||
}
|
||||
|
||||
this._debugDrawEnabled = enableDebugDraw;
|
||||
this._debugDrawShowHiddenInstances = showHiddenInstances;
|
||||
this._debugDrawShowPointsNames = showPointsNames;
|
||||
this._debugDrawShowCustomPoints = showCustomPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an object is registered, meaning that instances of it can be
|
||||
* created and lives in the container.
|
||||
* @see gdjs.RuntimeInstanceContainer#registerObject
|
||||
*/
|
||||
isObjectRegistered(objectName: string): boolean {
|
||||
return (
|
||||
this._objects.containsKey(objectName) &&
|
||||
this._instances.containsKey(objectName) &&
|
||||
this._objectsCtor.containsKey(objectName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link gdjs.RuntimeObject} so that instances of it can be
|
||||
* used in the container.
|
||||
* @param objectData The data for the object to register.
|
||||
*/
|
||||
registerObject(objectData: ObjectData) {
|
||||
this._objects.put(objectData.name, objectData);
|
||||
this._instances.put(objectData.name, []);
|
||||
|
||||
// Cache the constructor
|
||||
const Ctor = gdjs.getObjectConstructor(objectData.type);
|
||||
this._objectsCtor.put(objectData.name, Ctor);
|
||||
|
||||
// Also prepare a cache for recycled instances, if the object supports it.
|
||||
if (Ctor.supportsReinitialization) {
|
||||
this._instancesCache.put(objectData.name, []);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the data of a {@link gdjs.RuntimeObject} so that instances use
|
||||
* this when constructed.
|
||||
* @param objectData The data for the object to register.
|
||||
*/
|
||||
updateObject(objectData: ObjectData): void {
|
||||
if (!this.isObjectRegistered(objectData.name)) {
|
||||
logger.warn(
|
||||
'Tried to call updateObject for an object that was not registered (' +
|
||||
objectData.name +
|
||||
'). Call registerObject first.'
|
||||
);
|
||||
}
|
||||
this._objects.put(objectData.name, objectData);
|
||||
}
|
||||
|
||||
// Don't erase instances, nor instances cache, or objectsCtor cache.
|
||||
/**
|
||||
* Unregister a {@link gdjs.RuntimeObject}. Instances will be destroyed.
|
||||
* @param objectName The name of the object to unregister.
|
||||
*/
|
||||
unregisterObject(objectName: string) {
|
||||
const instances = this._instances.get(objectName);
|
||||
if (instances) {
|
||||
// This is sub-optimal: markObjectForDeletion will search the instance to
|
||||
// remove in instances, so cost is O(n^2), n being the number of instances.
|
||||
// As we're unregistering an object which only happen during a hot-reloading,
|
||||
// this is fine.
|
||||
const instancesToRemove = instances.slice();
|
||||
for (let i = 0; i < instancesToRemove.length; i++) {
|
||||
this.markObjectForDeletion(instancesToRemove[i]);
|
||||
}
|
||||
this._cacheOrClearRemovedInstances();
|
||||
}
|
||||
this._objects.remove(objectName);
|
||||
this._instances.remove(objectName);
|
||||
this._instancesCache.remove(objectName);
|
||||
this._objectsCtor.remove(objectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create objects from initial instances data (for example, the initial instances
|
||||
* of the scene or the instances of an external layout).
|
||||
*
|
||||
* @param data The instances data
|
||||
* @param xPos The offset on X axis
|
||||
* @param yPos The offset on Y axis
|
||||
* @param trackByPersistentUuid If true, objects are tracked by setting their `persistentUuid`
|
||||
* to the same as the associated instance. Useful for hot-reloading when instances are changed.
|
||||
*/
|
||||
createObjectsFrom(
|
||||
data: InstanceData[],
|
||||
xPos: float,
|
||||
yPos: float,
|
||||
trackByPersistentUuid: boolean
|
||||
) {
|
||||
for (let i = 0, len = data.length; i < len; ++i) {
|
||||
const instanceData = data[i];
|
||||
const objectName = instanceData.name;
|
||||
const newObject = this.createObject(objectName);
|
||||
if (newObject !== null) {
|
||||
if (trackByPersistentUuid) {
|
||||
// Give the object the same persistentUuid as the instance, so that
|
||||
// it can be hot-reloaded.
|
||||
newObject.persistentUuid = instanceData.persistentUuid || null;
|
||||
}
|
||||
newObject.setPosition(instanceData.x + xPos, instanceData.y + yPos);
|
||||
newObject.setZOrder(instanceData.zOrder);
|
||||
newObject.setAngle(instanceData.angle);
|
||||
newObject.setLayer(instanceData.layer);
|
||||
newObject
|
||||
.getVariables()
|
||||
.initFrom(instanceData.initialVariables, true);
|
||||
newObject.extraInitializationFromInitialInstance(instanceData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default Z order for each layer, which is the highest Z order found on each layer.
|
||||
* Useful as it ensures that instances created from events are, by default, shown in front
|
||||
* of other instances.
|
||||
*/
|
||||
_setLayerDefaultZOrders() {
|
||||
if (
|
||||
this.getGame().getGameData().properties.useDeprecatedZeroAsDefaultZOrder
|
||||
) {
|
||||
// Deprecated option to still support games that were made considered 0 as the
|
||||
// default Z order for all layers.
|
||||
return;
|
||||
}
|
||||
const layerHighestZOrders: Record<string, number> = {};
|
||||
const allInstances = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstances.length; i < len; ++i) {
|
||||
const object = allInstances[i];
|
||||
let layerName = object.getLayer();
|
||||
const zOrder = object.getZOrder();
|
||||
if (
|
||||
layerHighestZOrders[layerName] === undefined ||
|
||||
layerHighestZOrders[layerName] < zOrder
|
||||
) {
|
||||
layerHighestZOrders[layerName] = zOrder;
|
||||
}
|
||||
}
|
||||
for (let layerName in layerHighestZOrders) {
|
||||
this.getLayer(layerName).setDefaultZOrder(
|
||||
layerHighestZOrders[layerName] + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_updateLayersCameraCoordinates(scale: float) {
|
||||
this._layersCameraCoordinates = this._layersCameraCoordinates || {};
|
||||
for (const name in this._layers.items) {
|
||||
if (this._layers.items.hasOwnProperty(name)) {
|
||||
const theLayer = this._layers.items[name];
|
||||
this._layersCameraCoordinates[name] = this._layersCameraCoordinates[
|
||||
name
|
||||
] || [0, 0, 0, 0];
|
||||
this._layersCameraCoordinates[name][0] =
|
||||
theLayer.getCameraX() - (theLayer.getCameraWidth() / 2) * scale;
|
||||
this._layersCameraCoordinates[name][1] =
|
||||
theLayer.getCameraY() - (theLayer.getCameraHeight() / 2) * scale;
|
||||
this._layersCameraCoordinates[name][2] =
|
||||
theLayer.getCameraX() + (theLayer.getCameraWidth() / 2) * scale;
|
||||
this._layersCameraCoordinates[name][3] =
|
||||
theLayer.getCameraY() + (theLayer.getCameraHeight() / 2) * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update effects of layers before rendering.
|
||||
*/
|
||||
_updateLayersPreRender() {
|
||||
for (const name in this._layers.items) {
|
||||
if (this._layers.items.hasOwnProperty(name)) {
|
||||
const layer = this._layers.items[name];
|
||||
layer.updatePreRender(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update visibility of the renderers of objects
|
||||
* rendered on the scene ("culling"), update effects (of visible objects)
|
||||
* and give a last chance for objects to update before rendering.
|
||||
*
|
||||
* Visibility is set to false if object is hidden, or if
|
||||
* object is too far from the camera of its layer ("culling").
|
||||
*/
|
||||
_updateObjectsPreRender() {
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (rendererObject) {
|
||||
rendererObject.visible = !object.isHidden();
|
||||
|
||||
// Update effects, only for visible objects.
|
||||
if (rendererObject.visible) {
|
||||
this.getGame()
|
||||
.getEffectsManager()
|
||||
.updatePreRender(object.getRendererEffects(), object);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform pre-render update.
|
||||
object.updatePreRender(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the list of the removed objects:
|
||||
*
|
||||
* When an object is removed from the container, it is still kept in
|
||||
* {@link gdjs.RuntimeInstanceContainer#_instancesRemoved}.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
_cacheOrClearRemovedInstances() {
|
||||
for (let k = 0, lenk = this._instancesRemoved.length; k < lenk; ++k) {
|
||||
// Cache the instance to recycle it into a new instance later.
|
||||
// If the object does not support recycling, the cache won't be defined.
|
||||
const cache = this._instancesCache.get(
|
||||
this._instancesRemoved[k].getName()
|
||||
);
|
||||
if (cache) {
|
||||
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 _constructListOfAllInstances() {
|
||||
let currentListSize = 0;
|
||||
for (const name in this._instances.items) {
|
||||
if (this._instances.items.hasOwnProperty(name)) {
|
||||
const list = this._instances.items[name];
|
||||
const oldSize = currentListSize;
|
||||
currentListSize += list.length;
|
||||
for (let 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;
|
||||
this._allInstancesListIsUpToDate = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param objectName The name of the object
|
||||
* @returns the instances of a given object in the container.
|
||||
*/
|
||||
getInstancesOf(objectName: string): gdjs.RuntimeObject[] {
|
||||
return this._instances.items[objectName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all {@link gdjs.RuntimeObject} living in the container.
|
||||
* 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 The list of all runtime objects in the container
|
||||
*/
|
||||
getAdhocListOfAllInstances(): gdjs.RuntimeObject[] {
|
||||
if (!this._allInstancesListIsUpToDate) {
|
||||
this._constructListOfAllInstances();
|
||||
}
|
||||
return this._allInstancesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the objects before launching the events.
|
||||
*/
|
||||
_updateObjectsPreEvents() {
|
||||
// It is *mandatory* to create and iterate on a external list of all objects, as the behaviors
|
||||
// may delete the objects.
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const obj = allInstancesList[i];
|
||||
const elapsedTime = obj.getElapsedTime();
|
||||
if (!obj.hasNoForces()) {
|
||||
const averageForce = obj.getAverageForce();
|
||||
const 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);
|
||||
allInstancesList[i].stepBehaviorsPreEvents(this);
|
||||
}
|
||||
|
||||
// Some behaviors may have request objects to be deleted.
|
||||
this._cacheOrClearRemovedInstances();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the objects (update positions, time management...)
|
||||
*/
|
||||
_updateObjectsPostEvents() {
|
||||
this._cacheOrClearRemovedInstances();
|
||||
|
||||
// It is *mandatory* to create and iterate on a external list of all objects, as the behaviors
|
||||
// may delete the objects.
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
allInstancesList[i].stepBehaviorsPostEvents(this);
|
||||
}
|
||||
|
||||
// Some behaviors may have request objects to be deleted.
|
||||
this._cacheOrClearRemovedInstances();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object to the instances living in the container.
|
||||
* @param obj The object to be added.
|
||||
*/
|
||||
addObject(obj: gdjs.RuntimeObject) {
|
||||
if (!this._instances.containsKey(obj.name)) {
|
||||
this._instances.put(obj.name, []);
|
||||
}
|
||||
this._instances.get(obj.name).push(obj);
|
||||
this._allInstancesListIsUpToDate = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the instances of the object called name.
|
||||
* @param name Name of the object for which the instances must be returned.
|
||||
* @return The list of objects with the given name
|
||||
*/
|
||||
getObjects(name: string): gdjs.RuntimeObject[] | undefined {
|
||||
if (!this._instances.containsKey(name)) {
|
||||
logger.info(
|
||||
'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 in the container (No need to call {@link gdjs.RuntimeScene.addObject})
|
||||
* @param objectName The name of the object to be created
|
||||
* @return The created object
|
||||
*/
|
||||
createObject(objectName: string): gdjs.RuntimeObject | null {
|
||||
if (
|
||||
!this._objectsCtor.containsKey(objectName) ||
|
||||
!this._objects.containsKey(objectName)
|
||||
) {
|
||||
// There is no such object in this container.
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create a new object using the object constructor (cached during loading)
|
||||
// and the stored object's data:
|
||||
const cache = this._instancesCache.get(objectName);
|
||||
const ctor = this._objectsCtor.get(objectName);
|
||||
let obj;
|
||||
if (!cache || cache.length === 0) {
|
||||
obj = new ctor(this, this._objects.get(objectName));
|
||||
} else {
|
||||
// Reuse an objet destroyed before. If there is an object in the cache,
|
||||
// then it means it does support reinitialization.
|
||||
obj = cache.pop();
|
||||
obj.reinitialize(this._objects.get(objectName));
|
||||
}
|
||||
this.addObject(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called whenever an object must be removed from the container.
|
||||
* @param obj The object to be removed.
|
||||
*/
|
||||
markObjectForDeletion(obj: gdjs.RuntimeObject) {
|
||||
// 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())) {
|
||||
const objId = obj.id;
|
||||
const allInstances = this._instances.get(obj.getName());
|
||||
for (let i = 0, len = allInstances.length; i < len; ++i) {
|
||||
if (allInstances[i].id == objId) {
|
||||
allInstances.splice(i, 1);
|
||||
this._allInstancesListIsUpToDate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the object it was removed from the container
|
||||
obj.onDestroyFromScene(this);
|
||||
|
||||
// Notify the global callbacks
|
||||
for (let j = 0; j < gdjs.callbacksObjectDeletedFromScene.length; ++j) {
|
||||
gdjs.callbacksObjectDeletedFromScene[j](this, obj);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layer with the given name
|
||||
* @param name The name of the layer
|
||||
* @returns The layer, or the base layer if not found
|
||||
*/
|
||||
getLayer(name: string): gdjs.Layer {
|
||||
if (this._layers.containsKey(name)) {
|
||||
return this._layers.get(name);
|
||||
}
|
||||
return this._layers.get('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a layer exists
|
||||
* @param name The name of the layer
|
||||
*/
|
||||
hasLayer(name: string): boolean {
|
||||
return this._layers.containsKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a layer.
|
||||
* @param layerData The data to construct the layer
|
||||
*/
|
||||
addLayer(layerData: LayerData) {
|
||||
this._layers.put(layerData.name, new gdjs.Layer(layerData, this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a layer. All {@link gdjs.RuntimeObject} on this layer will
|
||||
* be moved back to the base layer.
|
||||
* @param layerName The name of the layer to remove
|
||||
*/
|
||||
removeLayer(layerName: string) {
|
||||
const allInstances = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0; i < allInstances.length; ++i) {
|
||||
const runtimeObject = allInstances[i];
|
||||
if (runtimeObject.getLayer() === layerName) {
|
||||
runtimeObject.setLayer('');
|
||||
}
|
||||
}
|
||||
this._layers.remove(layerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the position of a layer.
|
||||
*
|
||||
* @param layerName The name of the layer to reorder
|
||||
* @param index The new position in the list of layers
|
||||
*/
|
||||
setLayerIndex(layerName: string, index: integer): void {
|
||||
const layer: gdjs.Layer = this._layers.get(layerName);
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
this.getRenderer().setLayerIndex(layer, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the array passed as argument with the names of all layers
|
||||
* @param result The array where to put the layer names
|
||||
*/
|
||||
getAllLayerNames(result: string[]) {
|
||||
this._layers.keys(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of instances of the specified object living in the container.
|
||||
* @param objectName The object name for which instances must be counted.
|
||||
*/
|
||||
getInstancesCountOnScene(objectName: string): integer {
|
||||
const instances = this._instances.get(objectName);
|
||||
if (instances) {
|
||||
return instances.length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the objects positions according to their forces
|
||||
*/
|
||||
updateObjectsForces(): void {
|
||||
for (const name in this._instances.items) {
|
||||
if (this._instances.items.hasOwnProperty(name)) {
|
||||
const list = this._instances.items[name];
|
||||
for (let j = 0, listLen = list.length; j < listLen; ++j) {
|
||||
const obj = list[j];
|
||||
if (!obj.hasNoForces()) {
|
||||
const averageForce = obj.getAverageForce();
|
||||
const elapsedTimeInSeconds = obj.getElapsedTime() / 1000;
|
||||
obj.setX(obj.getX() + averageForce.getX() * elapsedTimeInSeconds);
|
||||
obj.setY(obj.getY() + averageForce.getY() * elapsedTimeInSeconds);
|
||||
obj.updateForces(elapsedTimeInSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any data structures to make sure memory is freed as soon as
|
||||
* possible.
|
||||
*/
|
||||
_destroy() {
|
||||
// It should not be necessary to reset these variables, but this help
|
||||
// ensuring that all memory related to the container is released immediately.
|
||||
this._layers = new Hashtable();
|
||||
this._objects = new Hashtable();
|
||||
this._instances = new Hashtable();
|
||||
this._instancesCache = new Hashtable();
|
||||
this._objectsCtor = new Hashtable();
|
||||
this._allInstancesList = [];
|
||||
this._instancesRemoved = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2013-2016 Florian Rival ([email protected]). All rights reserved.
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
namespace gdjs {
|
||||
/**
|
||||
* Represents a layer of a scene, used to display objects.
|
||||
*
|
||||
* Viewports and multiple cameras are not supported.
|
||||
*
|
||||
* It does some optimizations but works exactly the same as
|
||||
* {@link gdjs.Layer}.
|
||||
*/
|
||||
export class RuntimeSceneLayer extends gdjs.Layer {
|
||||
/**
|
||||
* @param layerData The data used to initialize the layer
|
||||
* @param scene The scene in which the layer is used
|
||||
*/
|
||||
constructor(layerData: LayerData, scene: gdjs.RuntimeScene) {
|
||||
super(layerData, scene);
|
||||
}
|
||||
|
||||
convertCoords(
|
||||
x: float,
|
||||
y: float,
|
||||
cameraId: integer = 0,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
// The result parameter used to be optional.
|
||||
let position = result || [0, 0];
|
||||
x -= this.getRuntimeScene()._cachedGameResolutionWidth / 2;
|
||||
y -= this.getRuntimeScene()._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).
|
||||
const angleInRadians = (this._cameraRotation / 180) * Math.PI;
|
||||
const tmp = x;
|
||||
const cosValue = Math.cos(angleInRadians);
|
||||
const sinValue = Math.sin(angleInRadians);
|
||||
x = cosValue * x - sinValue * y;
|
||||
y = sinValue * tmp + cosValue * y;
|
||||
position[0] = x + this.getCameraX(cameraId);
|
||||
position[1] = y + this.getCameraY(cameraId);
|
||||
return position;
|
||||
}
|
||||
|
||||
convertInverseCoords(
|
||||
x: float,
|
||||
y: float,
|
||||
cameraId: integer = 0,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
// The result parameter used to be optional.
|
||||
let position = result || [0, 0];
|
||||
x -= this.getCameraX(cameraId);
|
||||
y -= this.getCameraY(cameraId);
|
||||
|
||||
// Only compute angle and cos/sin once (allow heavy optimization from JS engines).
|
||||
const angleInRadians = (this._cameraRotation / 180) * Math.PI;
|
||||
const tmp = x;
|
||||
const cosValue = Math.cos(-angleInRadians);
|
||||
const sinValue = Math.sin(-angleInRadians);
|
||||
x = cosValue * x - sinValue * y;
|
||||
y = sinValue * tmp + cosValue * y;
|
||||
x *= Math.abs(this._zoomFactor);
|
||||
y *= Math.abs(this._zoomFactor);
|
||||
position[0] = x + this.getRuntimeScene()._cachedGameResolutionWidth / 2;
|
||||
position[1] = y + this.getRuntimeScene()._cachedGameResolutionHeight / 2;
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -639,7 +639,7 @@ namespace gdjs {
|
||||
newObjects.forEach((newObjectData) => {
|
||||
const objectName = newObjectData.name;
|
||||
const newBehaviors = newObjectData.behaviors;
|
||||
const runtimeObjects = runtimeScene.getObjects(objectName);
|
||||
const runtimeObjects = runtimeScene.getObjects(objectName)!;
|
||||
changedRuntimeBehaviors.forEach((changedRuntimeBehavior) => {
|
||||
const behaviorTypeName = changedRuntimeBehavior.behaviorTypeName;
|
||||
|
||||
@@ -784,7 +784,7 @@ namespace gdjs {
|
||||
runtimeScene.updateObject(newObjectData);
|
||||
|
||||
// Update existing instances
|
||||
const runtimeObjects = runtimeScene.getObjects(newObjectData.name);
|
||||
const runtimeObjects = runtimeScene.getObjects(newObjectData.name)!;
|
||||
|
||||
// Update instances state
|
||||
runtimeObjects.forEach((runtimeObject) => {
|
||||
|
||||
@@ -7,215 +7,217 @@ namespace gdjs {
|
||||
export namespace evtTools {
|
||||
export namespace camera {
|
||||
export const setCameraX = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
x: float,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
runtimeScene.getLayer(layer).setCameraX(x, cameraId);
|
||||
instanceContainer.getLayer(layer).setCameraX(x, cameraId);
|
||||
};
|
||||
|
||||
export const setCameraY = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
y: float,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
runtimeScene.getLayer(layer).setCameraY(y, cameraId);
|
||||
instanceContainer.getLayer(layer).setCameraY(y, cameraId);
|
||||
};
|
||||
|
||||
export const getCameraX = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraX();
|
||||
return instanceContainer.getLayer(layer).getCameraX();
|
||||
};
|
||||
|
||||
export const getCameraY = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraY();
|
||||
return instanceContainer.getLayer(layer).getCameraY();
|
||||
};
|
||||
|
||||
export const getCameraWidth = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraWidth();
|
||||
return instanceContainer.getLayer(layer).getCameraWidth();
|
||||
};
|
||||
|
||||
export const getCameraHeight = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraHeight();
|
||||
return instanceContainer.getLayer(layer).getCameraHeight();
|
||||
};
|
||||
|
||||
export const getCameraBorderLeft = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return (
|
||||
getCameraX(runtimeScene, layer, cameraId) -
|
||||
getCameraWidth(runtimeScene, layer, cameraId) / 2
|
||||
getCameraX(instanceContainer, layer, cameraId) -
|
||||
getCameraWidth(instanceContainer, layer, cameraId) / 2
|
||||
);
|
||||
};
|
||||
|
||||
export const getCameraBorderRight = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return (
|
||||
getCameraX(runtimeScene, layer, cameraId) +
|
||||
getCameraWidth(runtimeScene, layer, cameraId) / 2
|
||||
getCameraX(instanceContainer, layer, cameraId) +
|
||||
getCameraWidth(instanceContainer, layer, cameraId) / 2
|
||||
);
|
||||
};
|
||||
|
||||
export const getCameraBorderTop = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return (
|
||||
getCameraY(runtimeScene, layer, cameraId) -
|
||||
getCameraHeight(runtimeScene, layer, cameraId) / 2
|
||||
getCameraY(instanceContainer, layer, cameraId) -
|
||||
getCameraHeight(instanceContainer, layer, cameraId) / 2
|
||||
);
|
||||
};
|
||||
|
||||
export const getCameraBorderBottom = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return (
|
||||
getCameraY(runtimeScene, layer, cameraId) +
|
||||
getCameraHeight(runtimeScene, layer, cameraId) / 2
|
||||
getCameraY(instanceContainer, layer, cameraId) +
|
||||
getCameraHeight(instanceContainer, layer, cameraId) / 2
|
||||
);
|
||||
};
|
||||
|
||||
export const showLayer = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).show(true);
|
||||
return instanceContainer.getLayer(layer).show(true);
|
||||
};
|
||||
|
||||
export const hideLayer = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).show(false);
|
||||
return instanceContainer.getLayer(layer).show(false);
|
||||
};
|
||||
|
||||
export const layerIsVisible = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string
|
||||
): boolean {
|
||||
return (
|
||||
runtimeScene.hasLayer(layer) &&
|
||||
runtimeScene.getLayer(layer).isVisible()
|
||||
instanceContainer.hasLayer(layer) &&
|
||||
instanceContainer.getLayer(layer).isVisible()
|
||||
);
|
||||
};
|
||||
|
||||
export const setCameraRotation = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
rotation: float,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.setCameraRotation(rotation, cameraId);
|
||||
};
|
||||
|
||||
export const getCameraRotation = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraRotation(cameraId);
|
||||
return instanceContainer.getLayer(layer).getCameraRotation(cameraId);
|
||||
};
|
||||
|
||||
export const getCameraZoom = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getCameraZoom(cameraId);
|
||||
return instanceContainer.getLayer(layer).getCameraZoom(cameraId);
|
||||
};
|
||||
|
||||
export const setCameraZoom = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
newZoom: float,
|
||||
layer: string,
|
||||
cameraId: integer
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).setCameraZoom(newZoom, cameraId);
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.setCameraZoom(newZoom, cameraId);
|
||||
};
|
||||
|
||||
export const centerCamera = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
object: gdjs.RuntimeObject | null,
|
||||
anticipateMove: boolean,
|
||||
layerName: string,
|
||||
cameraId: integer
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layerName) || object == null) {
|
||||
if (!instanceContainer.hasLayer(layerName) || object == null) {
|
||||
return;
|
||||
}
|
||||
let xOffset = 0;
|
||||
@@ -223,11 +225,11 @@ namespace gdjs {
|
||||
if (anticipateMove && !object.hasNoForces()) {
|
||||
const objectAverageForce = object.getAverageForce();
|
||||
const elapsedTimeInSeconds =
|
||||
object.getElapsedTime(runtimeScene) / 1000;
|
||||
object.getElapsedTime(instanceContainer) / 1000;
|
||||
xOffset = objectAverageForce.getX() * elapsedTimeInSeconds;
|
||||
yOffset = objectAverageForce.getY() * elapsedTimeInSeconds;
|
||||
}
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layer = instanceContainer.getLayer(layerName);
|
||||
layer.setCameraX(object.getCenterXInScene() + xOffset, cameraId);
|
||||
layer.setCameraY(object.getCenterYInScene() + yOffset, cameraId);
|
||||
};
|
||||
@@ -236,7 +238,7 @@ namespace gdjs {
|
||||
* @deprecated prefer using centerCamera and clampCamera.
|
||||
*/
|
||||
export const centerCameraWithinLimits = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
object: gdjs.RuntimeObject | null,
|
||||
left: number,
|
||||
top: number,
|
||||
@@ -246,9 +248,15 @@ namespace gdjs {
|
||||
layerName: string,
|
||||
cameraId: integer
|
||||
) {
|
||||
centerCamera(runtimeScene, object, anticipateMove, layerName, cameraId);
|
||||
centerCamera(
|
||||
instanceContainer,
|
||||
object,
|
||||
anticipateMove,
|
||||
layerName,
|
||||
cameraId
|
||||
);
|
||||
clampCamera(
|
||||
runtimeScene,
|
||||
instanceContainer,
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
@@ -259,7 +267,7 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const clampCamera = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
left: float,
|
||||
top: float,
|
||||
right: float,
|
||||
@@ -267,10 +275,10 @@ namespace gdjs {
|
||||
layerName: string,
|
||||
cameraId: integer
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layerName)) {
|
||||
if (!instanceContainer.hasLayer(layerName)) {
|
||||
return;
|
||||
}
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layer = instanceContainer.getLayer(layerName);
|
||||
const cameraHalfWidth = layer.getCameraWidth(cameraId) / 2;
|
||||
const cameraHalfHeight = layer.getCameraHeight(cameraId) / 2;
|
||||
|
||||
@@ -304,164 +312,167 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Update a layer effect parameter (with a number).
|
||||
* @param runtimeScene The scene
|
||||
* @param instanceContainer the container owning the layer
|
||||
* @param layer The name of the layer
|
||||
* @param effect The name of the effect
|
||||
* @param parameter The parameter to update
|
||||
* @param value The new value
|
||||
*/
|
||||
export const setLayerEffectDoubleParameter = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
effect: string,
|
||||
parameter: string,
|
||||
value: float
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.setEffectDoubleParameter(effect, parameter, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a layer effect parameter (with a string).
|
||||
* @param runtimeScene The scene
|
||||
* @param instanceContainer the container owning the layer
|
||||
* @param layer The name of the layer
|
||||
* @param effect The name of the effect
|
||||
* @param parameter The parameter to update
|
||||
* @param value The new value
|
||||
*/
|
||||
export const setLayerEffectStringParameter = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
effect: string,
|
||||
parameter: string,
|
||||
value: string
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.setEffectStringParameter(effect, parameter, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable or disable a layer effect parameter (boolean).
|
||||
* @param runtimeScene The scene
|
||||
* @param instanceContainer the container owning the layer
|
||||
* @param layer The name of the layer
|
||||
* @param effect The name of the effect
|
||||
* @param parameter The parameter to update
|
||||
* @param value The new value
|
||||
*/
|
||||
export const setLayerEffectBooleanParameter = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
effect: string,
|
||||
parameter: string,
|
||||
value: boolean
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.setEffectBooleanParameter(effect, parameter, value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable, or disable, an effect of a layer.
|
||||
* @param runtimeScene The scene
|
||||
* @param instanceContainer the container owning the layer
|
||||
* @param layer The name of the layer
|
||||
* @param effect The name of the effect
|
||||
* @param enabled true to enable, false to disable.
|
||||
*/
|
||||
export const enableLayerEffect = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
effect: string,
|
||||
enabled: boolean
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
runtimeScene.getLayer(layer).enableEffect(effect, enabled);
|
||||
instanceContainer.getLayer(layer).enableEffect(effect, enabled);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if an effect is enabled.
|
||||
* @param runtimeScene The scene
|
||||
* @param instanceContainer the container owning the layer
|
||||
* @param layer The name of the layer
|
||||
* @param effect The name of the effect
|
||||
* @return true if the effect is enabled, false otherwise.
|
||||
*/
|
||||
export const layerEffectEnabled = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
effect: string
|
||||
): boolean {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return true;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).isEffectEnabled(effect);
|
||||
return instanceContainer.getLayer(layer).isEffectEnabled(effect);
|
||||
};
|
||||
|
||||
export const setLayerTimeScale = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
timeScale: float
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).setTimeScale(timeScale);
|
||||
return instanceContainer.getLayer(layer).setTimeScale(timeScale);
|
||||
};
|
||||
|
||||
export const getLayerTimeScale = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 1;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getTimeScale();
|
||||
return instanceContainer.getLayer(layer).getTimeScale();
|
||||
};
|
||||
|
||||
export const setLayerDefaultZOrder = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
defaultZOrder: integer
|
||||
) {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).setDefaultZOrder(defaultZOrder);
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.setDefaultZOrder(defaultZOrder);
|
||||
};
|
||||
|
||||
export const getLayerDefaultZOrder = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string
|
||||
): number {
|
||||
if (!runtimeScene.hasLayer(layer)) {
|
||||
if (!instanceContainer.hasLayer(layer)) {
|
||||
return 0;
|
||||
}
|
||||
return runtimeScene.getLayer(layer).getDefaultZOrder();
|
||||
return instanceContainer.getLayer(layer).getDefaultZOrder();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param instanceContainer the container owning the layer
|
||||
* @param layerName The lighting layer with the ambient color.
|
||||
* @param rgbColor The color, in RGB format ("128;200;255").
|
||||
*/
|
||||
export const setLayerAmbientLightColor = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layerName: string,
|
||||
rgbColor: string
|
||||
) {
|
||||
if (
|
||||
!runtimeScene.hasLayer(layerName) ||
|
||||
!runtimeScene.getLayer(layerName).isLightingLayer()
|
||||
!instanceContainer.hasLayer(layerName) ||
|
||||
!instanceContainer.getLayer(layerName).isLightingLayer()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -469,7 +480,7 @@ namespace gdjs {
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
}
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getLayer(layerName)
|
||||
.setClearColor(
|
||||
parseInt(colors[0], 10),
|
||||
|
||||
@@ -144,9 +144,12 @@ namespace gdjs {
|
||||
* Return true if the specified key is pressed
|
||||
*
|
||||
*/
|
||||
export const isKeyPressed = function (runtimeScene, key) {
|
||||
export const isKeyPressed = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
key: string
|
||||
) {
|
||||
if (gdjs.evtTools.input.keysNameToCode.hasOwnProperty(key)) {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isKeyPressed(gdjs.evtTools.input.keysNameToCode[key]);
|
||||
@@ -158,9 +161,12 @@ namespace gdjs {
|
||||
* Return true if the specified key was just released
|
||||
*
|
||||
*/
|
||||
export const wasKeyReleased = function (runtimeScene, key) {
|
||||
export const wasKeyReleased = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
key: string
|
||||
) {
|
||||
if (gdjs.evtTools.input.keysNameToCode.hasOwnProperty(key)) {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.wasKeyReleased(gdjs.evtTools.input.keysNameToCode[key]);
|
||||
@@ -171,8 +177,10 @@ namespace gdjs {
|
||||
/**
|
||||
* Return the name of the last key pressed in the game
|
||||
*/
|
||||
export const lastPressedKey = function (runtimeScene) {
|
||||
const keyCode = runtimeScene
|
||||
export const lastPressedKey = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
const keyCode = instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.getLastPressedKey();
|
||||
@@ -182,29 +190,36 @@ namespace gdjs {
|
||||
return '';
|
||||
};
|
||||
|
||||
export const anyKeyPressed = function (runtimeScene) {
|
||||
return runtimeScene.getGame().getInputManager().anyKeyPressed();
|
||||
export const anyKeyPressed = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
return instanceContainer.getGame().getInputManager().anyKeyPressed();
|
||||
};
|
||||
|
||||
export const anyKeyReleased = function (runtimeScene) {
|
||||
return runtimeScene.getGame().getInputManager().anyKeyReleased();
|
||||
export const anyKeyReleased = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
return instanceContainer.getGame().getInputManager().anyKeyReleased();
|
||||
};
|
||||
|
||||
export const isMouseButtonPressed = function (runtimeScene, button) {
|
||||
export const isMouseButtonPressed = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
button: string
|
||||
) {
|
||||
if (button === 'Left') {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonPressed(0);
|
||||
}
|
||||
if (button === 'Right') {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonPressed(1);
|
||||
}
|
||||
if (button === 'Middle') {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonPressed(2);
|
||||
@@ -212,21 +227,24 @@ namespace gdjs {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const isMouseButtonReleased = function (runtimeScene, button) {
|
||||
export const isMouseButtonReleased = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
button: string
|
||||
) {
|
||||
if (button === 'Left') {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonReleased(0);
|
||||
}
|
||||
if (button === 'Right') {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonReleased(1);
|
||||
}
|
||||
if (button === 'Middle') {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonReleased(2);
|
||||
@@ -234,129 +252,178 @@ namespace gdjs {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const hideCursor = function (runtimeScene) {
|
||||
runtimeScene.getRenderer().hideCursor();
|
||||
export const hideCursor = function (
|
||||
instanceContainer: gdjs.RuntimeScene
|
||||
) {
|
||||
instanceContainer.getScene().getRenderer().hideCursor();
|
||||
};
|
||||
|
||||
export const showCursor = function (runtimeScene) {
|
||||
runtimeScene.getRenderer().showCursor();
|
||||
export const showCursor = function (
|
||||
instanceContainer: gdjs.RuntimeScene
|
||||
) {
|
||||
instanceContainer.getScene().getRenderer().showCursor();
|
||||
};
|
||||
|
||||
export const getMouseWheelDelta = function (runtimeScene) {
|
||||
return runtimeScene.getGame().getInputManager().getMouseWheelDelta();
|
||||
export const getMouseWheelDelta = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.getMouseWheelDelta();
|
||||
};
|
||||
|
||||
export const isScrollingUp = function (runtimeScene) {
|
||||
return runtimeScene.getGame().getInputManager().isScrollingUp();
|
||||
export const isScrollingUp = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
return instanceContainer.getGame().getInputManager().isScrollingUp();
|
||||
};
|
||||
|
||||
export const isScrollingDown = function (runtimeScene) {
|
||||
return runtimeScene.getGame().getInputManager().isScrollingDown();
|
||||
export const isScrollingDown = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
return instanceContainer.getGame().getInputManager().isScrollingDown();
|
||||
};
|
||||
|
||||
export const getMouseX = function (runtimeScene, layer, camera) {
|
||||
return runtimeScene
|
||||
export const getMouseX = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
camera: integer
|
||||
) {
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
gdjs.evtTools.input.getMouseX
|
||||
) as FloatPoint;
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.convertCoords(
|
||||
runtimeScene.getGame().getInputManager().getMouseX(),
|
||||
runtimeScene.getGame().getInputManager().getMouseY()
|
||||
instanceContainer.getGame().getInputManager().getMouseX(),
|
||||
instanceContainer.getGame().getInputManager().getMouseY(),
|
||||
0,
|
||||
workingPoint
|
||||
)[0];
|
||||
};
|
||||
|
||||
export const getMouseY = function (runtimeScene, layer, camera) {
|
||||
return runtimeScene
|
||||
export const getMouseY = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: string,
|
||||
camera: integer
|
||||
) {
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
gdjs.evtTools.input.getMouseY
|
||||
) as FloatPoint;
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.convertCoords(
|
||||
runtimeScene.getGame().getInputManager().getMouseX(),
|
||||
runtimeScene.getGame().getInputManager().getMouseY()
|
||||
instanceContainer.getGame().getInputManager().getMouseX(),
|
||||
instanceContainer.getGame().getInputManager().getMouseY(),
|
||||
0,
|
||||
workingPoint
|
||||
)[1];
|
||||
};
|
||||
|
||||
export const isMouseInsideCanvas = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
return runtimeScene.getGame().getInputManager().isMouseInsideCanvas();
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseInsideCanvas();
|
||||
};
|
||||
|
||||
export const _cursorIsOnObject = function (obj, runtimeScene) {
|
||||
return obj.cursorOnObject(runtimeScene);
|
||||
export const _cursorIsOnObject = function (
|
||||
obj: gdjs.RuntimeObject,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
return obj.cursorOnObject(instanceContainer);
|
||||
};
|
||||
|
||||
export const cursorOnObject = function (
|
||||
objectsLists,
|
||||
runtimeScene,
|
||||
accurate,
|
||||
inverted
|
||||
objectsLists: Hashtable<gdjs.RuntimeObject[]>,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
accurate: boolean,
|
||||
inverted: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.pickObjectsIf(
|
||||
gdjs.evtTools.input._cursorIsOnObject,
|
||||
objectsLists,
|
||||
inverted,
|
||||
runtimeScene
|
||||
instanceContainer
|
||||
);
|
||||
};
|
||||
|
||||
export const getTouchX = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
identifier: integer,
|
||||
layer: string,
|
||||
camera: integer
|
||||
) {
|
||||
return runtimeScene
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
gdjs.evtTools.input.getTouchX
|
||||
) as FloatPoint;
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.convertCoords(
|
||||
runtimeScene.getGame().getInputManager().getTouchX(identifier),
|
||||
runtimeScene.getGame().getInputManager().getTouchY(identifier)
|
||||
instanceContainer.getGame().getInputManager().getTouchX(identifier),
|
||||
instanceContainer.getGame().getInputManager().getTouchY(identifier),
|
||||
0,
|
||||
workingPoint
|
||||
)[0];
|
||||
};
|
||||
|
||||
export const getTouchY = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
identifier: integer,
|
||||
layer: string,
|
||||
camera: integer
|
||||
) => {
|
||||
return runtimeScene
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
gdjs.evtTools.input.getTouchY
|
||||
) as FloatPoint;
|
||||
return instanceContainer
|
||||
.getLayer(layer)
|
||||
.convertCoords(
|
||||
runtimeScene.getGame().getInputManager().getTouchX(identifier),
|
||||
runtimeScene.getGame().getInputManager().getTouchY(identifier)
|
||||
instanceContainer.getGame().getInputManager().getTouchX(identifier),
|
||||
instanceContainer.getGame().getInputManager().getTouchY(identifier),
|
||||
0,
|
||||
workingPoint
|
||||
)[1];
|
||||
};
|
||||
|
||||
export const hasAnyTouchStarted = (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): boolean => {
|
||||
return (
|
||||
runtimeScene.getGame().getInputManager().getStartedTouchIdentifiers()
|
||||
.length > 0
|
||||
instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.getStartedTouchIdentifiers().length > 0
|
||||
);
|
||||
};
|
||||
|
||||
export const getStartedTouchCount = (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): integer => {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.getStartedTouchIdentifiers().length;
|
||||
};
|
||||
|
||||
export const getStartedTouchIdentifier = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
index: integer
|
||||
): integer => {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.getStartedTouchIdentifiers()[index];
|
||||
};
|
||||
|
||||
export const hasTouchEnded = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
identifier: integer
|
||||
): boolean => {
|
||||
return runtimeScene
|
||||
return instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.hasTouchEnded(identifier);
|
||||
@@ -380,9 +447,9 @@ namespace gdjs {
|
||||
* @deprecated
|
||||
*/
|
||||
export const popStartedTouch = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
const startedTouchId = runtimeScene
|
||||
const startedTouchId = instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.popStartedTouch();
|
||||
@@ -396,8 +463,10 @@ namespace gdjs {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export const popEndedTouch = function (runtimeScene: gdjs.RuntimeScene) {
|
||||
const endedTouchId = runtimeScene
|
||||
export const popEndedTouch = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
const endedTouchId = instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.popEndedTouch();
|
||||
@@ -408,8 +477,14 @@ namespace gdjs {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const touchSimulateMouse = function (runtimeScene, enable) {
|
||||
runtimeScene.getGame().getInputManager().touchSimulateMouse(enable);
|
||||
export const touchSimulateMouse = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
enable: boolean
|
||||
) {
|
||||
instanceContainer
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.touchSimulateMouse(enable);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,10 +147,10 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const enableMetrics = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
enable: boolean
|
||||
) {
|
||||
runtimeScene.getGame().enableMetrics(enable);
|
||||
instanceContainer.getGame().enableMetrics(enable);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace gdjs {
|
||||
* @param runtimeObject The object to keep in the lists
|
||||
*/
|
||||
export const pickOnly = function (
|
||||
objectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists: ObjectsLists,
|
||||
runtimeObject: gdjs.RuntimeObject
|
||||
) {
|
||||
for (const listName in objectsLists.items) {
|
||||
@@ -36,7 +36,7 @@ namespace gdjs {
|
||||
/**
|
||||
* 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
|
||||
* Note that the predicate method is not called strictly 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):
|
||||
@@ -63,8 +63,8 @@ namespace gdjs {
|
||||
object2: gdjs.RuntimeObject,
|
||||
extraArg: any
|
||||
) => boolean,
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists1: ObjectsLists,
|
||||
objectsLists2: ObjectsLists,
|
||||
inverted: boolean,
|
||||
extraArg: any
|
||||
) {
|
||||
@@ -170,7 +170,7 @@ namespace gdjs {
|
||||
*/
|
||||
export const pickObjectsIf = function (
|
||||
predicate: Function,
|
||||
objectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists: ObjectsLists,
|
||||
negatePredicate: boolean,
|
||||
extraArg: any
|
||||
): boolean {
|
||||
@@ -219,10 +219,10 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const hitBoxesCollisionTest = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists1: ObjectsLists,
|
||||
objectsLists2: ObjectsLists,
|
||||
inverted: boolean,
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
ignoreTouchingEdges: boolean
|
||||
) {
|
||||
return gdjs.evtTools.object.twoListsTest(
|
||||
@@ -239,8 +239,8 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const distanceTest = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists1: ObjectsLists,
|
||||
objectsLists2: ObjectsLists,
|
||||
distance: float,
|
||||
inverted: boolean
|
||||
) {
|
||||
@@ -278,8 +278,8 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const movesTowardTest = function (
|
||||
objectsLists1: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists2: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists1: ObjectsLists,
|
||||
objectsLists2: ObjectsLists,
|
||||
tolerance: float,
|
||||
inverted: boolean
|
||||
) {
|
||||
@@ -337,7 +337,10 @@ namespace gdjs {
|
||||
return true;
|
||||
};
|
||||
|
||||
export const pickRandomObject = function (runtimeScene, objectsLists) {
|
||||
export const pickRandomObject = function (
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectsLists: ObjectsLists
|
||||
) {
|
||||
// Compute one many objects we have
|
||||
let objectsCount = 0;
|
||||
for (let listName in objectsLists.items) {
|
||||
@@ -403,7 +406,7 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const raycastObject = function (
|
||||
objectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists: ObjectsLists,
|
||||
x: float,
|
||||
y: float,
|
||||
angle: float,
|
||||
@@ -425,7 +428,7 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
export const raycastObjectToPosition = function (
|
||||
objectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
objectsLists: ObjectsLists,
|
||||
x: float,
|
||||
y: float,
|
||||
endX: float,
|
||||
@@ -481,9 +484,9 @@ namespace gdjs {
|
||||
export const doCreateObjectOnScene = function (
|
||||
objectsContext: EventsFunctionContext | gdjs.RuntimeScene,
|
||||
objectName: string,
|
||||
objectsLists: Hashtable<Array<gdjs.RuntimeObject>>,
|
||||
x,
|
||||
y,
|
||||
objectsLists: ObjectsLists,
|
||||
x: float,
|
||||
y: float,
|
||||
layerName: string
|
||||
) {
|
||||
// objectsContext will either be the gdjs.RuntimeScene or, in an events function, the
|
||||
@@ -509,19 +512,19 @@ namespace gdjs {
|
||||
* Allows events to create a new object on a scene.
|
||||
*/
|
||||
export const createObjectOnScene = function (
|
||||
objectsContext,
|
||||
objectsLists,
|
||||
x,
|
||||
y,
|
||||
layer
|
||||
objectsContext: EventsFunctionContext | gdjs.RuntimeScene,
|
||||
objectsLists: ObjectsLists,
|
||||
x: float,
|
||||
y: float,
|
||||
layerName: string
|
||||
) {
|
||||
gdjs.evtTools.object.doCreateObjectOnScene(
|
||||
objectsContext,
|
||||
objectsLists.firstKey(),
|
||||
objectsLists.firstKey() as string,
|
||||
objectsLists,
|
||||
x,
|
||||
y,
|
||||
layer
|
||||
layerName
|
||||
);
|
||||
};
|
||||
|
||||
@@ -529,12 +532,12 @@ namespace gdjs {
|
||||
* Allows events to create a new object on a scene.
|
||||
*/
|
||||
export const createObjectFromGroupOnScene = function (
|
||||
objectsContext,
|
||||
objectsLists,
|
||||
objectName,
|
||||
x,
|
||||
y,
|
||||
layer
|
||||
objectsContext: EventsFunctionContext | gdjs.RuntimeScene,
|
||||
objectsLists: ObjectsLists,
|
||||
objectName: string,
|
||||
x: float,
|
||||
y: float,
|
||||
layerName: string
|
||||
) {
|
||||
gdjs.evtTools.object.doCreateObjectOnScene(
|
||||
objectsContext,
|
||||
@@ -542,7 +545,7 @@ namespace gdjs {
|
||||
objectsLists,
|
||||
x,
|
||||
y,
|
||||
layer
|
||||
layerName
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -6,40 +6,54 @@
|
||||
namespace gdjs {
|
||||
export namespace evtTools {
|
||||
export namespace runtimeScene {
|
||||
export const sceneJustBegins = function (runtimeScene) {
|
||||
return runtimeScene.getTimeManager().isFirstFrame();
|
||||
export const sceneJustBegins = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
return runtimeScene.getScene().getTimeManager().isFirstFrame();
|
||||
};
|
||||
|
||||
export const sceneJustResumed = function (runtimeScene) {
|
||||
return runtimeScene.sceneJustResumed();
|
||||
export const sceneJustResumed = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
return runtimeScene.getScene().sceneJustResumed();
|
||||
};
|
||||
|
||||
export const getSceneName = function (runtimeScene) {
|
||||
return runtimeScene.getName();
|
||||
export const getSceneName = function (runtimeScene: gdjs.RuntimeScene) {
|
||||
return runtimeScene.getScene().getName();
|
||||
};
|
||||
|
||||
export const setBackgroundColor = function (runtimeScene, rgbColor) {
|
||||
export const setBackgroundColor = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
rgbColor: string
|
||||
) {
|
||||
const colors = rgbColor.split(';');
|
||||
if (colors.length < 3) {
|
||||
return;
|
||||
}
|
||||
runtimeScene.setBackgroundColor(
|
||||
parseInt(colors[0]),
|
||||
parseInt(colors[1]),
|
||||
parseInt(colors[2])
|
||||
);
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.setBackgroundColor(
|
||||
parseInt(colors[0]),
|
||||
parseInt(colors[1]),
|
||||
parseInt(colors[2])
|
||||
);
|
||||
};
|
||||
|
||||
export const getElapsedTimeInSeconds = function (runtimeScene) {
|
||||
return runtimeScene.getTimeManager().getElapsedTime() / 1000;
|
||||
export const getElapsedTimeInSeconds = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
return runtimeScene.getScene().getTimeManager().getElapsedTime() / 1000;
|
||||
};
|
||||
|
||||
export const setTimeScale = function (runtimeScene, timeScale) {
|
||||
return runtimeScene.getTimeManager().setTimeScale(timeScale);
|
||||
export const setTimeScale = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
timeScale: float
|
||||
) {
|
||||
return runtimeScene.getScene().getTimeManager().setTimeScale(timeScale);
|
||||
};
|
||||
|
||||
export const getTimeScale = function (runtimeScene) {
|
||||
return runtimeScene.getTimeManager().getTimeScale();
|
||||
export const getTimeScale = function (runtimeScene: gdjs.RuntimeScene) {
|
||||
return runtimeScene.getScene().getTimeManager().getTimeScale();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -57,7 +71,7 @@ namespace gdjs {
|
||||
timeInSeconds: float,
|
||||
timerName: string
|
||||
) {
|
||||
const timeManager = runtimeScene.getTimeManager();
|
||||
const timeManager = runtimeScene.getScene().getTimeManager();
|
||||
if (!timeManager.hasTimer(timerName)) {
|
||||
timeManager.addTimer(timerName);
|
||||
return false;
|
||||
@@ -67,16 +81,22 @@ namespace gdjs {
|
||||
);
|
||||
};
|
||||
|
||||
export const timerPaused = function (runtimeScene, timerName) {
|
||||
const timeManager = runtimeScene.getTimeManager();
|
||||
export const timerPaused = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
timerName: string
|
||||
) {
|
||||
const timeManager = runtimeScene.getScene().getTimeManager();
|
||||
if (!timeManager.hasTimer(timerName)) {
|
||||
return false;
|
||||
}
|
||||
return timeManager.getTimer(timerName).isPaused();
|
||||
};
|
||||
|
||||
export const resetTimer = function (runtimeScene, timerName) {
|
||||
const timeManager = runtimeScene.getTimeManager();
|
||||
export const resetTimer = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
timerName: string
|
||||
) {
|
||||
const timeManager = runtimeScene.getScene().getTimeManager();
|
||||
if (!timeManager.hasTimer(timerName)) {
|
||||
timeManager.addTimer(timerName);
|
||||
} else {
|
||||
@@ -84,24 +104,33 @@ namespace gdjs {
|
||||
}
|
||||
};
|
||||
|
||||
export const pauseTimer = function (runtimeScene, timerName) {
|
||||
const timeManager = runtimeScene.getTimeManager();
|
||||
export const pauseTimer = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
timerName: string
|
||||
) {
|
||||
const timeManager = runtimeScene.getScene().getTimeManager();
|
||||
if (!timeManager.hasTimer(timerName)) {
|
||||
timeManager.addTimer(timerName);
|
||||
}
|
||||
timeManager.getTimer(timerName).setPaused(true);
|
||||
};
|
||||
|
||||
export const unpauseTimer = function (runtimeScene, timerName) {
|
||||
const timeManager = runtimeScene.getTimeManager();
|
||||
export const unpauseTimer = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
timerName: string
|
||||
) {
|
||||
const timeManager = runtimeScene.getScene().getTimeManager();
|
||||
if (!timeManager.hasTimer(timerName)) {
|
||||
timeManager.addTimer(timerName);
|
||||
}
|
||||
return timeManager.getTimer(timerName).setPaused(false);
|
||||
};
|
||||
|
||||
export const removeTimer = function (runtimeScene, timerName) {
|
||||
const timeManager = runtimeScene.getTimeManager();
|
||||
export const removeTimer = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
timerName: string
|
||||
) {
|
||||
const timeManager = runtimeScene.getScene().getTimeManager();
|
||||
timeManager.removeTimer(timerName);
|
||||
};
|
||||
|
||||
@@ -116,6 +145,7 @@ namespace gdjs {
|
||||
|
||||
update(runtimeScene: RuntimeScene): boolean {
|
||||
this.timeElapsedOnScene += runtimeScene
|
||||
.getScene()
|
||||
.getTimeManager()
|
||||
.getElapsedTime();
|
||||
return this.timeElapsedOnScene >= this.duration;
|
||||
@@ -139,7 +169,7 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
timerName: string
|
||||
) {
|
||||
const timeManager = runtimeScene.getTimeManager();
|
||||
const timeManager = runtimeScene.getScene().getTimeManager();
|
||||
if (!timeManager.hasTimer(timerName)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -158,7 +188,7 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
timerName: string
|
||||
) {
|
||||
const timeManager = runtimeScene.getTimeManager();
|
||||
const timeManager = runtimeScene.getScene().getTimeManager();
|
||||
if (!timeManager.hasTimer(timerName)) {
|
||||
return Number.NaN;
|
||||
}
|
||||
@@ -168,7 +198,9 @@ namespace gdjs {
|
||||
export const getTimeFromStartInSeconds = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
) {
|
||||
return runtimeScene.getTimeManager().getTimeFromStart() / 1000;
|
||||
return (
|
||||
runtimeScene.getScene().getTimeManager().getTimeFromStart() / 1000
|
||||
);
|
||||
};
|
||||
|
||||
export const getTime = function (
|
||||
@@ -211,34 +243,42 @@ namespace gdjs {
|
||||
if (!runtimeScene.getGame().getSceneData(newSceneName)) {
|
||||
return;
|
||||
}
|
||||
runtimeScene.requestChange(
|
||||
clearOthers
|
||||
? gdjs.SceneChangeRequest.CLEAR_SCENES
|
||||
: gdjs.SceneChangeRequest.REPLACE_SCENE,
|
||||
newSceneName
|
||||
);
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.requestChange(
|
||||
clearOthers
|
||||
? gdjs.SceneChangeRequest.CLEAR_SCENES
|
||||
: gdjs.SceneChangeRequest.REPLACE_SCENE,
|
||||
newSceneName
|
||||
);
|
||||
};
|
||||
|
||||
export const pushScene = function (runtimeScene, newSceneName) {
|
||||
export const pushScene = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
newSceneName: string
|
||||
) {
|
||||
if (!runtimeScene.getGame().getSceneData(newSceneName)) {
|
||||
return;
|
||||
}
|
||||
runtimeScene.requestChange(
|
||||
gdjs.SceneChangeRequest.PUSH_SCENE,
|
||||
newSceneName
|
||||
);
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.requestChange(gdjs.SceneChangeRequest.PUSH_SCENE, newSceneName);
|
||||
};
|
||||
|
||||
export const popScene = function (runtimeScene) {
|
||||
runtimeScene.requestChange(gdjs.SceneChangeRequest.POP_SCENE);
|
||||
export const popScene = function (runtimeScene: gdjs.RuntimeScene) {
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.requestChange(gdjs.SceneChangeRequest.POP_SCENE);
|
||||
};
|
||||
|
||||
export const stopGame = function (runtimeScene) {
|
||||
runtimeScene.requestChange(gdjs.SceneChangeRequest.STOP_GAME);
|
||||
export const stopGame = function (runtimeScene: gdjs.RuntimeScene) {
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.requestChange(gdjs.SceneChangeRequest.STOP_GAME);
|
||||
};
|
||||
|
||||
export const createObjectsFromExternalLayout = function (
|
||||
scene: gdjs.RuntimeScene,
|
||||
scene: gdjs.RuntimeInstanceContainer,
|
||||
externalLayout: string,
|
||||
xPos: float,
|
||||
yPos: float
|
||||
@@ -252,7 +292,7 @@ namespace gdjs {
|
||||
|
||||
// trackByPersistentUuid is set to false as we don't want external layouts
|
||||
// instantiated at runtime to be hot-reloaded.
|
||||
scene.createObjectsFrom(
|
||||
scene.getScene().createObjectsFrom(
|
||||
externalLayoutData.instances,
|
||||
xPos,
|
||||
yPos,
|
||||
|
||||
@@ -11,20 +11,20 @@ namespace gdjs {
|
||||
export const getGlobalVolume = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): float {
|
||||
return runtimeScene.getSoundManager().getGlobalVolume();
|
||||
return runtimeScene.getScene().getSoundManager().getGlobalVolume();
|
||||
};
|
||||
|
||||
export const setGlobalVolume = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
globalVolume: float
|
||||
): void {
|
||||
runtimeScene.getSoundManager().setGlobalVolume(globalVolume);
|
||||
runtimeScene.getScene().getSoundManager().setGlobalVolume(globalVolume);
|
||||
};
|
||||
|
||||
export const unloadAllAudio = function (
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
): void {
|
||||
runtimeScene.getSoundManager().unloadAll();
|
||||
runtimeScene.getScene().getSoundManager().unloadAll();
|
||||
};
|
||||
|
||||
// Sounds:
|
||||
@@ -36,6 +36,7 @@ namespace gdjs {
|
||||
pitch: float
|
||||
): void {
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.playSound(soundFile, loop, volume, pitch);
|
||||
};
|
||||
@@ -49,6 +50,7 @@ namespace gdjs {
|
||||
pitch: float
|
||||
): void {
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.playSoundOnChannel(soundFile, channel, loop, volume, pitch);
|
||||
};
|
||||
@@ -57,7 +59,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): void {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) sound.stop();
|
||||
else {
|
||||
logger.error(`Cannot stop non-existing sound on channel ${channel}.`);
|
||||
@@ -68,7 +73,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): void {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) sound.pause();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -81,7 +89,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): void {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) {
|
||||
if (!sound.playing()) sound.play();
|
||||
} else {
|
||||
@@ -95,7 +106,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): boolean {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
return sound ? sound.playing() : false;
|
||||
};
|
||||
|
||||
@@ -103,7 +117,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): boolean {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) return sound.paused();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -117,7 +134,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): boolean {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) return sound.stopped();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -131,7 +151,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): float {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) return sound.getVolume() * 100;
|
||||
else {
|
||||
logger.error(
|
||||
@@ -146,7 +169,10 @@ namespace gdjs {
|
||||
channel: integer,
|
||||
volume: float
|
||||
): void {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) sound.setVolume(volume / 100);
|
||||
else {
|
||||
logger.error(
|
||||
@@ -159,7 +185,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): float {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) return sound.getSeek();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -174,7 +203,10 @@ namespace gdjs {
|
||||
channel: integer,
|
||||
playingOffset: float
|
||||
): void {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) sound.setSeek(playingOffset);
|
||||
else {
|
||||
logger.error(
|
||||
@@ -187,7 +219,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): float {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) return sound.getRate();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -202,7 +237,10 @@ namespace gdjs {
|
||||
channel: integer,
|
||||
pitch: float
|
||||
): void {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) sound.setRate(pitch);
|
||||
else {
|
||||
logger.error(
|
||||
@@ -216,6 +254,7 @@ namespace gdjs {
|
||||
soundFile: string
|
||||
) =>
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.loadAudio(soundFile, /* isMusic= */ false);
|
||||
|
||||
@@ -224,6 +263,7 @@ namespace gdjs {
|
||||
soundFile: string
|
||||
) =>
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.unloadAudio(soundFile, /* isMusic= */ false);
|
||||
|
||||
@@ -236,6 +276,7 @@ namespace gdjs {
|
||||
pitch: float
|
||||
): void {
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.playMusic(soundFile, loop, volume, pitch);
|
||||
};
|
||||
@@ -249,6 +290,7 @@ namespace gdjs {
|
||||
pitch: float
|
||||
): void {
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.playMusicOnChannel(soundFile, channel, loop, volume, pitch);
|
||||
};
|
||||
@@ -257,7 +299,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): void {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) music.stop();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -270,7 +315,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): void {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) music.pause();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -283,7 +331,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): void {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) {
|
||||
if (!music.playing()) music.play();
|
||||
} else {
|
||||
@@ -297,7 +348,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): boolean {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
return music ? music.playing() : false;
|
||||
};
|
||||
|
||||
@@ -305,7 +359,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): boolean {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) return music.paused();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -319,7 +376,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): boolean {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) return music.stopped();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -333,7 +393,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): float {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) return music.getVolume() * 100;
|
||||
else {
|
||||
logger.error(
|
||||
@@ -348,7 +411,10 @@ namespace gdjs {
|
||||
channel: integer,
|
||||
volume: float
|
||||
): void {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) music.setVolume(volume / 100);
|
||||
else {
|
||||
logger.error(
|
||||
@@ -361,7 +427,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): float {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) return music.getSeek();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -376,7 +445,10 @@ namespace gdjs {
|
||||
channel: integer,
|
||||
playingOffset: float
|
||||
): void {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) music.setSeek(playingOffset);
|
||||
else {
|
||||
logger.error(
|
||||
@@ -389,7 +461,10 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
channel: integer
|
||||
): float {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) return music.getRate();
|
||||
else {
|
||||
logger.error(
|
||||
@@ -404,7 +479,10 @@ namespace gdjs {
|
||||
channel: integer,
|
||||
pitch: float
|
||||
): void {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) music.setRate(pitch);
|
||||
else {
|
||||
logger.error(
|
||||
@@ -418,6 +496,7 @@ namespace gdjs {
|
||||
soundFile: string
|
||||
) =>
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.loadAudio(soundFile, /* isMusic= */ true);
|
||||
|
||||
@@ -426,6 +505,7 @@ namespace gdjs {
|
||||
soundFile: string
|
||||
) =>
|
||||
runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.unloadAudio(soundFile, /* isMusic= */ true);
|
||||
|
||||
@@ -435,7 +515,10 @@ namespace gdjs {
|
||||
toVolume: float,
|
||||
timeOfFade: float /* in seconds */
|
||||
) => {
|
||||
const sound = runtimeScene.getSoundManager().getSoundOnChannel(channel);
|
||||
const sound = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getSoundOnChannel(channel);
|
||||
if (sound) {
|
||||
sound.fade(sound.getVolume(), toVolume / 100, timeOfFade * 1000);
|
||||
} else {
|
||||
@@ -450,7 +533,10 @@ namespace gdjs {
|
||||
toVolume: float,
|
||||
timeOfFade: float /* in seconds */
|
||||
) => {
|
||||
const music = runtimeScene.getSoundManager().getMusicOnChannel(channel);
|
||||
const music = runtimeScene
|
||||
.getScene()
|
||||
.getSoundManager()
|
||||
.getMusicOnChannel(channel);
|
||||
if (music) {
|
||||
music.fade(music.getVolume(), toVolume / 100, timeOfFade * 1000);
|
||||
} else {
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace gdjs {
|
||||
export const readNumberFromJSONFile = (
|
||||
name: string,
|
||||
elementPath: string,
|
||||
runtimeScene: gdjs.RuntimeScene | null,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer | null,
|
||||
variable: gdjs.Variable
|
||||
) => {
|
||||
return loadObject(name, (jsObject) => {
|
||||
@@ -250,7 +250,7 @@ namespace gdjs {
|
||||
export const readStringFromJSONFile = (
|
||||
name: string,
|
||||
elementPath: string,
|
||||
runtimeScene: gdjs.RuntimeScene | null,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer | null,
|
||||
variable: gdjs.Variable
|
||||
) => {
|
||||
return loadObject(name, (jsObject) => {
|
||||
|
||||
@@ -26,21 +26,25 @@ namespace gdjs {
|
||||
/**
|
||||
* Return the uppercased version of the string.
|
||||
*/
|
||||
export const toUpperCase = function (str) {
|
||||
export const toUpperCase = function (str: string) {
|
||||
return str.toUpperCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the lowercased version of the string.
|
||||
*/
|
||||
export const toLowerCase = function (str) {
|
||||
export const toLowerCase = function (str: string) {
|
||||
return str.toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a new string containing the substring of the original string.
|
||||
*/
|
||||
export const subStr = function (str, start, len) {
|
||||
export const subStr = function (
|
||||
str: string,
|
||||
start: integer,
|
||||
len: integer
|
||||
) {
|
||||
if (start < str.length && start >= 0) {
|
||||
return str.substr(start, len);
|
||||
}
|
||||
@@ -50,7 +54,7 @@ namespace gdjs {
|
||||
/**
|
||||
* Return a new string containing the character at the specified position.
|
||||
*/
|
||||
export const strAt = function (str, start) {
|
||||
export const strAt = function (str: string, start: integer) {
|
||||
if (start < str.length && start >= 0) {
|
||||
return str.substr(start, 1);
|
||||
}
|
||||
@@ -60,7 +64,7 @@ namespace gdjs {
|
||||
/**
|
||||
* Return the string repeated.
|
||||
*/
|
||||
export const strRepeat = function (str, count) {
|
||||
export const strRepeat = function (str: string, count: integer) {
|
||||
let result = '';
|
||||
for (let i = 0; i < count; i++) {
|
||||
result += str;
|
||||
@@ -71,21 +75,21 @@ namespace gdjs {
|
||||
/**
|
||||
* Return the length of the string
|
||||
*/
|
||||
export const strLen = function (str) {
|
||||
export const strLen = function (str: string) {
|
||||
return str.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Search the first occurence in a string (return the position of the result, from the beginning of the string, or -1 if not found)
|
||||
* Search the first occurrence in a string (return the position of the result, from the beginning of the string, or -1 if not found)
|
||||
*/
|
||||
export const strFind = function (str, what) {
|
||||
export const strFind = function (str: string, what: string) {
|
||||
return str.indexOf(what);
|
||||
};
|
||||
|
||||
/**
|
||||
* Search the last occurence in a string (return the position of the result, from the beginning of the string, or -1 if not found)
|
||||
* Search the last occurrence in a string (return the position of the result, from the beginning of the string, or -1 if not found)
|
||||
*/
|
||||
export const strFindLast = function (str, what) {
|
||||
export const strFindLast = function (str: string, what: string) {
|
||||
return str.lastIndexOf(what);
|
||||
};
|
||||
|
||||
@@ -95,16 +99,24 @@ namespace gdjs {
|
||||
export const strRFind = gdjs.evtTools.string.strFindLast;
|
||||
|
||||
/**
|
||||
* Search the first occurence in a string, starting from a specified position (return the position of the result, from the beginning of the string, or -1 if not found)
|
||||
* Search the first occurrence in a string, starting from a specified position (return the position of the result, from the beginning of the string, or -1 if not found)
|
||||
*/
|
||||
export const strFindFrom = function (str, what, pos) {
|
||||
export const strFindFrom = function (
|
||||
str: string,
|
||||
what: string,
|
||||
pos: integer
|
||||
) {
|
||||
return str.indexOf(what, pos);
|
||||
};
|
||||
|
||||
/**
|
||||
* Search the last occurence in a string, starting from a specified position (return the position of the result, from the beginning of the string, or -1 if not found)
|
||||
* Search the last occurrence in a string, starting from a specified position (return the position of the result, from the beginning of the string, or -1 if not found)
|
||||
*/
|
||||
export const strFindLastFrom = function (str, what, pos) {
|
||||
export const strFindLastFrom = function (
|
||||
str: string,
|
||||
what: string,
|
||||
pos: integer
|
||||
) {
|
||||
return str.lastIndexOf(what, pos);
|
||||
};
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace gdjs {
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
variableName: string
|
||||
): boolean {
|
||||
return runtimeScene.getVariables().has(variableName);
|
||||
return runtimeScene.getScene().getVariables().has(variableName);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -85,10 +85,10 @@ namespace gdjs {
|
||||
* @private
|
||||
*/
|
||||
export const globalVariableExists = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
variableName: string
|
||||
): boolean {
|
||||
return runtimeScene.getGame().getVariables().has(variableName);
|
||||
return instanceContainer.getGame().getVariables().has(variableName);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ namespace gdjs {
|
||||
|
||||
type RuntimeSceneCallback = (runtimeScene: gdjs.RuntimeScene) => void;
|
||||
type RuntimeSceneRuntimeObjectCallback = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
runtimeObject: gdjs.RuntimeObject
|
||||
) => void;
|
||||
|
||||
|
||||
+138
-54
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
namespace gdjs {
|
||||
/**
|
||||
* Represents a layer of a scene, used to display objects.
|
||||
* Represents a layer of a container, used to display objects.
|
||||
*
|
||||
* Viewports and multiple cameras are not supported.
|
||||
*/
|
||||
@@ -19,10 +19,8 @@ namespace gdjs {
|
||||
_initialEffectsData: Array<EffectData>;
|
||||
_cameraX: float;
|
||||
_cameraY: float;
|
||||
_cachedGameResolutionWidth: integer;
|
||||
_cachedGameResolutionHeight: integer;
|
||||
|
||||
_runtimeScene: gdjs.RuntimeScene;
|
||||
_runtimeScene: gdjs.RuntimeInstanceContainer;
|
||||
_effectsManager: gdjs.EffectsManager;
|
||||
|
||||
// Lighting layer properties.
|
||||
@@ -31,26 +29,23 @@ namespace gdjs {
|
||||
_clearColor: Array<integer>;
|
||||
|
||||
_rendererEffects: Record<string, PixiFiltersTools.Filter> = {};
|
||||
_renderer: LayerRenderer;
|
||||
_renderer: gdjs.LayerRenderer;
|
||||
|
||||
/**
|
||||
* @param layerData The data used to initialize the layer
|
||||
* @param runtimeScene The scene in which the layer is used
|
||||
* @param instanceContainer The container in which the layer is used
|
||||
*/
|
||||
constructor(layerData: LayerData, runtimeScene: gdjs.RuntimeScene) {
|
||||
constructor(
|
||||
layerData: LayerData,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._name = layerData.name;
|
||||
this._hidden = !layerData.visibility;
|
||||
this._initialEffectsData = 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;
|
||||
this._effectsManager = runtimeScene.getGame().getEffectsManager();
|
||||
this._runtimeScene = instanceContainer;
|
||||
this._cameraX = this.getWidth() / 2;
|
||||
this._cameraY = this.getHeight() / 2;
|
||||
this._effectsManager = instanceContainer.getGame().getEffectsManager();
|
||||
this._isLightingLayer = layerData.isLightingLayer;
|
||||
this._followBaseLayerCamera = layerData.followBaseLayerCamera;
|
||||
this._clearColor = [
|
||||
@@ -59,7 +54,11 @@ namespace gdjs {
|
||||
layerData.ambientLightColorB / 255,
|
||||
1.0,
|
||||
];
|
||||
this._renderer = new gdjs.LayerRenderer(this, runtimeScene.getRenderer());
|
||||
this._renderer = new gdjs.LayerRenderer(
|
||||
this,
|
||||
instanceContainer.getRenderer(),
|
||||
instanceContainer.getGame().getRenderer().getPIXIRenderer()
|
||||
);
|
||||
this.show(!this._hidden);
|
||||
for (let i = 0; i < layerData.effects.length; ++i) {
|
||||
this.addEffect(layerData.effects[i]);
|
||||
@@ -90,16 +89,10 @@ namespace gdjs {
|
||||
* Called by the RuntimeScene whenever the game resolution size is changed.
|
||||
* Updates the layer width/height and position.
|
||||
*/
|
||||
onGameResolutionResized(): void {
|
||||
const oldGameResolutionWidth = this._cachedGameResolutionWidth;
|
||||
const oldGameResolutionHeight = this._cachedGameResolutionHeight;
|
||||
this._cachedGameResolutionWidth = this._runtimeScene
|
||||
.getGame()
|
||||
.getGameResolutionWidth();
|
||||
this._cachedGameResolutionHeight = this._runtimeScene
|
||||
.getGame()
|
||||
.getGameResolutionHeight();
|
||||
|
||||
onGameResolutionResized(
|
||||
oldGameResolutionOriginX: float,
|
||||
oldGameResolutionOriginY: float
|
||||
): void {
|
||||
// Adapt position of the camera center as:
|
||||
// * Most cameras following a player/object on the scene will be updating this
|
||||
// in events anyway.
|
||||
@@ -108,24 +101,24 @@ namespace gdjs {
|
||||
// move from its initial position (which is centered in the screen) - and anchor
|
||||
// behavior would behave counterintuitively.
|
||||
this._cameraX +=
|
||||
(this._cachedGameResolutionWidth - oldGameResolutionWidth) / 2;
|
||||
this._runtimeScene.getViewportOriginX() - oldGameResolutionOriginX;
|
||||
this._cameraY +=
|
||||
(this._cachedGameResolutionHeight - oldGameResolutionHeight) / 2;
|
||||
this._runtimeScene.getViewportOriginY() - oldGameResolutionOriginY;
|
||||
this._renderer.updatePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scene the layer belongs to
|
||||
* @returns the scene the layer belongs to
|
||||
* Returns the scene the layer belongs to directly or indirectly
|
||||
* @returns the scene the layer belongs to directly or indirectly
|
||||
*/
|
||||
getRuntimeScene(): gdjs.RuntimeScene {
|
||||
return this._runtimeScene;
|
||||
return this._runtimeScene.getScene();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at each frame, after events are run and before rendering.
|
||||
*/
|
||||
updatePreRender(runtimeScene?: gdjs.RuntimeScene): void {
|
||||
updatePreRender(instanceContainer?: gdjs.RuntimeInstanceContainer): void {
|
||||
if (this._followBaseLayerCamera) {
|
||||
this.followBaseLayer();
|
||||
}
|
||||
@@ -148,6 +141,7 @@ namespace gdjs {
|
||||
* @return The x position of the camera
|
||||
*/
|
||||
getCameraX(cameraId?: integer): float {
|
||||
this._forceDimensionUpdate();
|
||||
return this._cameraX;
|
||||
}
|
||||
|
||||
@@ -158,6 +152,7 @@ namespace gdjs {
|
||||
* @return The y position of the camera
|
||||
*/
|
||||
getCameraY(cameraId?: integer): float {
|
||||
this._forceDimensionUpdate();
|
||||
return this._cameraY;
|
||||
}
|
||||
|
||||
@@ -168,6 +163,7 @@ namespace gdjs {
|
||||
* @param cameraId The camera number. Currently ignored.
|
||||
*/
|
||||
setCameraX(x: float, cameraId?: integer): void {
|
||||
this._forceDimensionUpdate();
|
||||
this._cameraX = x;
|
||||
this._renderer.updatePosition();
|
||||
}
|
||||
@@ -179,6 +175,7 @@ namespace gdjs {
|
||||
* @param cameraId The camera number. Currently ignored.
|
||||
*/
|
||||
setCameraY(y: float, cameraId?: integer): void {
|
||||
this._forceDimensionUpdate();
|
||||
this._cameraY = y;
|
||||
this._renderer.updatePosition();
|
||||
}
|
||||
@@ -191,7 +188,7 @@ namespace gdjs {
|
||||
* @return The width of the camera
|
||||
*/
|
||||
getCameraWidth(cameraId?: integer): float {
|
||||
return (+this._cachedGameResolutionWidth * 1) / this._zoomFactor;
|
||||
return this.getWidth() / this._zoomFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,7 +199,7 @@ namespace gdjs {
|
||||
* @return The height of the camera
|
||||
*/
|
||||
getCameraHeight(cameraId?: integer): float {
|
||||
return (+this._cachedGameResolutionHeight * 1) / this._zoomFactor;
|
||||
return this.getHeight() / this._zoomFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,15 +265,51 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Convert a point from the canvas coordinates (for example,
|
||||
* the mouse position) to the scene coordinates.
|
||||
* the mouse position) to the container coordinates.
|
||||
*
|
||||
* @param x The x position, in canvas coordinates.
|
||||
* @param y The y position, in canvas coordinates.
|
||||
* @param cameraId The camera number. Currently ignored.
|
||||
* @param result The point instance that is used to return the result.
|
||||
*/
|
||||
convertCoords(x: float, y: float, cameraId?: integer): FloatPoint {
|
||||
x -= this._cachedGameResolutionWidth / 2;
|
||||
y -= this._cachedGameResolutionHeight / 2;
|
||||
convertCoords(
|
||||
x: float,
|
||||
y: float,
|
||||
cameraId: integer = 0,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
// The result parameter used to be optional.
|
||||
let position = result || [0, 0];
|
||||
// TODO EBO use an AffineTransformation to avoid chained calls.
|
||||
position = this._runtimeScene.convertCoords(x, y, position);
|
||||
return this.applyLayerInverseTransformation(
|
||||
position[0],
|
||||
position[1],
|
||||
cameraId,
|
||||
position
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array containing the coordinates of the point passed as parameter
|
||||
* in layer local coordinates (as opposed to the parent coordinates).
|
||||
*
|
||||
* All transformations (scale, rotation) are supported.
|
||||
*
|
||||
* @param x The X position of the point, in parent coordinates.
|
||||
* @param y The Y position of the point, in parent coordinates.
|
||||
* @param result Array that will be updated with the result
|
||||
* @param result The point instance that is used to return the result.
|
||||
* (x and y position of the point in layer coordinates).
|
||||
*/
|
||||
applyLayerInverseTransformation(
|
||||
x: float,
|
||||
y: float,
|
||||
cameraId: integer,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
x -= this._runtimeScene.getViewportOriginX();
|
||||
y -= this._runtimeScene.getViewportOriginY();
|
||||
x /= Math.abs(this._zoomFactor);
|
||||
y /= Math.abs(this._zoomFactor);
|
||||
|
||||
@@ -287,18 +320,54 @@ namespace gdjs {
|
||||
const sinValue = Math.sin(angleInRadians);
|
||||
x = cosValue * x - sinValue * y;
|
||||
y = sinValue * tmp + cosValue * y;
|
||||
return [x + this.getCameraX(cameraId), y + this.getCameraY(cameraId)];
|
||||
result[0] = x + this.getCameraX(cameraId);
|
||||
result[1] = y + this.getCameraY(cameraId);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a point from the scene coordinates (for example,
|
||||
* Convert a point from the container coordinates (for example,
|
||||
* an object position) to the canvas coordinates.
|
||||
*
|
||||
* @param x The x position, in scene coordinates.
|
||||
* @param y The y position, in scene coordinates.
|
||||
* @param x The x position, in container coordinates.
|
||||
* @param y The y position, in container coordinates.
|
||||
* @param cameraId The camera number. Currently ignored.
|
||||
* @param result The point instance that is used to return the result.
|
||||
*/
|
||||
convertInverseCoords(x: float, y: float, cameraId?: integer): FloatPoint {
|
||||
convertInverseCoords(
|
||||
x: float,
|
||||
y: float,
|
||||
cameraId: integer = 0,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
let position = result || [0, 0];
|
||||
// TODO EBO use an AffineTransformation to avoid chained calls.
|
||||
this.applyLayerTransformation(x, y, cameraId, position);
|
||||
return this._runtimeScene.convertInverseCoords(
|
||||
position[0],
|
||||
position[1],
|
||||
position
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array containing the coordinates of the point passed as parameter
|
||||
* in parent coordinate coordinates (as opposed to the layer local coordinates).
|
||||
*
|
||||
* All transformations (scale, rotation) are supported.
|
||||
*
|
||||
* @param x The X position of the point, in layer coordinates.
|
||||
* @param y The Y position of the point, in layer coordinates.
|
||||
* @param result Array that will be updated with the result
|
||||
* (x and y position of the point in parent coordinates).
|
||||
*/
|
||||
applyLayerTransformation(
|
||||
x: float,
|
||||
y: float,
|
||||
cameraId: integer,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
x -= this.getCameraX(cameraId);
|
||||
y -= this.getCameraY(cameraId);
|
||||
|
||||
@@ -311,18 +380,31 @@ namespace gdjs {
|
||||
y = sinValue * tmp + cosValue * y;
|
||||
x *= Math.abs(this._zoomFactor);
|
||||
y *= Math.abs(this._zoomFactor);
|
||||
return [
|
||||
x + this._cachedGameResolutionWidth / 2,
|
||||
y + this._cachedGameResolutionHeight / 2,
|
||||
];
|
||||
x += this._runtimeScene.getViewportOriginX();
|
||||
y += this._runtimeScene.getViewportOriginY();
|
||||
|
||||
result[0] = x;
|
||||
result[1] = y;
|
||||
return result;
|
||||
}
|
||||
|
||||
getWidth(): float {
|
||||
return this._cachedGameResolutionWidth;
|
||||
return this._runtimeScene.getViewportWidth();
|
||||
}
|
||||
|
||||
getHeight(): float {
|
||||
return this._cachedGameResolutionHeight;
|
||||
return this._runtimeScene.getViewportHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* This ensure that the viewport dimensions are up to date.
|
||||
*
|
||||
* It's needed because custom objects dimensions are only updated on
|
||||
* demand for efficiency reasons.
|
||||
*/
|
||||
private _forceDimensionUpdate(): void {
|
||||
// This will update dimensions.
|
||||
this._runtimeScene.getViewportWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,10 +546,12 @@ namespace gdjs {
|
||||
/**
|
||||
* Return the time elapsed since the last frame,
|
||||
* in milliseconds, for objects on the layer.
|
||||
*
|
||||
* @param instanceContainer The instance container the layer belongs to (deprecated - can be omitted).
|
||||
*/
|
||||
getElapsedTime(runtimeScene?: RuntimeScene): float {
|
||||
runtimeScene = runtimeScene || this._runtimeScene;
|
||||
return runtimeScene.getTimeManager().getElapsedTime() * this._timeScale;
|
||||
getElapsedTime(instanceContainer?: gdjs.RuntimeInstanceContainer): float {
|
||||
const container = instanceContainer || this._runtimeScene;
|
||||
return container.getElapsedTime() * this._timeScale;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
|
||||
/**
|
||||
* The renderer for a {@link gdjs.CustomRuntimeObject} using Pixi.js.
|
||||
*/
|
||||
export class CustomObjectPixiRenderer
|
||||
implements gdjs.RuntimeInstanceContainerPixiRenderer {
|
||||
_object: gdjs.CustomRuntimeObject;
|
||||
_instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer;
|
||||
_pixiContainer: PIXI.Container;
|
||||
_isContainerDirty: boolean = true;
|
||||
_debugDraw: PIXI.Graphics | null = null;
|
||||
_debugDrawContainer: PIXI.Container | null = null;
|
||||
_debugDrawRenderedObjectsPoints: Record<
|
||||
number,
|
||||
{
|
||||
wasRendered: boolean;
|
||||
points: Record<string, PIXI.Text>;
|
||||
}
|
||||
>;
|
||||
|
||||
constructor(
|
||||
object: gdjs.CustomRuntimeObject,
|
||||
instanceContainer: gdjs.CustomRuntimeObjectInstanceContainer,
|
||||
parent: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = object;
|
||||
this._instanceContainer = instanceContainer;
|
||||
this._pixiContainer = new PIXI.Container();
|
||||
this._debugDrawRenderedObjectsPoints = {};
|
||||
|
||||
// Contains the layers of the scene (and, optionally, debug PIXI objects).
|
||||
this._pixiContainer.sortableChildren = true;
|
||||
this._debugDraw = null;
|
||||
|
||||
const layer = parent.getLayer('');
|
||||
if (layer) {
|
||||
layer
|
||||
.getRenderer()
|
||||
.addRendererObject(this._pixiContainer, object.getZOrder());
|
||||
}
|
||||
}
|
||||
|
||||
reinitialize(
|
||||
object: gdjs.CustomRuntimeObject,
|
||||
parent: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = object;
|
||||
this._isContainerDirty = true;
|
||||
const layer = parent.getLayer('');
|
||||
if (layer) {
|
||||
layer
|
||||
.getRenderer()
|
||||
.addRendererObject(this._pixiContainer, object.getZOrder());
|
||||
}
|
||||
}
|
||||
|
||||
getRendererObject() {
|
||||
return this._pixiContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the internal PIXI.Container position, angle...
|
||||
*/
|
||||
_updatePIXIContainer() {
|
||||
this._pixiContainer.pivot.x = this._object.getUnscaledCenterX();
|
||||
this._pixiContainer.pivot.y = this._object.getUnscaledCenterY();
|
||||
this._pixiContainer.position.x =
|
||||
this._object.getDrawableX() +
|
||||
this._pixiContainer.pivot.x * Math.abs(this._object._scaleX);
|
||||
this._pixiContainer.position.y =
|
||||
this._object.getDrawableY() +
|
||||
this._pixiContainer.pivot.y * Math.abs(this._object._scaleY);
|
||||
this._pixiContainer.rotation = gdjs.toRad(this._object.angle);
|
||||
this._pixiContainer.scale.x = this._object._scaleX;
|
||||
this._pixiContainer.scale.y = this._object._scaleY;
|
||||
this._pixiContainer.visible = !this._object.hidden;
|
||||
this._pixiContainer.alpha = this._object.opacity / 255;
|
||||
|
||||
this._isContainerDirty = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to make sure the sprite is ready to be rendered.
|
||||
*/
|
||||
ensureUpToDate() {
|
||||
if (this._isContainerDirty) {
|
||||
this._updatePIXIContainer();
|
||||
}
|
||||
}
|
||||
|
||||
update(): void {
|
||||
this._isContainerDirty = true;
|
||||
}
|
||||
|
||||
updateX(): void {
|
||||
this._pixiContainer.position.x =
|
||||
this._object.x +
|
||||
this._pixiContainer.pivot.x * Math.abs(this._object._scaleX);
|
||||
}
|
||||
|
||||
updateY(): void {
|
||||
this._pixiContainer.position.y =
|
||||
this._object.y +
|
||||
this._pixiContainer.pivot.y * Math.abs(this._object._scaleY);
|
||||
}
|
||||
|
||||
updateAngle(): void {
|
||||
this._pixiContainer.rotation = gdjs.toRad(this._object.angle);
|
||||
}
|
||||
|
||||
updateOpacity(): void {
|
||||
this._pixiContainer.alpha = this._object.opacity / 255;
|
||||
}
|
||||
|
||||
updateVisibility(): void {
|
||||
this._pixiContainer.visible = !this._object.hidden;
|
||||
}
|
||||
|
||||
getPIXIContainer() {
|
||||
return this._pixiContainer;
|
||||
}
|
||||
|
||||
getPIXIRenderer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
setLayerIndex(layer: gdjs.Layer, index: float): void {
|
||||
const layerPixiRenderer: gdjs.LayerPixiRenderer = layer.getRenderer();
|
||||
let layerPixiObject:
|
||||
| PIXI.Container
|
||||
| PIXI.Sprite
|
||||
| null = layerPixiRenderer.getRendererObject();
|
||||
if (layer.isLightingLayer()) {
|
||||
layerPixiObject = layerPixiRenderer.getLightingSprite();
|
||||
}
|
||||
if (!layerPixiObject) {
|
||||
return;
|
||||
}
|
||||
if (this._pixiContainer.children.indexOf(layerPixiObject) === index) {
|
||||
return;
|
||||
}
|
||||
this._pixiContainer.removeChild(layerPixiObject);
|
||||
this._pixiContainer.addChildAt(layerPixiObject, index);
|
||||
}
|
||||
}
|
||||
|
||||
// Register the class to let the engine use it.
|
||||
export type CustomObjectRenderer = gdjs.CustomObjectPixiRenderer;
|
||||
export const CustomObjectRenderer = gdjs.CustomObjectPixiRenderer;
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
|
||||
/**
|
||||
* A renderer for debug instances location of a container using Pixi.js.
|
||||
*
|
||||
* @see gdjs.CustomObjectPixiRenderer
|
||||
*/
|
||||
export class DebuggerPixiRenderer {
|
||||
_instanceContainer: gdjs.RuntimeInstanceContainer;
|
||||
_debugDraw: PIXI.Graphics | null = null;
|
||||
_debugDrawContainer: PIXI.Container | null = null;
|
||||
_debugDrawRenderedObjectsPoints: Record<
|
||||
number,
|
||||
{
|
||||
wasRendered: boolean;
|
||||
points: Record<string, PIXI.Text>;
|
||||
}
|
||||
>;
|
||||
|
||||
constructor(instanceContainer: gdjs.RuntimeInstanceContainer) {
|
||||
this._instanceContainer = instanceContainer;
|
||||
this._debugDrawRenderedObjectsPoints = {};
|
||||
this._debugDraw = null;
|
||||
}
|
||||
|
||||
getRendererObject() {
|
||||
return this._debugDrawContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render graphics for debugging purpose. Activate this in `gdjs.RuntimeScene`,
|
||||
* in the `renderAndStep` method.
|
||||
* @see gdjs.RuntimeInstanceContainer#enableDebugDraw
|
||||
*/
|
||||
renderDebugDraw(
|
||||
instances: gdjs.RuntimeObject[],
|
||||
showHiddenInstances: boolean,
|
||||
showPointsNames: boolean,
|
||||
showCustomPoints: boolean
|
||||
) {
|
||||
const pixiContainer = this._instanceContainer
|
||||
.getRenderer()
|
||||
.getRendererObject();
|
||||
if (!this._debugDraw || !this._debugDrawContainer) {
|
||||
this._debugDrawContainer = new PIXI.Container();
|
||||
this._debugDraw = new PIXI.Graphics();
|
||||
|
||||
// Add on top of all layers:
|
||||
this._debugDrawContainer.addChild(this._debugDraw);
|
||||
pixiContainer.addChild(this._debugDrawContainer);
|
||||
}
|
||||
const debugDraw = this._debugDraw;
|
||||
|
||||
// Reset the boolean "wasRendered" of all points of objects to false:
|
||||
for (let id in this._debugDrawRenderedObjectsPoints) {
|
||||
this._debugDrawRenderedObjectsPoints[id].wasRendered = false;
|
||||
}
|
||||
|
||||
const renderObjectPoint = (
|
||||
points: Record<string, PIXI.Text>,
|
||||
name: string,
|
||||
fillColor: integer,
|
||||
x: float,
|
||||
y: float
|
||||
) => {
|
||||
debugDraw.line.color = fillColor;
|
||||
debugDraw.fill.color = fillColor;
|
||||
debugDraw.drawCircle(x, y, 3);
|
||||
|
||||
if (showPointsNames) {
|
||||
if (!points[name]) {
|
||||
points[name] = new PIXI.Text(name, {
|
||||
fill: fillColor,
|
||||
fontSize: 12,
|
||||
});
|
||||
|
||||
this._debugDrawContainer!.addChild(points[name]);
|
||||
}
|
||||
|
||||
points[name].position.set(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
debugDraw.clear();
|
||||
debugDraw.beginFill();
|
||||
debugDraw.alpha = 0.8;
|
||||
debugDraw.lineStyle(2, 0x0000ff, 1);
|
||||
|
||||
// Draw AABB
|
||||
const workingPoint: FloatPoint = [0, 0];
|
||||
for (let i = 0; i < instances.length; i++) {
|
||||
const object = instances[i];
|
||||
const layer = this._instanceContainer.getLayer(object.getLayer());
|
||||
|
||||
if (
|
||||
(!object.isVisible() || !layer.isVisible()) &&
|
||||
!showHiddenInstances
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (!rendererObject) {
|
||||
continue;
|
||||
}
|
||||
const aabb = object.getAABB();
|
||||
debugDraw.fill.alpha = 0.2;
|
||||
debugDraw.line.color = 0x778ee8;
|
||||
debugDraw.fill.color = 0x778ee8;
|
||||
|
||||
const polygon: float[] = [];
|
||||
polygon.push.apply(
|
||||
polygon,
|
||||
layer.applyLayerTransformation(
|
||||
aabb.min[0],
|
||||
aabb.min[1],
|
||||
0,
|
||||
workingPoint
|
||||
)
|
||||
);
|
||||
polygon.push.apply(
|
||||
polygon,
|
||||
layer.applyLayerTransformation(
|
||||
aabb.max[0],
|
||||
aabb.min[1],
|
||||
0,
|
||||
workingPoint
|
||||
)
|
||||
);
|
||||
polygon.push.apply(
|
||||
polygon,
|
||||
layer.applyLayerTransformation(
|
||||
aabb.max[0],
|
||||
aabb.max[1],
|
||||
0,
|
||||
workingPoint
|
||||
)
|
||||
);
|
||||
polygon.push.apply(
|
||||
polygon,
|
||||
layer.applyLayerTransformation(
|
||||
aabb.min[0],
|
||||
aabb.max[1],
|
||||
0,
|
||||
workingPoint
|
||||
)
|
||||
);
|
||||
|
||||
debugDraw.drawPolygon(polygon);
|
||||
}
|
||||
|
||||
// Draw hitboxes and points
|
||||
for (let i = 0; i < instances.length; i++) {
|
||||
const object = instances[i];
|
||||
const layer = this._instanceContainer.getLayer(object.getLayer());
|
||||
|
||||
if (
|
||||
(!object.isVisible() || !layer.isVisible()) &&
|
||||
!showHiddenInstances
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (!rendererObject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the structure to store the points in memory
|
||||
const id = object.id;
|
||||
if (!this._debugDrawRenderedObjectsPoints[id]) {
|
||||
this._debugDrawRenderedObjectsPoints[id] = {
|
||||
wasRendered: true,
|
||||
points: {},
|
||||
};
|
||||
}
|
||||
const renderedObjectPoints = this._debugDrawRenderedObjectsPoints[id];
|
||||
renderedObjectPoints.wasRendered = true;
|
||||
|
||||
// Draw hitboxes (sub-optimal performance)
|
||||
const hitboxes = object.getHitBoxes();
|
||||
for (let j = 0; j < hitboxes.length; j++) {
|
||||
// Note that this conversion is sub-optimal, but we don't care
|
||||
// as this is for debug draw.
|
||||
const polygon: float[] = [];
|
||||
hitboxes[j].vertices.forEach((point) => {
|
||||
point = layer.applyLayerTransformation(
|
||||
point[0],
|
||||
point[1],
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
polygon.push(point[0]);
|
||||
polygon.push(point[1]);
|
||||
});
|
||||
debugDraw.fill.alpha = 0;
|
||||
debugDraw.line.alpha = 0.5;
|
||||
debugDraw.line.color = 0xff0000;
|
||||
debugDraw.drawPolygon(polygon);
|
||||
}
|
||||
|
||||
// Draw points
|
||||
debugDraw.fill.alpha = 0.3;
|
||||
|
||||
// Draw Center point
|
||||
const centerPoint = layer.applyLayerTransformation(
|
||||
object.getCenterXInScene(),
|
||||
object.getCenterYInScene(),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
renderObjectPoint(
|
||||
renderedObjectPoints.points,
|
||||
'Center',
|
||||
0xffff00,
|
||||
centerPoint[0],
|
||||
centerPoint[1]
|
||||
);
|
||||
|
||||
// Draw position point
|
||||
const positionPoint = layer.applyLayerTransformation(
|
||||
object.getX(),
|
||||
object.getY(),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
renderObjectPoint(
|
||||
renderedObjectPoints.points,
|
||||
'Position',
|
||||
0xff0000,
|
||||
positionPoint[0],
|
||||
positionPoint[1]
|
||||
);
|
||||
|
||||
// Draw Origin point
|
||||
if (object instanceof gdjs.SpriteRuntimeObject) {
|
||||
let originPoint = object.getPointPosition('origin');
|
||||
// When there is neither rotation nor flipping,
|
||||
// the origin point is over the position point.
|
||||
if (
|
||||
Math.abs(originPoint[0] - positionPoint[0]) >= 1 ||
|
||||
Math.abs(originPoint[1] - positionPoint[1]) >= 1
|
||||
) {
|
||||
originPoint = layer.applyLayerTransformation(
|
||||
originPoint[0],
|
||||
originPoint[1],
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
renderObjectPoint(
|
||||
renderedObjectPoints.points,
|
||||
'Origin',
|
||||
0xff0000,
|
||||
originPoint[0],
|
||||
originPoint[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw custom point
|
||||
if (showCustomPoints && object instanceof gdjs.SpriteRuntimeObject) {
|
||||
if (!object._animationFrame) continue;
|
||||
|
||||
for (const customPointName in object._animationFrame.points.items) {
|
||||
let customPoint = object.getPointPosition(customPointName);
|
||||
|
||||
customPoint = layer.applyLayerTransformation(
|
||||
customPoint[0],
|
||||
customPoint[1],
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
renderObjectPoint(
|
||||
renderedObjectPoints.points,
|
||||
customPointName,
|
||||
0x0000ff,
|
||||
customPoint[0],
|
||||
customPoint[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean any point text from an object that is not rendered.
|
||||
for (const objectID in this._debugDrawRenderedObjectsPoints) {
|
||||
const renderedObjectPoints = this._debugDrawRenderedObjectsPoints[
|
||||
objectID
|
||||
];
|
||||
if (renderedObjectPoints.wasRendered) continue;
|
||||
|
||||
const points = renderedObjectPoints.points;
|
||||
for (const name in points) {
|
||||
this._debugDrawContainer.removeChild(points[name]);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.endFill();
|
||||
}
|
||||
|
||||
clearDebugDraw(): void {
|
||||
if (this._debugDraw) {
|
||||
this._debugDraw.clear();
|
||||
}
|
||||
|
||||
if (this._debugDrawContainer) {
|
||||
this._debugDrawContainer.destroy({
|
||||
children: true,
|
||||
});
|
||||
const pixiContainer: PIXI.Container = this._instanceContainer
|
||||
.getRenderer()
|
||||
.getRendererObject();
|
||||
pixiContainer.removeChild(this._debugDrawContainer);
|
||||
}
|
||||
this._debugDraw = null;
|
||||
this._debugDrawContainer = null;
|
||||
this._debugDrawRenderedObjectsPoints = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Register the class to let the engine use it.
|
||||
export type DebuggerRenderer = gdjs.DebuggerPixiRenderer;
|
||||
export const DebuggerRenderer = gdjs.DebuggerPixiRenderer;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2013-2016 Florian Rival ([email protected]). All rights reserved.
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
namespace gdjs {
|
||||
import PIXI = GlobalPIXIModule.PIXI;
|
||||
|
||||
/**
|
||||
* A render for instance container.
|
||||
*
|
||||
* @see gdjs.RuntimeInstanceContainer
|
||||
*/
|
||||
export interface RuntimeInstanceContainerPixiRenderer {
|
||||
/**
|
||||
* Change the position of a layer.
|
||||
*
|
||||
* @param layer The layer to reorder
|
||||
* @param index The new position in the list of layers
|
||||
*
|
||||
* @see gdjs.RuntimeInstanceContainer.setLayerIndex
|
||||
*/
|
||||
setLayerIndex(layer: gdjs.Layer, index: integer): void;
|
||||
|
||||
getRendererObject(): PIXI.Container;
|
||||
}
|
||||
|
||||
// Register the class to let the engine use it.
|
||||
export type RuntimeInstanceContainerRenderer = gdjs.RuntimeInstanceContainerPixiRenderer;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace gdjs {
|
||||
_layer: gdjs.Layer;
|
||||
_renderTexture: PIXI.RenderTexture | null = null;
|
||||
_lightingSprite: PIXI.Sprite | null = null;
|
||||
_runtimeSceneRenderer: any;
|
||||
_runtimeSceneRenderer: gdjs.RuntimeInstanceContainerRenderer;
|
||||
_pixiRenderer: PIXI.Renderer | null;
|
||||
|
||||
// Width and height are tracked when a render texture is used.
|
||||
@@ -27,19 +27,22 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* @param layer The layer
|
||||
* @param runtimeSceneRenderer The scene renderer
|
||||
* @param runtimeInstanceContainerRenderer The scene renderer
|
||||
*/
|
||||
constructor(
|
||||
layer: gdjs.Layer,
|
||||
runtimeSceneRenderer: gdjs.RuntimeScenePixiRenderer
|
||||
runtimeInstanceContainerRenderer: gdjs.RuntimeInstanceContainerRenderer,
|
||||
pixiRenderer: PIXI.Renderer | null
|
||||
) {
|
||||
this._pixiContainer = new PIXI.Container();
|
||||
this._layer = layer;
|
||||
this._runtimeSceneRenderer = runtimeSceneRenderer;
|
||||
this._pixiRenderer = runtimeSceneRenderer.getPIXIRenderer();
|
||||
this._runtimeSceneRenderer = runtimeInstanceContainerRenderer;
|
||||
this._pixiRenderer = pixiRenderer;
|
||||
this._isLightingLayer = layer.isLightingLayer();
|
||||
this._clearColor = layer.getClearColor();
|
||||
runtimeSceneRenderer.getPIXIContainer().addChild(this._pixiContainer);
|
||||
runtimeInstanceContainerRenderer
|
||||
.getRendererObject()
|
||||
.addChild(this._pixiContainer);
|
||||
this._pixiContainer.filters = [];
|
||||
if (this._isLightingLayer) {
|
||||
this._replaceContainerWithSprite();
|
||||
@@ -244,7 +247,7 @@ namespace gdjs {
|
||||
}
|
||||
this._lightingSprite = new PIXI.Sprite(this._renderTexture);
|
||||
this._lightingSprite.blendMode = PIXI.BLEND_MODES.MULTIPLY;
|
||||
const sceneContainer = this._runtimeSceneRenderer.getPIXIContainer();
|
||||
const sceneContainer = this._runtimeSceneRenderer.getRendererObject();
|
||||
const index = sceneContainer.getChildIndex(this._pixiContainer);
|
||||
sceneContainer.addChildAt(this._lightingSprite, index);
|
||||
sceneContainer.removeChild(this._pixiContainer);
|
||||
|
||||
@@ -9,8 +9,10 @@ namespace gdjs {
|
||||
type RendererEffects = Record<string, PixiFiltersTools.Filter>;
|
||||
|
||||
export interface EffectsTarget {
|
||||
getRuntimeScene: () => RuntimeScene;
|
||||
getElapsedTime: (runtimeScene?: RuntimeScene) => number;
|
||||
getRuntimeScene: () => gdjs.RuntimeInstanceContainer;
|
||||
getElapsedTime: (
|
||||
instanceContainer?: gdjs.RuntimeInstanceContainer
|
||||
) => number;
|
||||
getHeight: () => number;
|
||||
getWidth: () => number;
|
||||
isLightingLayer?: () => boolean;
|
||||
|
||||
@@ -409,18 +409,24 @@ namespace gdjs {
|
||||
* Convert a point from the canvas coordinates to the dom element container coordinates.
|
||||
*
|
||||
* @param canvasCoords The point in the canvas coordinates.
|
||||
* @param result The point to return.
|
||||
* @returns The point in the dom element container coordinates.
|
||||
*/
|
||||
convertCanvasToDomElementContainerCoords(
|
||||
canvasCoords: FloatPoint
|
||||
canvasCoords: FloatPoint,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
const pageCoords: FloatPoint = [canvasCoords[0], canvasCoords[1]];
|
||||
const pageCoords = result || [0, 0];
|
||||
|
||||
// Handle the fact that the game is stretched to fill the canvas.
|
||||
pageCoords[0] /=
|
||||
this._game.getGameResolutionWidth() / (this._canvasWidth || 1);
|
||||
pageCoords[1] /=
|
||||
this._game.getGameResolutionHeight() / (this._canvasHeight || 1);
|
||||
pageCoords[0] =
|
||||
canvasCoords[0] /
|
||||
this._game.getGameResolutionWidth() /
|
||||
(this._canvasWidth || 1);
|
||||
pageCoords[1] =
|
||||
canvasCoords[1] /
|
||||
this._game.getGameResolutionHeight() /
|
||||
(this._canvasHeight || 1);
|
||||
|
||||
return pageCoords;
|
||||
}
|
||||
|
||||
@@ -4,21 +4,13 @@ namespace gdjs {
|
||||
/**
|
||||
* The renderer for a gdjs.RuntimeScene using Pixi.js.
|
||||
*/
|
||||
export class RuntimeScenePixiRenderer {
|
||||
export class RuntimeScenePixiRenderer
|
||||
implements gdjs.RuntimeInstanceContainerPixiRenderer {
|
||||
_pixiRenderer: PIXI.Renderer | null;
|
||||
_runtimeScene: gdjs.RuntimeScene;
|
||||
_pixiContainer: PIXI.Container;
|
||||
_debugDraw: PIXI.Graphics | null = null;
|
||||
_debugDrawContainer: PIXI.Container | null = null;
|
||||
_profilerText: PIXI.Text | null = null;
|
||||
_showCursorAtNextRender: boolean = false;
|
||||
_debugDrawRenderedObjectsPoints: Record<
|
||||
number,
|
||||
{
|
||||
wasRendered: boolean;
|
||||
points: Record<string, PIXI.Text>;
|
||||
}
|
||||
>;
|
||||
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
@@ -29,11 +21,9 @@ namespace gdjs {
|
||||
: null;
|
||||
this._runtimeScene = runtimeScene;
|
||||
this._pixiContainer = new PIXI.Container();
|
||||
this._debugDrawRenderedObjectsPoints = {};
|
||||
|
||||
// Contains the layers of the scene (and, optionally, debug PIXI objects).
|
||||
this._pixiContainer.sortableChildren = true;
|
||||
this._debugDraw = null;
|
||||
}
|
||||
|
||||
onGameResolutionResized() {
|
||||
@@ -90,259 +80,6 @@ namespace gdjs {
|
||||
this._profilerText.text = outputs.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render graphics for debugging purpose. Activate this in `gdjs.RuntimeScene`,
|
||||
* in the `renderAndStep` method.
|
||||
*/
|
||||
renderDebugDraw(
|
||||
instances: gdjs.RuntimeObject[],
|
||||
showHiddenInstances: boolean,
|
||||
showPointsNames: boolean,
|
||||
showCustomPoints: boolean
|
||||
) {
|
||||
if (!this._debugDraw || !this._debugDrawContainer) {
|
||||
this._debugDrawContainer = new PIXI.Container();
|
||||
this._debugDraw = new PIXI.Graphics();
|
||||
|
||||
// Add on top of all layers:
|
||||
this._debugDrawContainer.addChild(this._debugDraw);
|
||||
this._pixiContainer.addChild(this._debugDrawContainer);
|
||||
}
|
||||
const debugDraw = this._debugDraw;
|
||||
|
||||
// Reset the boolean "wasRendered" of all points of objects to false:
|
||||
for (let id in this._debugDrawRenderedObjectsPoints) {
|
||||
this._debugDrawRenderedObjectsPoints[id].wasRendered = false;
|
||||
}
|
||||
|
||||
const renderObjectPoint = (
|
||||
points: Record<string, PIXI.Text>,
|
||||
name: string,
|
||||
fillColor: integer,
|
||||
x: float,
|
||||
y: float
|
||||
) => {
|
||||
debugDraw.line.color = fillColor;
|
||||
debugDraw.fill.color = fillColor;
|
||||
debugDraw.drawCircle(x, y, 3);
|
||||
|
||||
if (showPointsNames) {
|
||||
if (!points[name]) {
|
||||
points[name] = new PIXI.Text(name, {
|
||||
fill: fillColor,
|
||||
fontSize: 12,
|
||||
});
|
||||
|
||||
this._debugDrawContainer!.addChild(points[name]);
|
||||
}
|
||||
|
||||
points[name].position.set(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
debugDraw.clear();
|
||||
debugDraw.beginFill();
|
||||
debugDraw.alpha = 0.8;
|
||||
debugDraw.lineStyle(2, 0x0000ff, 1);
|
||||
|
||||
// Draw AABB
|
||||
for (let i = 0; i < instances.length; i++) {
|
||||
const object = instances[i];
|
||||
const layer = this._runtimeScene.getLayer(object.getLayer());
|
||||
|
||||
if (
|
||||
(!object.isVisible() || !layer.isVisible()) &&
|
||||
!showHiddenInstances
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (!rendererObject) {
|
||||
continue;
|
||||
}
|
||||
const aabb = object.getAABB();
|
||||
debugDraw.fill.alpha = 0.2;
|
||||
debugDraw.line.color = 0x778ee8;
|
||||
debugDraw.fill.color = 0x778ee8;
|
||||
|
||||
const polygon: float[] = [];
|
||||
polygon.push.apply(
|
||||
polygon,
|
||||
layer.convertInverseCoords(aabb.min[0], aabb.min[1])
|
||||
);
|
||||
polygon.push.apply(
|
||||
polygon,
|
||||
layer.convertInverseCoords(aabb.max[0], aabb.min[1])
|
||||
);
|
||||
polygon.push.apply(
|
||||
polygon,
|
||||
layer.convertInverseCoords(aabb.max[0], aabb.max[1])
|
||||
);
|
||||
polygon.push.apply(
|
||||
polygon,
|
||||
layer.convertInverseCoords(aabb.min[0], aabb.max[1])
|
||||
);
|
||||
|
||||
debugDraw.drawPolygon(polygon);
|
||||
}
|
||||
|
||||
// Draw hitboxes and points
|
||||
for (let i = 0; i < instances.length; i++) {
|
||||
const object = instances[i];
|
||||
const layer = this._runtimeScene.getLayer(object.getLayer());
|
||||
|
||||
if (
|
||||
(!object.isVisible() || !layer.isVisible()) &&
|
||||
!showHiddenInstances
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (!rendererObject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the structure to store the points in memory
|
||||
const id = object.id;
|
||||
if (!this._debugDrawRenderedObjectsPoints[id]) {
|
||||
this._debugDrawRenderedObjectsPoints[id] = {
|
||||
wasRendered: true,
|
||||
points: {},
|
||||
};
|
||||
}
|
||||
const renderedObjectPoints = this._debugDrawRenderedObjectsPoints[id];
|
||||
renderedObjectPoints.wasRendered = true;
|
||||
|
||||
// Draw hitboxes (sub-optimal performance)
|
||||
const hitboxes = object.getHitBoxes();
|
||||
for (let j = 0; j < hitboxes.length; j++) {
|
||||
// Note that this conversion is sub-optimal, but we don't care
|
||||
// as this is for debug draw.
|
||||
const polygon: float[] = [];
|
||||
hitboxes[j].vertices.forEach((point) => {
|
||||
point = layer.convertInverseCoords(point[0], point[1]);
|
||||
|
||||
polygon.push(point[0]);
|
||||
polygon.push(point[1]);
|
||||
});
|
||||
debugDraw.fill.alpha = 0;
|
||||
debugDraw.line.alpha = 0.5;
|
||||
debugDraw.line.color = 0xff0000;
|
||||
debugDraw.drawPolygon(polygon);
|
||||
}
|
||||
|
||||
// Draw points
|
||||
debugDraw.fill.alpha = 0.3;
|
||||
|
||||
// Draw Center point
|
||||
const centerPoint = layer.convertInverseCoords(
|
||||
object.getCenterXInScene(),
|
||||
object.getCenterYInScene()
|
||||
);
|
||||
|
||||
renderObjectPoint(
|
||||
renderedObjectPoints.points,
|
||||
'Center',
|
||||
0xffff00,
|
||||
centerPoint[0],
|
||||
centerPoint[1]
|
||||
);
|
||||
|
||||
// Draw position point
|
||||
const positionPoint = layer.convertInverseCoords(
|
||||
object.getX(),
|
||||
object.getY()
|
||||
);
|
||||
|
||||
renderObjectPoint(
|
||||
renderedObjectPoints.points,
|
||||
'Position',
|
||||
0xff0000,
|
||||
positionPoint[0],
|
||||
positionPoint[1]
|
||||
);
|
||||
|
||||
// Draw Origin point
|
||||
if (object instanceof gdjs.SpriteRuntimeObject) {
|
||||
let originPoint = object.getPointPosition('origin');
|
||||
// When there is neither rotation nor flipping,
|
||||
// the origin point is over the position point.
|
||||
if (
|
||||
Math.abs(originPoint[0] - positionPoint[0]) >= 1 ||
|
||||
Math.abs(originPoint[1] - positionPoint[1]) >= 1
|
||||
) {
|
||||
originPoint = layer.convertInverseCoords(
|
||||
originPoint[0],
|
||||
originPoint[1]
|
||||
);
|
||||
|
||||
renderObjectPoint(
|
||||
renderedObjectPoints.points,
|
||||
'Origin',
|
||||
0xff0000,
|
||||
originPoint[0],
|
||||
originPoint[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw custom point
|
||||
if (showCustomPoints && object instanceof gdjs.SpriteRuntimeObject) {
|
||||
if (!object._animationFrame) continue;
|
||||
|
||||
for (const customPointName in object._animationFrame.points.items) {
|
||||
let customPoint = object.getPointPosition(customPointName);
|
||||
|
||||
customPoint = layer.convertInverseCoords(
|
||||
customPoint[0],
|
||||
customPoint[1]
|
||||
);
|
||||
|
||||
renderObjectPoint(
|
||||
renderedObjectPoints.points,
|
||||
customPointName,
|
||||
0x0000ff,
|
||||
customPoint[0],
|
||||
customPoint[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean any point text from an object that is not rendered.
|
||||
for (const objectID in this._debugDrawRenderedObjectsPoints) {
|
||||
const renderedObjectPoints = this._debugDrawRenderedObjectsPoints[
|
||||
objectID
|
||||
];
|
||||
if (renderedObjectPoints.wasRendered) continue;
|
||||
|
||||
const points = renderedObjectPoints.points;
|
||||
for (const name in points) {
|
||||
this._debugDrawContainer.removeChild(points[name]);
|
||||
}
|
||||
}
|
||||
|
||||
debugDraw.endFill();
|
||||
}
|
||||
|
||||
clearDebugDraw(): void {
|
||||
if (this._debugDraw) {
|
||||
this._debugDraw.clear();
|
||||
}
|
||||
|
||||
if (this._debugDrawContainer) {
|
||||
this._debugDrawContainer.destroy({
|
||||
children: true,
|
||||
});
|
||||
this._pixiContainer.removeChild(this._debugDrawContainer);
|
||||
}
|
||||
this._debugDraw = null;
|
||||
this._debugDrawContainer = null;
|
||||
this._debugDrawRenderedObjectsPoints = {};
|
||||
}
|
||||
|
||||
hideCursor(): void {
|
||||
this._showCursorAtNextRender = false;
|
||||
if (!this._pixiRenderer) {
|
||||
@@ -359,6 +96,10 @@ namespace gdjs {
|
||||
return this._pixiContainer;
|
||||
}
|
||||
|
||||
getRendererObject() {
|
||||
return this._pixiContainer;
|
||||
}
|
||||
|
||||
getPIXIRenderer() {
|
||||
return this._pixiRenderer;
|
||||
}
|
||||
@@ -383,7 +124,7 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
//Register the class to let the engine use it.
|
||||
// Register the class to let the engine use it.
|
||||
export type RuntimeSceneRenderer = gdjs.RuntimeScenePixiRenderer;
|
||||
export const RuntimeSceneRenderer = gdjs.RuntimeScenePixiRenderer;
|
||||
}
|
||||
|
||||
@@ -14,19 +14,17 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* @param runtimeObject The object
|
||||
* @param runtimeScene The scene
|
||||
* @param instanceContainer The scene
|
||||
*/
|
||||
constructor(
|
||||
runtimeObject: gdjs.SpriteRuntimeObject,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
if (this._sprite === undefined) {
|
||||
this._sprite = new PIXI.Sprite(
|
||||
runtimeScene.getGame().getImageManager().getInvalidPIXITexture()
|
||||
);
|
||||
}
|
||||
const layer = runtimeScene.getLayer('');
|
||||
this._sprite = new PIXI.Sprite(
|
||||
instanceContainer.getGame().getImageManager().getInvalidPIXITexture()
|
||||
);
|
||||
const layer = instanceContainer.getLayer('');
|
||||
if (layer) {
|
||||
layer
|
||||
.getRenderer()
|
||||
@@ -34,11 +32,14 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
reinitialize(runtimeObject, runtimeScene) {
|
||||
reinitialize(
|
||||
runtimeObject: gdjs.SpriteRuntimeObject,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._spriteDirty = true;
|
||||
this._textureDirty = true;
|
||||
const layer = runtimeScene.getLayer('');
|
||||
const layer = instanceContainer.getLayer('');
|
||||
if (layer) {
|
||||
layer
|
||||
.getRenderer()
|
||||
|
||||
@@ -41,12 +41,12 @@ namespace gdjs {
|
||||
_activated: boolean = true;
|
||||
|
||||
/**
|
||||
* @param runtimeScene The scene owning the object of the behavior
|
||||
* @param instanceContainer The container owning the object of the behavior
|
||||
* @param behaviorData The properties used to setup the behavior
|
||||
* @param owner The object owning the behavior
|
||||
*/
|
||||
constructor(
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
behaviorData: BehaviorData,
|
||||
public owner: gdjs.RuntimeObject
|
||||
) {
|
||||
@@ -92,15 +92,15 @@ namespace gdjs {
|
||||
/**
|
||||
* Called at each frame before events. Call doStepPreEvents.<br>
|
||||
* Behaviors writers: Please do not redefine this method. Redefine doStepPreEvents instead.
|
||||
* @param runtimeScene The runtimeScene owning the object
|
||||
* @param instanceContainer The instanceContainer owning the object
|
||||
*/
|
||||
stepPreEvents(runtimeScene: gdjs.RuntimeScene): void {
|
||||
stepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if (this._activated) {
|
||||
const profiler = runtimeScene.getProfiler();
|
||||
const profiler = instanceContainer.getScene().getProfiler();
|
||||
if (profiler) {
|
||||
profiler.begin(this.name);
|
||||
}
|
||||
this.doStepPreEvents(runtimeScene);
|
||||
this.doStepPreEvents(instanceContainer);
|
||||
if (profiler) {
|
||||
profiler.end(this.name);
|
||||
}
|
||||
@@ -110,15 +110,15 @@ namespace gdjs {
|
||||
/**
|
||||
* Called at each frame after events. Call doStepPostEvents.<br>
|
||||
* Behaviors writers: Please do not redefine this method. Redefine doStepPreEvents instead.
|
||||
* @param runtimeScene The runtimeScene owning the object
|
||||
* @param instanceContainer The instanceContainer owning the object
|
||||
*/
|
||||
stepPostEvents(runtimeScene: gdjs.RuntimeScene): void {
|
||||
stepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if (this._activated) {
|
||||
const profiler = runtimeScene.getProfiler();
|
||||
const profiler = instanceContainer.getScene().getProfiler();
|
||||
if (profiler) {
|
||||
profiler.begin(this.name);
|
||||
}
|
||||
this.doStepPostEvents(runtimeScene);
|
||||
this.doStepPostEvents(instanceContainer);
|
||||
if (profiler) {
|
||||
profiler.end(this.name);
|
||||
}
|
||||
@@ -171,15 +171,15 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* This method is called each tick before events are done.
|
||||
* @param runtimeScene The runtimeScene owning the object
|
||||
* @param instanceContainer The instanceContainer owning the object
|
||||
*/
|
||||
doStepPreEvents(runtimeScene: gdjs.RuntimeScene): void {}
|
||||
doStepPreEvents(instanceContainer: gdjs.RuntimeInstanceContainer): void {}
|
||||
|
||||
/**
|
||||
* This method is called each tick after events are done.
|
||||
* @param runtimeScene The runtimeScene owning the object
|
||||
* @param instanceContainer The instanceContainer owning the object
|
||||
*/
|
||||
doStepPostEvents(runtimeScene: gdjs.RuntimeScene): void {}
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer): void {}
|
||||
|
||||
/**
|
||||
* This method is called when the owner of the behavior
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace gdjs {
|
||||
export class RuntimeGame {
|
||||
_variables: VariablesContainer;
|
||||
_data: ProjectData;
|
||||
_eventsBasedObjectDatas: Map<String, EventsBasedObjectData>;
|
||||
_imageManager: ImageManager;
|
||||
_soundManager: SoundManager;
|
||||
_fontManager: FontManager;
|
||||
@@ -142,6 +143,18 @@ namespace gdjs {
|
||||
this._sessionId = null;
|
||||
this._playerId = null;
|
||||
|
||||
this._eventsBasedObjectDatas = new Map<String, EventsBasedObjectData>();
|
||||
if (this._data.eventsFunctionsExtensions) {
|
||||
for (const extension of this._data.eventsFunctionsExtensions) {
|
||||
for (const eventsBasedObject of extension.eventsBasedObjects) {
|
||||
this._eventsBasedObjectDatas.set(
|
||||
extension.name + '::' + eventsBasedObject.name,
|
||||
eventsBasedObject
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isUsingGDevelopDevelopmentEnvironment()) {
|
||||
logger.info(
|
||||
'This game will run on the development version of GDevelop APIs.'
|
||||
@@ -251,6 +264,17 @@ namespace gdjs {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
getEventsBasedObjectData(type: string): EventsBasedObjectData | null {
|
||||
const eventsBasedObjectData = this._eventsBasedObjectDatas.get(type);
|
||||
if (!eventsBasedObjectData) {
|
||||
logger.error(
|
||||
'The game has no events-based object of the type "' + type + '"'
|
||||
);
|
||||
return null;
|
||||
}
|
||||
return eventsBasedObjectData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data associated to a scene.
|
||||
*
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace gdjs {
|
||||
|
||||
readonly id: integer;
|
||||
private destroyCallbacks = new Set<() => void>();
|
||||
_runtimeScene: gdjs.RuntimeScene;
|
||||
_runtimeScene: gdjs.RuntimeInstanceContainer;
|
||||
|
||||
/**
|
||||
* An optional UUID associated to the object to be used
|
||||
@@ -209,12 +209,15 @@ namespace gdjs {
|
||||
* @param runtimeScene The scene the object belongs to..
|
||||
* @param objectData The initial properties of the object.
|
||||
*/
|
||||
constructor(runtimeScene: gdjs.RuntimeScene, objectData: ObjectData) {
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectData: ObjectData & any
|
||||
) {
|
||||
this.name = objectData.name || '';
|
||||
this.type = objectData.type || '';
|
||||
this._nameId = RuntimeObject.getNameIdentifier(this.name);
|
||||
this.id = runtimeScene.createNewUniqueId();
|
||||
this._runtimeScene = runtimeScene;
|
||||
this.id = instanceContainer.getScene().createNewUniqueId();
|
||||
this._runtimeScene = instanceContainer;
|
||||
this._defaultHitBoxes.push(gdjs.Polygon.createRectangle(0, 0));
|
||||
this.hitBoxes = this._defaultHitBoxes;
|
||||
this._variables = new gdjs.VariablesContainer(
|
||||
@@ -234,7 +237,7 @@ namespace gdjs {
|
||||
for (let i = 0, len = objectData.behaviors.length; i < len; ++i) {
|
||||
const autoData = objectData.behaviors[i];
|
||||
const Ctor = gdjs.getBehaviorConstructor(autoData.type);
|
||||
this._behaviors.push(new Ctor(runtimeScene, autoData, this));
|
||||
this._behaviors.push(new Ctor(instanceContainer, autoData, this));
|
||||
this._behaviorsTable.put(autoData.name, this._behaviors[i]);
|
||||
}
|
||||
this._timers = new Hashtable();
|
||||
@@ -335,6 +338,8 @@ namespace gdjs {
|
||||
this._timers.clear();
|
||||
|
||||
this.destroyCallbacks.clear();
|
||||
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
static supportsReinitialization = false;
|
||||
@@ -345,9 +350,9 @@ namespace gdjs {
|
||||
*
|
||||
* Objects can have different elapsed time if they are on layers with different time scales.
|
||||
*
|
||||
* @param runtimeScene The RuntimeScene the object belongs to (deprecated - can be omitted).
|
||||
* @param instanceContainer The instance container the object belongs to (deprecated - can be omitted).
|
||||
*/
|
||||
getElapsedTime(runtimeScene?: gdjs.RuntimeScene): float {
|
||||
getElapsedTime(instanceContainer?: gdjs.RuntimeInstanceContainer): float {
|
||||
const theLayer = this._runtimeScene.getLayer(this.layer);
|
||||
return theLayer.getElapsedTime();
|
||||
}
|
||||
@@ -355,21 +360,35 @@ namespace gdjs {
|
||||
/**
|
||||
* The gdjs.RuntimeScene the object belongs to.
|
||||
*/
|
||||
getRuntimeScene(): RuntimeScene {
|
||||
getParent(): gdjs.RuntimeInstanceContainer {
|
||||
return this._runtimeScene;
|
||||
}
|
||||
|
||||
/**
|
||||
* The gdjs.RuntimeScene the object belongs to.
|
||||
*/
|
||||
getRuntimeScene(): gdjs.RuntimeScene {
|
||||
return this._runtimeScene.getScene();
|
||||
}
|
||||
|
||||
/**
|
||||
* The container the object belongs to.
|
||||
*/
|
||||
getInstanceContainer(): gdjs.RuntimeInstanceContainer {
|
||||
return this._runtimeScene;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once during the game loop, before events and rendering.
|
||||
* @param runtimeScene The gdjs.RuntimeScene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
*/
|
||||
update(runtimeScene: gdjs.RuntimeScene): void {}
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {}
|
||||
|
||||
/**
|
||||
* Called once during the game loop, after events and before rendering.
|
||||
* @param runtimeScene The gdjs.RuntimeScene the object belongs to.
|
||||
* @param instanceContainer The container the object belongs to.
|
||||
*/
|
||||
updatePreRender(runtimeScene: gdjs.RuntimeScene): void {}
|
||||
updatePreRender(instanceContainer: gdjs.RuntimeInstanceContainer): void {}
|
||||
|
||||
/**
|
||||
* Called when the object is created from an initial instance at the startup of the scene.<br>
|
||||
@@ -401,11 +420,11 @@ namespace gdjs {
|
||||
* Remove an object from a scene.
|
||||
*
|
||||
* Do not change/redefine this method. Instead, redefine the onDestroyFromScene method.
|
||||
* @param runtimeScene The RuntimeScene owning the object.
|
||||
* @param instanceContainer The container owning the object.
|
||||
*/
|
||||
deleteFromScene(runtimeScene: gdjs.RuntimeScene): void {
|
||||
deleteFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if (this._livingOnScene) {
|
||||
runtimeScene.markObjectForDeletion(this);
|
||||
instanceContainer.markObjectForDeletion(this);
|
||||
this._livingOnScene = false;
|
||||
}
|
||||
}
|
||||
@@ -423,10 +442,10 @@ namespace gdjs {
|
||||
* is being unloaded). If you redefine this function, **make sure to call the original method**
|
||||
* (`RuntimeObject.prototype.onDestroyFromScene.call(this, runtimeScene);`).
|
||||
*
|
||||
* @param runtimeScene The scene owning the object.
|
||||
* @param instanceContainer The container owning the object.
|
||||
*/
|
||||
onDestroyFromScene(runtimeScene: gdjs.RuntimeScene): void {
|
||||
const theLayer = runtimeScene.getLayer(this.layer);
|
||||
onDestroyFromScene(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
const theLayer = instanceContainer.getLayer(this.layer);
|
||||
const rendererObject = this.getRendererObject();
|
||||
if (rendererObject) {
|
||||
theLayer.getRenderer().removeRendererObject(rendererObject);
|
||||
@@ -515,7 +534,21 @@ namespace gdjs {
|
||||
return;
|
||||
}
|
||||
this.x = x;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a signal that the object hitboxes are no longer up to date.
|
||||
*
|
||||
* The signal is propagated to parents so
|
||||
* {@link gdjs.RuntimeObject.hitBoxesDirty} should never be modified
|
||||
* directly.
|
||||
*/
|
||||
invalidateHitboxes(): void {
|
||||
// TODO EBO Check that no community extension set hitBoxesDirty to true
|
||||
// directly.
|
||||
this.hitBoxesDirty = true;
|
||||
this._runtimeScene.onChildrenLocationChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -537,7 +570,7 @@ namespace gdjs {
|
||||
return;
|
||||
}
|
||||
this.y = y;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -593,10 +626,15 @@ namespace gdjs {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param angle The targeted direction angle.
|
||||
* @param speed The rotation speed.
|
||||
* @param instanceContainer The container the object belongs to (deprecated - can be omitted).
|
||||
*/
|
||||
rotateTowardAngle(
|
||||
angle: float,
|
||||
speed: float,
|
||||
runtimeScene: gdjs.RuntimeScene
|
||||
instanceContainer?: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
if (speed === 0) {
|
||||
this.setAngle(angle);
|
||||
@@ -609,10 +647,7 @@ namespace gdjs {
|
||||
const diffWasPositive = angularDiff >= 0;
|
||||
let newAngle =
|
||||
this.getAngle() +
|
||||
((diffWasPositive ? -1.0 : 1.0) *
|
||||
speed *
|
||||
this.getElapsedTime(runtimeScene)) /
|
||||
1000;
|
||||
((diffWasPositive ? -1.0 : 1.0) * speed * this.getElapsedTime()) / 1000;
|
||||
|
||||
if (
|
||||
// @ts-ignore
|
||||
@@ -637,12 +672,13 @@ namespace gdjs {
|
||||
* Rotate the object at the given speed
|
||||
*
|
||||
* @param speed The speed, in degrees per second.
|
||||
* @param runtimeScene The scene where the object is displayed.
|
||||
* @param instanceContainer The container the object belongs to (deprecated - can be omitted).
|
||||
*/
|
||||
rotate(speed: float, runtimeScene: gdjs.RuntimeScene): void {
|
||||
this.setAngle(
|
||||
this.getAngle() + (speed * this.getElapsedTime(runtimeScene)) / 1000
|
||||
);
|
||||
rotate(
|
||||
speed: float,
|
||||
instanceContainer?: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
this.setAngle(this.getAngle() + (speed * this.getElapsedTime()) / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -655,7 +691,7 @@ namespace gdjs {
|
||||
return;
|
||||
}
|
||||
this.angle = angle;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1620,18 +1656,22 @@ namespace gdjs {
|
||||
/**
|
||||
* Call each behavior stepPreEvents method.
|
||||
*/
|
||||
stepBehaviorsPreEvents(runtimeScene): void {
|
||||
stepBehaviorsPreEvents(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
for (let i = 0, len = this._behaviors.length; i < len; ++i) {
|
||||
this._behaviors[i].stepPreEvents(runtimeScene);
|
||||
this._behaviors[i].stepPreEvents(instanceContainer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call each behavior stepPostEvents method.
|
||||
*/
|
||||
stepBehaviorsPostEvents(runtimeScene): void {
|
||||
stepBehaviorsPostEvents(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
): void {
|
||||
for (let i = 0, len = this._behaviors.length; i < len; ++i) {
|
||||
this._behaviors[i].stepPostEvents(runtimeScene);
|
||||
this._behaviors[i].stepPostEvents(instanceContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1862,7 +1902,7 @@ namespace gdjs {
|
||||
* @return true if the object was moved
|
||||
*/
|
||||
separateFromObjects(
|
||||
objects: RuntimeObject[],
|
||||
objects: gdjs.RuntimeObject[],
|
||||
ignoreTouchingEdges: boolean
|
||||
): boolean {
|
||||
let moveXArray: Array<float> = separateFromObjectsStatics.moveXArray;
|
||||
@@ -2402,12 +2442,18 @@ namespace gdjs {
|
||||
*
|
||||
* @return true if the cursor, or any touch, is on the object.
|
||||
*/
|
||||
cursorOnObject(runtimeScene: RuntimeScene): boolean {
|
||||
const inputManager = runtimeScene.getGame().getInputManager();
|
||||
const layer = runtimeScene.getLayer(this.layer);
|
||||
cursorOnObject(instanceContainer: gdjs.RuntimeInstanceContainer): boolean {
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
RuntimeObject.prototype.cursorOnObject
|
||||
) as FloatPoint;
|
||||
workingPoint.length = 2;
|
||||
const inputManager = instanceContainer.getGame().getInputManager();
|
||||
const layer = instanceContainer.getLayer(this.layer);
|
||||
const mousePos = layer.convertCoords(
|
||||
inputManager.getMouseX(),
|
||||
inputManager.getMouseY()
|
||||
inputManager.getMouseY(),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
if (this.insideObject(mousePos[0], mousePos[1])) {
|
||||
return true;
|
||||
@@ -2416,7 +2462,9 @@ namespace gdjs {
|
||||
for (let i = 0; i < touchIds.length; ++i) {
|
||||
const touchPos = layer.convertCoords(
|
||||
inputManager.getTouchX(touchIds[i]),
|
||||
inputManager.getTouchY(touchIds[i])
|
||||
inputManager.getTouchY(touchIds[i]),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
if (this.insideObject(touchPos[0], touchPos[1])) {
|
||||
return true;
|
||||
|
||||
+126
-582
@@ -10,21 +10,14 @@ namespace gdjs {
|
||||
/**
|
||||
* A scene being played, containing instances of objects rendered on screen.
|
||||
*/
|
||||
export class RuntimeScene {
|
||||
export class RuntimeScene extends gdjs.RuntimeInstanceContainer {
|
||||
_eventsFunction: null | ((runtimeScene: RuntimeScene) => void) = null;
|
||||
_instances: Hashtable<RuntimeObject[]>;
|
||||
|
||||
//Contains the instances living on the scene
|
||||
_instancesCache: Hashtable<RuntimeObject[]>;
|
||||
|
||||
//Used to recycle destroyed instance instead of creating new ones.
|
||||
_objects: Hashtable<ObjectData>;
|
||||
|
||||
//Contains the objects data stored in the project
|
||||
_objectsCtor: Hashtable<typeof RuntimeObject>;
|
||||
_layers: Hashtable<Layer>;
|
||||
// TODO EBO move behavior shared data up to the instances container.
|
||||
/** Contains the objects data stored in the project */
|
||||
_initialBehaviorSharedData: Hashtable<BehaviorSharedData | null>;
|
||||
_renderer: RuntimeSceneRenderer;
|
||||
_debuggerRenderer: gdjs.DebuggerRenderer;
|
||||
_variables: gdjs.VariablesContainer;
|
||||
_runtimeGame: gdjs.RuntimeGame;
|
||||
_lastId: integer = 0;
|
||||
@@ -32,92 +25,77 @@ namespace gdjs {
|
||||
_timeManager: TimeManager;
|
||||
_gameStopRequested: boolean = false;
|
||||
_requestedScene: string = '';
|
||||
_isLoaded: boolean = false;
|
||||
private _asyncTasksManager = new gdjs.AsyncTasksManager();
|
||||
|
||||
// True if loadFromScene was called and the scene is being played.
|
||||
/** True if loadFromScene was called and the scene is being played. */
|
||||
_isLoaded: boolean = false;
|
||||
/** True in the first frame after resuming the paused scene */
|
||||
_isJustResumed: boolean = false;
|
||||
|
||||
// True in the first frame after resuming the paused scene
|
||||
_requestedChange: SceneChangeRequest;
|
||||
/** Black background by default. */
|
||||
_backgroundColor: integer = 0;
|
||||
_allInstancesList: gdjs.RuntimeObject[] = [];
|
||||
_onceTriggers: OnceTriggers;
|
||||
_layersCameraCoordinates: Record<string, [float, float, float, float]> = {};
|
||||
_instancesRemoved: gdjs.RuntimeObject[] = [];
|
||||
_profiler: gdjs.Profiler | null = null;
|
||||
|
||||
// Options for the debug draw:
|
||||
_debugDrawEnabled: boolean = false;
|
||||
_debugDrawShowHiddenInstances: boolean = false;
|
||||
_debugDrawShowPointsNames: boolean = false;
|
||||
_debugDrawShowCustomPoints: boolean = false;
|
||||
|
||||
// Set to `new gdjs.Profiler()` to have profiling done on the scene.
|
||||
_onProfilerStopped: null | ((oldProfiler: gdjs.Profiler) => void) = null;
|
||||
|
||||
_cachedGameResolutionWidth: integer;
|
||||
_cachedGameResolutionHeight: integer;
|
||||
|
||||
/**
|
||||
* @param runtimeGame The game associated to this scene.
|
||||
*/
|
||||
constructor(runtimeGame: gdjs.RuntimeGame) {
|
||||
this._instances = new Hashtable();
|
||||
this._instancesCache = new Hashtable();
|
||||
this._objects = new Hashtable();
|
||||
this._objectsCtor = new Hashtable();
|
||||
this._layers = new Hashtable();
|
||||
super();
|
||||
this._initialBehaviorSharedData = new Hashtable();
|
||||
this._runtimeGame = runtimeGame;
|
||||
this._variables = new gdjs.VariablesContainer();
|
||||
this._timeManager = new gdjs.TimeManager();
|
||||
this._onceTriggers = new gdjs.OnceTriggers();
|
||||
this._requestedChange = SceneChangeRequest.CONTINUE;
|
||||
this._cachedGameResolutionWidth = runtimeGame
|
||||
? runtimeGame.getGameResolutionWidth()
|
||||
: 0;
|
||||
this._cachedGameResolutionHeight = runtimeGame
|
||||
? runtimeGame.getGameResolutionHeight()
|
||||
: 0;
|
||||
|
||||
this._renderer = new gdjs.RuntimeSceneRenderer(
|
||||
this,
|
||||
// @ts-ignore
|
||||
// @ts-ignore This is needed because of test. They should mock RuntimeGame instead.
|
||||
runtimeGame ? runtimeGame.getRenderer() : null
|
||||
);
|
||||
this._variables = new gdjs.VariablesContainer();
|
||||
this._runtimeGame = runtimeGame;
|
||||
this._timeManager = new gdjs.TimeManager();
|
||||
this._requestedChange = SceneChangeRequest.CONTINUE;
|
||||
this._debuggerRenderer = new gdjs.DebuggerRenderer(this);
|
||||
|
||||
// What to do after the frame is rendered.
|
||||
|
||||
// Black background by default.
|
||||
|
||||
//An array used to create a list of all instance when necessary ( see _constructListOfAllInstances )
|
||||
this._onceTriggers = new gdjs.OnceTriggers();
|
||||
|
||||
//The instances removed from the scene and waiting to be sent to the cache.
|
||||
|
||||
// The callback function to call when the profiler is stopped.
|
||||
this.onGameResolutionResized();
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate or deactivate the debug visualization for collisions and points.
|
||||
*/
|
||||
enableDebugDraw(
|
||||
enableDebugDraw: boolean,
|
||||
showHiddenInstances: boolean,
|
||||
showPointsNames: boolean,
|
||||
showCustomPoints: boolean
|
||||
): void {
|
||||
if (this._debugDrawEnabled && !enableDebugDraw) {
|
||||
this.getRenderer().clearDebugDraw();
|
||||
}
|
||||
|
||||
this._debugDrawEnabled = enableDebugDraw;
|
||||
this._debugDrawShowHiddenInstances = showHiddenInstances;
|
||||
this._debugDrawShowPointsNames = showPointsNames;
|
||||
this._debugDrawShowCustomPoints = showCustomPoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called when the canvas where the scene is rendered has been resized.
|
||||
* See gdjs.RuntimeGame.startGameLoop in particular.
|
||||
*/
|
||||
onGameResolutionResized() {
|
||||
const oldGameResolutionOriginX = this.getViewportOriginX();
|
||||
const oldGameResolutionOriginY = this.getViewportOriginY();
|
||||
this._cachedGameResolutionWidth = this._runtimeGame
|
||||
? this._runtimeGame.getGameResolutionWidth()
|
||||
: 0;
|
||||
this._cachedGameResolutionHeight = this._runtimeGame
|
||||
? this._runtimeGame.getGameResolutionHeight()
|
||||
: 0;
|
||||
for (const name in this._layers.items) {
|
||||
if (this._layers.items.hasOwnProperty(name)) {
|
||||
/** @type gdjs.Layer */
|
||||
const theLayer: gdjs.Layer = this._layers.items[name];
|
||||
theLayer.onGameResolutionResized();
|
||||
theLayer.onGameResolutionResized(
|
||||
oldGameResolutionOriginX,
|
||||
oldGameResolutionOriginY
|
||||
);
|
||||
}
|
||||
}
|
||||
this._renderer.onGameResolutionResized();
|
||||
@@ -133,6 +111,7 @@ namespace gdjs {
|
||||
logger.error('loadFromScene was called without a scene');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._isLoaded) {
|
||||
this.unloadScene();
|
||||
}
|
||||
@@ -208,75 +187,13 @@ namespace gdjs {
|
||||
this._timeManager.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an object is registered, meaning that instances of it can be created and lives in the scene.
|
||||
* @see gdjs.RuntimeScene#registerObject
|
||||
*/
|
||||
isObjectRegistered(objectName: string): boolean {
|
||||
return (
|
||||
this._objects.containsKey(objectName) &&
|
||||
this._instances.containsKey(objectName) &&
|
||||
this._objectsCtor.containsKey(objectName)
|
||||
addLayer(layerData: LayerData) {
|
||||
this._layers.put(
|
||||
layerData.name,
|
||||
new gdjs.RuntimeSceneLayer(layerData, this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link gdjs.RuntimeObject} so that instances of it can be used in the scene.
|
||||
* @param objectData The data for the object to register.
|
||||
*/
|
||||
registerObject(objectData: ObjectData) {
|
||||
this._objects.put(objectData.name, objectData);
|
||||
this._instances.put(objectData.name, []);
|
||||
|
||||
// Cache the constructor
|
||||
const Ctor = gdjs.getObjectConstructor(objectData.type);
|
||||
this._objectsCtor.put(objectData.name, Ctor);
|
||||
|
||||
// Also prepare a cache for recycled instances, if the object supports it.
|
||||
if (Ctor.supportsReinitialization) {
|
||||
this._instancesCache.put(objectData.name, []);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the data of a {@link gdjs.RuntimeObject} so that instances use this when constructed.
|
||||
* @param objectData The data for the object to register.
|
||||
*/
|
||||
updateObject(objectData: ObjectData): void {
|
||||
if (!this.isObjectRegistered(objectData.name)) {
|
||||
logger.warn(
|
||||
'Tried to call updateObject for an object that was not registered (' +
|
||||
objectData.name +
|
||||
'). Call registerObject first.'
|
||||
);
|
||||
}
|
||||
this._objects.put(objectData.name, objectData);
|
||||
}
|
||||
|
||||
// Don't erase instances, nor instances cache, or objectsCtor cache.
|
||||
/**
|
||||
* Unregister a {@link gdjs.RuntimeObject}. Instances will be destroyed.
|
||||
* @param objectName The name of the object to unregister.
|
||||
*/
|
||||
unregisterObject(objectName: string) {
|
||||
const instances = this._instances.get(objectName);
|
||||
if (instances) {
|
||||
// This is sub-optimal: markObjectForDeletion will search the instance to
|
||||
// remove in instances, so cost is O(n^2), n being the number of instances.
|
||||
// As we're unregistering an object which only happen during a hot-reloading,
|
||||
// this is fine.
|
||||
const instancesToRemove = instances.slice();
|
||||
for (let i = 0; i < instancesToRemove.length; i++) {
|
||||
this.markObjectForDeletion(instancesToRemove[i]);
|
||||
}
|
||||
this._cacheOrClearRemovedInstances();
|
||||
}
|
||||
this._objects.remove(objectName);
|
||||
this._instances.remove(objectName);
|
||||
this._instancesCache.remove(objectName);
|
||||
this._objectsCtor.remove(objectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a scene is "paused", i.e it will be not be rendered again
|
||||
* for some time, until it's resumed or unloaded.
|
||||
@@ -284,9 +201,9 @@ namespace gdjs {
|
||||
onPause() {
|
||||
// Notify the objects that the scene is being paused. Objects should not
|
||||
// do anything special, but some object renderers might want to know about this.
|
||||
this._constructListOfAllInstances();
|
||||
for (let i = 0, len = this._allInstancesList.length; i < len; ++i) {
|
||||
const object = this._allInstancesList[i];
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
object.onScenePaused(this);
|
||||
}
|
||||
|
||||
@@ -304,9 +221,9 @@ namespace gdjs {
|
||||
|
||||
// Notify the objects that the scene is being resumed. Objects should not
|
||||
// do anything special, but some object renderers might want to know about this.
|
||||
this._constructListOfAllInstances();
|
||||
for (let i = 0, len = this._allInstancesList.length; i < len; ++i) {
|
||||
const object = this._allInstancesList[i];
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
object.onSceneResumed(this);
|
||||
}
|
||||
|
||||
@@ -334,9 +251,9 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
// Notify the objects they are being destroyed
|
||||
this._constructListOfAllInstances();
|
||||
for (let i = 0, len = this._allInstancesList.length; i < len; ++i) {
|
||||
const object = this._allInstancesList[i];
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
object.onDestroyFromScene(this);
|
||||
}
|
||||
|
||||
@@ -352,96 +269,22 @@ namespace gdjs {
|
||||
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._eventsFunction = null;
|
||||
this._objectsCtor = new Hashtable();
|
||||
this._allInstancesList = [];
|
||||
this._instancesRemoved = [];
|
||||
this._lastId = 0;
|
||||
this._destroy();
|
||||
|
||||
//@ts-ignore We are deleting the object
|
||||
this._onceTriggers = null;
|
||||
this._isLoaded = false;
|
||||
this.onGameResolutionResized();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create objects from initial instances data (for example, the initial instances
|
||||
* of the scene or the instances of an external layout).
|
||||
*
|
||||
* @param data The instances data
|
||||
* @param xPos The offset on X axis
|
||||
* @param yPos The offset on Y axis
|
||||
* @param trackByPersistentUuid If true, objects are tracked by setting their `persistentUuid`
|
||||
* to the same as the associated instance. Useful for hot-reloading when instances are changed.
|
||||
*/
|
||||
createObjectsFrom(
|
||||
data: InstanceData[],
|
||||
xPos: float,
|
||||
yPos: float,
|
||||
trackByPersistentUuid: boolean
|
||||
) {
|
||||
for (let i = 0, len = data.length; i < len; ++i) {
|
||||
const instanceData = data[i];
|
||||
const objectName = instanceData.name;
|
||||
const newObject = this.createObject(objectName);
|
||||
if (newObject !== null) {
|
||||
if (trackByPersistentUuid) {
|
||||
// Give the object the same persistentUuid as the instance, so that
|
||||
// it can be hot-reloaded.
|
||||
newObject.persistentUuid = instanceData.persistentUuid || null;
|
||||
}
|
||||
newObject.setPosition(instanceData.x + xPos, instanceData.y + yPos);
|
||||
newObject.setZOrder(instanceData.zOrder);
|
||||
newObject.setAngle(instanceData.angle);
|
||||
newObject.setLayer(instanceData.layer);
|
||||
newObject
|
||||
.getVariables()
|
||||
.initFrom(instanceData.initialVariables, true);
|
||||
newObject.extraInitializationFromInitialInstance(instanceData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default Z order for each layer, which is the highest Z order found on each layer.
|
||||
* Useful as it ensures that instances created from events are, by default, shown in front
|
||||
* of other instances.
|
||||
*/
|
||||
private _setLayerDefaultZOrders() {
|
||||
if (
|
||||
this._runtimeGame.getGameData().properties
|
||||
.useDeprecatedZeroAsDefaultZOrder
|
||||
) {
|
||||
// Deprecated option to still support games that were made considered 0 as the
|
||||
// default Z order for all layers.
|
||||
return;
|
||||
}
|
||||
const layerHighestZOrders: Record<string, number> = {};
|
||||
const allInstances = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstances.length; i < len; ++i) {
|
||||
const object = allInstances[i];
|
||||
let layerName = object.getLayer();
|
||||
const zOrder = object.getZOrder();
|
||||
if (
|
||||
layerHighestZOrders[layerName] === undefined ||
|
||||
layerHighestZOrders[layerName] < zOrder
|
||||
) {
|
||||
layerHighestZOrders[layerName] = zOrder;
|
||||
}
|
||||
}
|
||||
for (let layerName in layerHighestZOrders) {
|
||||
this.getLayer(layerName).setDefaultZOrder(
|
||||
layerHighestZOrders[layerName] + 1
|
||||
);
|
||||
}
|
||||
_destroy() {
|
||||
// It should not be necessary to reset these variables, but this help
|
||||
// ensuring that all memory related to the RuntimeScene is released immediately.
|
||||
super._destroy();
|
||||
this._variables = new gdjs.VariablesContainer();
|
||||
this._initialBehaviorSharedData = new Hashtable();
|
||||
this._eventsFunction = null;
|
||||
this._lastId = 0;
|
||||
// @ts-ignore We are deleting the object
|
||||
this._onceTriggers = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,8 +400,8 @@ namespace gdjs {
|
||||
// Set to true to enable debug rendering (look for the implementation in the renderer
|
||||
// to see what is rendered).
|
||||
if (this._debugDrawEnabled) {
|
||||
this.getRenderer().renderDebugDraw(
|
||||
this._allInstancesList,
|
||||
this._debuggerRenderer.renderDebugDraw(
|
||||
this.getAdhocListOfAllInstances(),
|
||||
this._debugDrawShowHiddenInstances,
|
||||
this._debugDrawShowPointsNames,
|
||||
this._debugDrawShowCustomPoints
|
||||
@@ -583,38 +426,6 @@ namespace gdjs {
|
||||
this._renderer.render();
|
||||
}
|
||||
|
||||
_updateLayersCameraCoordinates(scale: float) {
|
||||
this._layersCameraCoordinates = this._layersCameraCoordinates || {};
|
||||
for (const name in this._layers.items) {
|
||||
if (this._layers.items.hasOwnProperty(name)) {
|
||||
const theLayer = this._layers.items[name];
|
||||
this._layersCameraCoordinates[name] = this._layersCameraCoordinates[
|
||||
name
|
||||
] || [0, 0, 0, 0];
|
||||
this._layersCameraCoordinates[name][0] =
|
||||
theLayer.getCameraX() - (theLayer.getCameraWidth() / 2) * scale;
|
||||
this._layersCameraCoordinates[name][1] =
|
||||
theLayer.getCameraY() - (theLayer.getCameraHeight() / 2) * scale;
|
||||
this._layersCameraCoordinates[name][2] =
|
||||
theLayer.getCameraX() + (theLayer.getCameraWidth() / 2) * scale;
|
||||
this._layersCameraCoordinates[name][3] =
|
||||
theLayer.getCameraY() + (theLayer.getCameraHeight() / 2) * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update effects of layers before rendering.
|
||||
*/
|
||||
_updateLayersPreRender() {
|
||||
for (const name in this._layers.items) {
|
||||
if (this._layers.items.hasOwnProperty(name)) {
|
||||
const layer = this._layers.items[name];
|
||||
layer.updatePreRender(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update visibility of the renderers of objects
|
||||
* rendered on the scene ("culling"), update effects (of visible objects)
|
||||
@@ -625,24 +436,7 @@ namespace gdjs {
|
||||
*/
|
||||
_updateObjectsPreRender() {
|
||||
if (this._timeManager.isFirstFrame()) {
|
||||
this._constructListOfAllInstances();
|
||||
for (let i = 0, len = this._allInstancesList.length; i < len; ++i) {
|
||||
const object = this._allInstancesList[i];
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (rendererObject) {
|
||||
rendererObject.visible = !object.isHidden();
|
||||
|
||||
// Update effects, only for visible objects.
|
||||
if (rendererObject.visible) {
|
||||
this._runtimeGame
|
||||
.getEffectsManager()
|
||||
.updatePreRender(object.getRendererEffects(), object);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform pre-render update.
|
||||
object.updatePreRender(this);
|
||||
}
|
||||
super._updateObjectsPreRender();
|
||||
return;
|
||||
} else {
|
||||
// After first frame, optimise rendering by setting only objects
|
||||
@@ -656,9 +450,9 @@ namespace gdjs {
|
||||
// instead.
|
||||
// - objects having effects rendering outside of their visibility AABB.
|
||||
this._updateLayersCameraCoordinates(2);
|
||||
this._constructListOfAllInstances();
|
||||
for (let i = 0, len = this._allInstancesList.length; i < len; ++i) {
|
||||
const object = this._allInstancesList[i];
|
||||
const allInstancesList = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0, len = allInstancesList.length; i < len; ++i) {
|
||||
const object = allInstancesList[i];
|
||||
const rendererObject = object.getRendererObject();
|
||||
if (rendererObject) {
|
||||
if (object.isHidden()) {
|
||||
@@ -703,98 +497,6 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
_cacheOrClearRemovedInstances() {
|
||||
for (let k = 0, lenk = this._instancesRemoved.length; k < lenk; ++k) {
|
||||
// Cache the instance to recycle it into a new instance later.
|
||||
// If the object does not support recycling, the cache won't be defined.
|
||||
const cache = this._instancesCache.get(
|
||||
this._instancesRemoved[k].getName()
|
||||
);
|
||||
if (cache) {
|
||||
if (cache.length < 128) {
|
||||
cache.push(this._instancesRemoved[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._instancesRemoved.length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool function filling _allInstancesList member with all the living object instances.
|
||||
*/
|
||||
_constructListOfAllInstances() {
|
||||
let currentListSize = 0;
|
||||
for (const name in this._instances.items) {
|
||||
if (this._instances.items.hasOwnProperty(name)) {
|
||||
const list = this._instances.items[name];
|
||||
const oldSize = currentListSize;
|
||||
currentListSize += list.length;
|
||||
for (let 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.
|
||||
*/
|
||||
_updateObjectsPreEvents() {
|
||||
//It is *mandatory* to create and iterate on a external list of all objects, as the behaviors
|
||||
//may delete the objects.
|
||||
this._constructListOfAllInstances();
|
||||
for (let i = 0, len = this._allInstancesList.length; i < len; ++i) {
|
||||
const obj = this._allInstancesList[i];
|
||||
const elapsedTime = obj.getElapsedTime(this);
|
||||
if (!obj.hasNoForces()) {
|
||||
const averageForce = obj.getAverageForce();
|
||||
const 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);
|
||||
}
|
||||
|
||||
//Some behaviors may have request objects to be deleted.
|
||||
this._cacheOrClearRemovedInstances();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the objects (update positions, time management...)
|
||||
*/
|
||||
_updateObjectsPostEvents() {
|
||||
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 (let i = 0, len = this._allInstancesList.length; i < len; ++i) {
|
||||
this._allInstancesList[i].stepBehaviorsPostEvents(this);
|
||||
}
|
||||
|
||||
//Some behaviors may have request objects to be deleted.
|
||||
this._cacheOrClearRemovedInstances();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the background color, by setting the RGB components.
|
||||
* Internally, the color is stored as an hexadecimal number.
|
||||
@@ -822,121 +524,6 @@ namespace gdjs {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the objects positions according to their forces
|
||||
*/
|
||||
updateObjectsForces(): void {
|
||||
for (const name in this._instances.items) {
|
||||
if (this._instances.items.hasOwnProperty(name)) {
|
||||
const list = this._instances.items[name];
|
||||
for (let j = 0, listLen = list.length; j < listLen; ++j) {
|
||||
const obj = list[j];
|
||||
if (!obj.hasNoForces()) {
|
||||
const averageForce = obj.getAverageForce();
|
||||
const 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.
|
||||
*/
|
||||
addObject(obj: RuntimeObject) {
|
||||
if (!this._instances.containsKey(obj.name)) {
|
||||
this._instances.put(obj.name, []);
|
||||
}
|
||||
this._instances.get(obj.name).push(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the instances of the object called name.
|
||||
* @param name Name of the object for which the instances must be returned.
|
||||
* @return The list of objects with the given name
|
||||
*/
|
||||
getObjects(name: string): gdjs.RuntimeObject[] {
|
||||
if (!this._instances.containsKey(name)) {
|
||||
logger.info(
|
||||
'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 objectName The name of the object to be created
|
||||
* @return The created object
|
||||
*/
|
||||
createObject(objectName: string): gdjs.RuntimeObject | null {
|
||||
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:
|
||||
const cache = this._instancesCache.get(objectName);
|
||||
const ctor = this._objectsCtor.get(objectName);
|
||||
let obj;
|
||||
if (!cache || cache.length === 0) {
|
||||
obj = new ctor(this, this._objects.get(objectName));
|
||||
} else {
|
||||
// Reuse an objet destroyed before. If there is an object in the cache,
|
||||
// then it means it does support reinitialization.
|
||||
obj = cache.pop();
|
||||
obj.reinitialize(this._objects.get(objectName));
|
||||
}
|
||||
this.addObject(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called whenever an object must be removed from the scene.
|
||||
* @param obj The object to be removed.
|
||||
*/
|
||||
markObjectForDeletion(obj: gdjs.RuntimeObject) {
|
||||
//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())) {
|
||||
const objId = obj.id;
|
||||
const allInstances = this._instances.get(obj.getName());
|
||||
for (let i = 0, len = allInstances.length; i < len; ++i) {
|
||||
if (allInstances[i].id == objId) {
|
||||
allInstances.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Notify the object it was removed from the scene
|
||||
obj.onDestroyFromScene(this);
|
||||
|
||||
// Notify the global callbacks
|
||||
for (let j = 0; j < gdjs.callbacksObjectDeletedFromScene.length; ++j) {
|
||||
gdjs.callbacksObjectDeletedFromScene[j](this, obj);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an identifier for a new object of the scene.
|
||||
*/
|
||||
@@ -945,20 +532,61 @@ namespace gdjs {
|
||||
return this._lastId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the renderer associated to the RuntimeScene.
|
||||
*/
|
||||
getRenderer() {
|
||||
getRenderer(): gdjs.RuntimeScenePixiRenderer {
|
||||
return this._renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the runtimeGame associated to the RuntimeScene.
|
||||
*/
|
||||
getDebuggerRenderer() {
|
||||
return this._debuggerRenderer;
|
||||
}
|
||||
|
||||
getGame() {
|
||||
return this._runtimeGame;
|
||||
}
|
||||
|
||||
getScene() {
|
||||
return this;
|
||||
}
|
||||
|
||||
getViewportWidth(): float {
|
||||
return this._cachedGameResolutionWidth;
|
||||
}
|
||||
|
||||
getViewportHeight(): float {
|
||||
return this._cachedGameResolutionHeight;
|
||||
}
|
||||
|
||||
getViewportOriginX(): float {
|
||||
return this._cachedGameResolutionWidth / 2;
|
||||
}
|
||||
|
||||
getViewportOriginY(): float {
|
||||
return this._cachedGameResolutionHeight / 2;
|
||||
}
|
||||
|
||||
convertCoords(x: float, y: float, result: FloatPoint): FloatPoint {
|
||||
// The result parameter used to be optional.
|
||||
const point = result || [0, 0];
|
||||
point[0] = x;
|
||||
point[1] = y;
|
||||
return point;
|
||||
}
|
||||
|
||||
convertInverseCoords(
|
||||
sceneX: float,
|
||||
sceneY: float,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
const point = result || [0, 0];
|
||||
point[0] = sceneX;
|
||||
point[1] = sceneY;
|
||||
return point;
|
||||
}
|
||||
|
||||
onChildrenLocationChanged(): void {
|
||||
// Scenes don't maintain bounds.
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variables of the runtimeScene.
|
||||
* @return The container holding the variables of the scene.
|
||||
@@ -993,72 +621,6 @@ namespace gdjs {
|
||||
this._initialBehaviorSharedData.put(name, sharedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layer with the given name
|
||||
* @param name The name of the layer
|
||||
* @returns The layer, or the base layer if not found
|
||||
*/
|
||||
getLayer(name: string): gdjs.Layer {
|
||||
if (this._layers.containsKey(name)) {
|
||||
return this._layers.get(name);
|
||||
}
|
||||
return this._layers.get('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a layer exists
|
||||
* @param name The name of the layer
|
||||
*/
|
||||
hasLayer(name: string): boolean {
|
||||
return this._layers.containsKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a layer.
|
||||
* @param layerData The data to construct the layer
|
||||
*/
|
||||
addLayer(layerData: LayerData) {
|
||||
this._layers.put(layerData.name, new gdjs.Layer(layerData, this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a layer. All {@link gdjs.RuntimeObject} on this layer will
|
||||
* be moved back to the base layer.
|
||||
* @param layerName The name of the layer to remove
|
||||
*/
|
||||
removeLayer(layerName: string) {
|
||||
const allInstances = this.getAdhocListOfAllInstances();
|
||||
for (let i = 0; i < allInstances.length; ++i) {
|
||||
const runtimeObject = allInstances[i];
|
||||
if (runtimeObject.getLayer() === layerName) {
|
||||
runtimeObject.setLayer('');
|
||||
}
|
||||
}
|
||||
this._layers.remove(layerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the position of a layer.
|
||||
*
|
||||
* @param layerName The name of the layer to reorder
|
||||
* @param index The new position in the list of layers
|
||||
*/
|
||||
setLayerIndex(layerName: string, index: integer): void {
|
||||
const layer: gdjs.Layer = this._layers.get(layerName);
|
||||
if (!layer) {
|
||||
return;
|
||||
}
|
||||
this._renderer.setLayerIndex(layer, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the array passed as argument with the names of all layers
|
||||
* @param result The array where to put the layer names
|
||||
*/
|
||||
getAllLayerNames(result: string[]) {
|
||||
this._layers.keys(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TimeManager of the scene.
|
||||
* @return The gdjs.TimeManager of the scene.
|
||||
@@ -1067,6 +629,14 @@ namespace gdjs {
|
||||
return this._timeManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time elapsed since the last frame,
|
||||
* in milliseconds, for objects on the layer.
|
||||
*/
|
||||
getElapsedTime(): float {
|
||||
return this._timeManager.getElapsedTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut to get the SoundManager of the game.
|
||||
* @return The gdjs.SoundManager of the game.
|
||||
@@ -1112,7 +682,7 @@ namespace gdjs {
|
||||
/**
|
||||
* Get the profiler associated with the scene, or null if none.
|
||||
*/
|
||||
getProfiler() {
|
||||
getProfiler(): gdjs.Profiler | null {
|
||||
return this._profiler;
|
||||
}
|
||||
|
||||
@@ -1152,32 +722,6 @@ namespace gdjs {
|
||||
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 The list of all runtime objects on the scnee
|
||||
*/
|
||||
getAdhocListOfAllInstances(): gdjs.RuntimeObject[] {
|
||||
this._constructListOfAllInstances();
|
||||
return this._allInstancesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of instances of the specified object living on the scene.
|
||||
* @param objectName The object name for which instances must be counted.
|
||||
*/
|
||||
getInstancesCountOnScene(objectName: string): integer {
|
||||
const instances = this._instances.get(objectName);
|
||||
if (instances) {
|
||||
return instances.length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the scene was just resumed.
|
||||
* This is true during the first frame after the scene has been unpaused.
|
||||
|
||||
@@ -201,7 +201,10 @@ namespace gdjs {
|
||||
loop: boolean;
|
||||
frames: SpriteAnimationFrame[] = [];
|
||||
|
||||
constructor(imageManager, directionData) {
|
||||
constructor(
|
||||
imageManager: gdjs.PixiImageManager,
|
||||
directionData: SpriteDirectionData
|
||||
) {
|
||||
this.timeBetweenFrames = directionData
|
||||
? directionData.timeBetweenFrames
|
||||
: 1.0;
|
||||
@@ -247,7 +250,10 @@ namespace gdjs {
|
||||
name: string;
|
||||
directions: gdjs.SpriteAnimationDirection[] = [];
|
||||
|
||||
constructor(imageManager, animData) {
|
||||
constructor(
|
||||
imageManager: gdjs.PixiImageManager,
|
||||
animData: SpriteAnimationData
|
||||
) {
|
||||
this.hasMultipleDirections = !!animData.useMultipleDirections;
|
||||
this.name = animData.name || '';
|
||||
this.reinitialize(imageManager, animData);
|
||||
@@ -282,9 +288,6 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* The SpriteRuntimeObject represents an object that can display images.
|
||||
*
|
||||
* @param runtimeScene The scene the object belongs to
|
||||
* @param spriteObjectData The object data used to initialize the object
|
||||
*/
|
||||
export class SpriteRuntimeObject extends gdjs.RuntimeObject {
|
||||
_currentAnimation: number = 0;
|
||||
@@ -313,21 +316,30 @@ namespace gdjs {
|
||||
*/
|
||||
_animationFrame: gdjs.SpriteAnimationFrame | null = null;
|
||||
_renderer: gdjs.SpriteRuntimeObjectRenderer;
|
||||
hitBoxesDirty: any;
|
||||
_animationFrameDirty: any;
|
||||
|
||||
constructor(runtimeScene, spriteObjectData) {
|
||||
super(runtimeScene, spriteObjectData);
|
||||
/**
|
||||
* @param instanceContainer The container the object belongs to
|
||||
* @param spriteObjectData The object data used to initialize the object
|
||||
*/
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
spriteObjectData: ObjectData & SpriteObjectDataType
|
||||
) {
|
||||
super(instanceContainer, spriteObjectData);
|
||||
this._updateIfNotVisible = !!spriteObjectData.updateIfNotVisible;
|
||||
for (let i = 0, len = spriteObjectData.animations.length; i < len; ++i) {
|
||||
this._animations.push(
|
||||
new gdjs.SpriteAnimation(
|
||||
runtimeScene.getGame().getImageManager(),
|
||||
instanceContainer.getGame().getImageManager(),
|
||||
spriteObjectData.animations[i]
|
||||
)
|
||||
);
|
||||
}
|
||||
this._renderer = new gdjs.SpriteRuntimeObjectRenderer(this, runtimeScene);
|
||||
this._renderer = new gdjs.SpriteRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
this._updateAnimationFrame();
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
@@ -336,7 +348,7 @@ namespace gdjs {
|
||||
|
||||
reinitialize(spriteObjectData: SpriteObjectData) {
|
||||
super.reinitialize(spriteObjectData);
|
||||
const runtimeScene = this._runtimeScene;
|
||||
const instanceContainer = this.getInstanceContainer();
|
||||
this._currentAnimation = 0;
|
||||
this._currentDirection = 0;
|
||||
this._currentFrame = 0;
|
||||
@@ -355,13 +367,13 @@ namespace gdjs {
|
||||
const animData = spriteObjectData.animations[i];
|
||||
if (i < this._animations.length) {
|
||||
this._animations[i].reinitialize(
|
||||
runtimeScene.getGame().getImageManager(),
|
||||
instanceContainer.getGame().getImageManager(),
|
||||
animData
|
||||
);
|
||||
} else {
|
||||
this._animations.push(
|
||||
new gdjs.SpriteAnimation(
|
||||
runtimeScene.getGame().getImageManager(),
|
||||
instanceContainer.getGame().getImageManager(),
|
||||
animData
|
||||
)
|
||||
);
|
||||
@@ -371,7 +383,7 @@ namespace gdjs {
|
||||
|
||||
//Make sure to delete already existing animations which are not used anymore.
|
||||
this._animationFrame = null;
|
||||
this._renderer.reinitialize(this, runtimeScene);
|
||||
this._renderer.reinitialize(this, instanceContainer);
|
||||
this._updateAnimationFrame();
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object reinitialize method.
|
||||
@@ -382,19 +394,19 @@ namespace gdjs {
|
||||
oldObjectData: SpriteObjectData,
|
||||
newObjectData: SpriteObjectData
|
||||
): boolean {
|
||||
const runtimeScene = this._runtimeScene;
|
||||
const instanceContainer = this.getInstanceContainer();
|
||||
let i = 0;
|
||||
for (const len = newObjectData.animations.length; i < len; ++i) {
|
||||
const animData = newObjectData.animations[i];
|
||||
if (i < this._animations.length) {
|
||||
this._animations[i].reinitialize(
|
||||
runtimeScene.getGame().getImageManager(),
|
||||
instanceContainer.getGame().getImageManager(),
|
||||
animData
|
||||
);
|
||||
} else {
|
||||
this._animations.push(
|
||||
new gdjs.SpriteAnimation(
|
||||
runtimeScene.getGame().getImageManager(),
|
||||
instanceContainer.getGame().getImageManager(),
|
||||
animData
|
||||
)
|
||||
);
|
||||
@@ -407,7 +419,7 @@ namespace gdjs {
|
||||
if (!this._animationFrame) {
|
||||
this.setAnimation(0);
|
||||
}
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -437,7 +449,7 @@ namespace gdjs {
|
||||
/**
|
||||
* Update the current frame of the object according to the elapsed time on the scene.
|
||||
*/
|
||||
update(runtimeScene: gdjs.RuntimeScene): void {
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
//Playing the animation of all objects including the ones outside the screen can be
|
||||
//costly when the scene is big with a lot of animated objects. By default, we skip
|
||||
//updating the object if it is not visible.
|
||||
@@ -463,7 +475,7 @@ namespace gdjs {
|
||||
//and compute nothing more.
|
||||
if (!direction.loop && this._currentFrame >= direction.frames.length) {
|
||||
} else {
|
||||
const elapsedTime = this.getElapsedTime(runtimeScene) / 1000;
|
||||
const elapsedTime = this.getElapsedTime() / 1000;
|
||||
this._frameElapsedTime += this._animationPaused
|
||||
? 0
|
||||
: elapsedTime * this._animationSpeedScale;
|
||||
@@ -493,7 +505,7 @@ namespace gdjs {
|
||||
this._updateAnimationFrame();
|
||||
}
|
||||
if (oldFrame !== this._currentFrame) {
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
this._renderer.ensureUpToDate();
|
||||
}
|
||||
@@ -502,7 +514,7 @@ namespace gdjs {
|
||||
* Ensure the sprite is ready to be displayed: the proper animation frame
|
||||
* is set and the renderer is up to date (position, angle, alpha, flip, blend mode...).
|
||||
*/
|
||||
updatePreRender(runtimeScene: gdjs.RuntimeScene): void {
|
||||
updatePreRender(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
if (this._animationFrameDirty) {
|
||||
this._updateAnimationFrame();
|
||||
}
|
||||
@@ -613,7 +625,7 @@ namespace gdjs {
|
||||
//TODO: This may be unnecessary.
|
||||
this._renderer.update();
|
||||
this._animationFrameDirty = true;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +681,7 @@ namespace gdjs {
|
||||
return;
|
||||
}
|
||||
this.angle = newValue;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
this._renderer.updateAngle();
|
||||
} else {
|
||||
newValue = newValue | 0;
|
||||
@@ -688,7 +700,7 @@ namespace gdjs {
|
||||
//TODO: This may be unnecessary.
|
||||
this._renderer.update();
|
||||
this._animationFrameDirty = true;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,7 +737,7 @@ namespace gdjs {
|
||||
) {
|
||||
this._currentFrame = newFrame;
|
||||
this._animationFrameDirty = true;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -979,7 +991,7 @@ namespace gdjs {
|
||||
}
|
||||
this.x = x;
|
||||
if (this._animationFrame !== null) {
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
this._renderer.updateX();
|
||||
}
|
||||
}
|
||||
@@ -994,7 +1006,7 @@ namespace gdjs {
|
||||
}
|
||||
this.y = y;
|
||||
if (this._animationFrame !== null) {
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
this._renderer.updateY();
|
||||
}
|
||||
}
|
||||
@@ -1013,7 +1025,7 @@ namespace gdjs {
|
||||
}
|
||||
this.angle = angle;
|
||||
this._renderer.updateAngle();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
} else {
|
||||
angle = angle % 360;
|
||||
if (angle < 0) {
|
||||
@@ -1104,20 +1116,20 @@ namespace gdjs {
|
||||
return this._renderer.getColor();
|
||||
}
|
||||
|
||||
flipX(enable) {
|
||||
flipX(enable: boolean) {
|
||||
if (enable !== this._flippedX) {
|
||||
this._scaleX *= -1;
|
||||
this._flippedX = enable;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
this._renderer.update();
|
||||
}
|
||||
}
|
||||
|
||||
flipY(enable) {
|
||||
flipY(enable: boolean) {
|
||||
if (enable !== this._flippedY) {
|
||||
this._scaleY *= -1;
|
||||
this._flippedY = enable;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
this._renderer.update();
|
||||
}
|
||||
}
|
||||
@@ -1214,7 +1226,7 @@ namespace gdjs {
|
||||
this._scaleX = newScale * (this._flippedX ? -1 : 1);
|
||||
this._scaleY = newScale * (this._flippedY ? -1 : 1);
|
||||
this._renderer.update();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1231,11 +1243,11 @@ namespace gdjs {
|
||||
}
|
||||
this._scaleX = newScale * (this._flippedX ? -1 : 1);
|
||||
this._renderer.update();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on Y axis of the object (changing its width).
|
||||
* Change the scale on Y axis of the object (changing its height).
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
@@ -1248,7 +1260,7 @@ namespace gdjs {
|
||||
}
|
||||
this._scaleY = newScale * (this._flippedY ? -1 : 1);
|
||||
this._renderer.update();
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1284,7 +1296,7 @@ namespace gdjs {
|
||||
* @param scene The scene containing the object
|
||||
* @deprecated
|
||||
*/
|
||||
turnTowardObject(obj, scene) {
|
||||
turnTowardObject(obj: gdjs.RuntimeObject, scene: gdjs.RuntimeScene) {
|
||||
if (obj === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vendored
+12
-1
@@ -16,6 +16,7 @@ declare interface ProjectData {
|
||||
variables: RootVariableData[];
|
||||
layouts: LayoutData[];
|
||||
externalLayouts: ExternalLayoutData[];
|
||||
eventsFunctionsExtensions: EventsFunctionsExtensionData[];
|
||||
}
|
||||
|
||||
/** Object containing initial properties for all objects extending {@link gdjs.RuntimeObject}. */
|
||||
@@ -27,7 +28,7 @@ declare type ObjectData = {
|
||||
/** The list of default variables. */
|
||||
variables: Array<RootVariableData>;
|
||||
/** The list of default behaviors. */
|
||||
behaviors: Array<BehaviorData>;
|
||||
behaviors: Array<BehaviorData & any>;
|
||||
/** The list of effects. */
|
||||
effects: Array<EffectData>;
|
||||
};
|
||||
@@ -84,6 +85,16 @@ declare interface LayoutData {
|
||||
behaviorsSharedData: BehaviorSharedData[];
|
||||
}
|
||||
|
||||
declare interface EventsFunctionsExtensionData {
|
||||
name: string;
|
||||
eventsBasedObjects: EventsBasedObjectData[];
|
||||
}
|
||||
|
||||
declare interface EventsBasedObjectData {
|
||||
name: string;
|
||||
objects: Array<ObjectData & any>;
|
||||
}
|
||||
|
||||
declare interface BehaviorSharedData {
|
||||
name: string;
|
||||
type: string;
|
||||
|
||||
@@ -10,8 +10,8 @@ describe('gdjs.Layer', function() {
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
|
||||
it('benchmark convertCoords and convertInverseCoords', function() {
|
||||
this.timeout(20000);
|
||||
var layer = new gdjs.Layer(
|
||||
this.timeout(25000);
|
||||
var layer = new gdjs.RuntimeSceneLayer(
|
||||
{ name: 'My layer',
|
||||
visibility: true,
|
||||
effects: [],
|
||||
@@ -29,12 +29,14 @@ describe('gdjs.Layer', function() {
|
||||
layer.setCameraRotation(90, 0);
|
||||
|
||||
const benchmarkSuite = makeBenchmarkSuite();
|
||||
/** @type {FloatPoint} */
|
||||
const workingPoint = [0, 0];
|
||||
benchmarkSuite
|
||||
.add('convertCoords', () => {
|
||||
layer.convertCoords(350, 450, 0);
|
||||
layer.convertCoords(350, 450, 0, workingPoint);
|
||||
})
|
||||
.add('convertInverseCoords', () => {
|
||||
layer.convertInverseCoords(350, 450, 0);
|
||||
layer.convertInverseCoords(350, 450, 0, workingPoint);
|
||||
});
|
||||
|
||||
console.log(benchmarkSuite.run());
|
||||
|
||||
@@ -49,11 +49,13 @@ module.exports = function (config) {
|
||||
'./newIDE/app/resources/GDJS/Runtime/timemanager.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/polygon.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/runtimeobject.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/RuntimeInstanceContainer.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/runtimescene.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/scenestack.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/profiler.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/force.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/layer.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/RuntimeSceneLayer.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/timer.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/inputmanager.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/runtimegame.js',
|
||||
@@ -62,6 +64,8 @@ module.exports = function (config) {
|
||||
'./newIDE/app/resources/GDJS/Runtime/oncetriggers.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/runtimebehavior.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/spriteruntimeobject.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/CustomRuntimeObject.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/CustomRuntimeObjectInstanceContainer.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/events-tools/commontools.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/events-tools/runtimescenetools.js',
|
||||
'./newIDE/app/resources/GDJS/Runtime/events-tools/inputtools.js',
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @internal
|
||||
* @returns {Promise<gdjs.RuntimeGame>} A promise resolving with the game with loaded assets.
|
||||
*/
|
||||
gdjs.getPixiRuntimeGameWithAssets = () => {
|
||||
gdjs.getPixiRuntimeGameWithAssets = (customOptions = {}) => {
|
||||
if (gdjs.getPixiRuntimeGameWithAssets._pixiRuntimeGameWithAssetsPromise) {
|
||||
return gdjs.getPixiRuntimeGameWithAssets._pixiRuntimeGameWithAssetsPromise;
|
||||
}
|
||||
@@ -71,6 +71,28 @@ gdjs.getPixiRuntimeGameWithAssets = () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
// Used in CustomRuntimeObjects.js
|
||||
eventsFunctionsExtensions: [
|
||||
{
|
||||
name: 'MyExtension',
|
||||
eventsBasedObjects: [
|
||||
{
|
||||
name: 'MyEventsBasedObject',
|
||||
objects: [
|
||||
{
|
||||
name: 'MySprite',
|
||||
type: 'Sprite',
|
||||
updateIfNotVisible: false,
|
||||
variables: [],
|
||||
behaviors: [],
|
||||
animations: [],
|
||||
effects: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
gdjs.getPixiRuntimeGameWithAssets._pixiRuntimeGameWithAssetsPromise = new Promise(
|
||||
|
||||
@@ -0,0 +1,722 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* Basic tests for gdjs.SpriteRuntimeObject
|
||||
*/
|
||||
describe('gdjs.CustomRuntimeObject', function () {
|
||||
/**
|
||||
* Create a CustomRuntimeObject with a SpriteRuntimeObject using a 64x64
|
||||
* image with a custom collision mask.
|
||||
* @param {gdjs.RuntimeInstanceContainer} instanceContainer
|
||||
*/
|
||||
const createCustomObject = (instanceContainer) => {
|
||||
// The corresponding event-based object declaration is done by
|
||||
// getPixiRuntimeGameWithAssets.
|
||||
const customObject = new gdjs.CustomRuntimeObject(instanceContainer, {
|
||||
name: 'MyCustomObject',
|
||||
type: 'MyExtension::MyEventsBasedObject',
|
||||
variables: [],
|
||||
behaviors: [],
|
||||
effects: [],
|
||||
content: {},
|
||||
childrenContent: {
|
||||
MySprite: {
|
||||
updateIfNotVisible: false,
|
||||
animations: [
|
||||
{
|
||||
name: 'animation',
|
||||
directions: [
|
||||
{
|
||||
sprites: [
|
||||
{
|
||||
image: 'base/tests-utils/assets/64x64.jpg',
|
||||
originPoint: { name: 'Origin', x: 0, y: 0 },
|
||||
centerPoint: {
|
||||
name: 'Center',
|
||||
x: 32,
|
||||
y: 32,
|
||||
automatic: false,
|
||||
},
|
||||
points: [
|
||||
{ name: 'Center', x: 32, y: 32 },
|
||||
{ name: 'Origin', x: 0, y: 0 },
|
||||
],
|
||||
hasCustomCollisionMask: true,
|
||||
customCollisionMask: [
|
||||
[
|
||||
{ x: 64, y: 64 },
|
||||
{ x: 0, y: 64 },
|
||||
{ x: 64, y: 0 },
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
timeBetweenFrames: 0,
|
||||
looping: false,
|
||||
},
|
||||
],
|
||||
useMultipleDirections: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
instanceContainer.addObject(customObject);
|
||||
return customObject;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {gdjs.RuntimeInstanceContainer} parent
|
||||
*/
|
||||
const createSpriteObject = (parent) => {
|
||||
const sprite = parent.createObject('MySprite');
|
||||
if (!sprite) {
|
||||
throw new Error("Object couldn't be created");
|
||||
}
|
||||
return sprite;
|
||||
};
|
||||
|
||||
const createSceneWithLayer = (runtimeGame) => {
|
||||
const runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
runtimeScene.addLayer({
|
||||
name: '',
|
||||
visibility: true,
|
||||
cameras: [],
|
||||
effects: [],
|
||||
ambientLightColorR: 0,
|
||||
ambientLightColorG: 0,
|
||||
ambientLightColorB: 0,
|
||||
isLightingLayer: false,
|
||||
followBaseLayerCamera: false,
|
||||
});
|
||||
return runtimeScene;
|
||||
};
|
||||
|
||||
describe('with 2 sprites', function () {
|
||||
/** @type {gdjs.CustomRuntimeObject} */
|
||||
let customObject;
|
||||
/** @type {gdjs.RuntimeObject} */
|
||||
let leftSprite;
|
||||
/** @type {gdjs.RuntimeObject} */
|
||||
let rightSprite;
|
||||
|
||||
const makeCustomObjectWith2Children = (instanceContainer) => {
|
||||
customObject = createCustomObject(instanceContainer);
|
||||
|
||||
// Child-object creation should be done in the onCreate method of custom object.
|
||||
// TODO EBO Rewrite this test when an events-based object has initialInstances.
|
||||
leftSprite = createSpriteObject(customObject._instanceContainer);
|
||||
rightSprite = createSpriteObject(customObject._instanceContainer);
|
||||
|
||||
rightSprite.setX(64);
|
||||
};
|
||||
|
||||
it('can return hit-boxes according to its children', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
expect(leftSprite.getHitBoxes().length).to.be(1);
|
||||
expect(leftSprite.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
|
||||
expect(rightSprite.getHitBoxes().length).to.be(1);
|
||||
expect(rightSprite.getHitBoxes()[0].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
|
||||
expect(customObject.getWidth()).to.be(128);
|
||||
expect(customObject.getHeight()).to.be(64);
|
||||
|
||||
expect(customObject.getAABB()).to.eql({
|
||||
min: [0, 0],
|
||||
max: [128, 64],
|
||||
});
|
||||
|
||||
expect(customObject.getCenterXInScene()).to.be(64);
|
||||
expect(customObject.getCenterYInScene()).to.be(32);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can translate its hit-boxes', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
customObject.setPosition(8, 16);
|
||||
|
||||
expect(customObject.getWidth()).to.be(128);
|
||||
expect(customObject.getHeight()).to.be(64);
|
||||
|
||||
expect(customObject.getCenterXInScene()).to.be(64 + 8);
|
||||
expect(customObject.getCenterYInScene()).to.be(32 + 16);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[72, 80],
|
||||
[8, 80],
|
||||
[72, 16],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[136, 80],
|
||||
[72, 80],
|
||||
[136, 16],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can rotate its hit-boxes', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
customObject.setAngle(90);
|
||||
|
||||
expect(customObject.getWidth()).to.be(128);
|
||||
expect(customObject.getHeight()).to.be(64);
|
||||
|
||||
expect(customObject.getCenterXInScene()).to.be(64);
|
||||
expect(customObject.getCenterYInScene()).to.be(32);
|
||||
|
||||
// sin(pi/2) can't be exactly 0
|
||||
// but cos(pi/2) is rounded to 1 because of the mantissa length.
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[32, 32],
|
||||
[31.999999999999993, -31.999999999999996],
|
||||
[96, 31.999999999999996],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[32, 96],
|
||||
[32, 32],
|
||||
[96, 96],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can scale its hit-boxes', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
customObject.setWidth(32);
|
||||
customObject.setHeight(96);
|
||||
|
||||
expect(customObject.getWidth()).to.be(32);
|
||||
expect(customObject.getHeight()).to.be(96);
|
||||
|
||||
expect(customObject.getCenterXInScene()).to.be(16);
|
||||
expect(customObject.getCenterYInScene()).to.be(48);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[16, 96],
|
||||
[0, 96],
|
||||
[16, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[32, 96],
|
||||
[16, 96],
|
||||
[32, 0],
|
||||
]);
|
||||
});
|
||||
|
||||
it('can translate, scale and rotate its hit-boxes', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
customObject.setPosition(8, 16);
|
||||
customObject.setAngle(90);
|
||||
customObject.setWidth(32);
|
||||
customObject.setHeight(96);
|
||||
|
||||
expect(customObject.getWidth()).to.be(32);
|
||||
expect(customObject.getHeight()).to.be(96);
|
||||
|
||||
expect(customObject.getCenterXInScene()).to.be(32 / 2 + 8);
|
||||
expect(customObject.getCenterYInScene()).to.be(96 / 2 + 16);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[-12, 100],
|
||||
[-12, 84],
|
||||
[84, 100],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[-12, 116],
|
||||
[-12, 100],
|
||||
[84, 116],
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps hit-boxes up to date when its children move and push the bottom-right corner', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
rightSprite.setPosition(64 + 32, 0 + 8);
|
||||
|
||||
expect(customObject.getWidth()).to.be(128 + 32);
|
||||
expect(customObject.getHeight()).to.be(64 + 8);
|
||||
|
||||
expect(customObject.getX()).to.be(0);
|
||||
expect(customObject.getY()).to.be(0);
|
||||
|
||||
expect(customObject.getCenterXInScene()).to.be(64 + 16);
|
||||
expect(customObject.getCenterYInScene()).to.be(32 + 4);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[160, 72],
|
||||
[96, 72],
|
||||
[160, 8],
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps hit-boxes up to date when its children move and push the top-left corner', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
leftSprite.setPosition(0 - 32, 0 - 8);
|
||||
|
||||
expect(customObject.getWidth()).to.be(128 + 32);
|
||||
expect(customObject.getHeight()).to.be(64 + 8);
|
||||
|
||||
expect(customObject.getX()).to.be(0);
|
||||
expect(customObject.getY()).to.be(0);
|
||||
|
||||
expect(customObject.getDrawableX()).to.be(-32);
|
||||
expect(customObject.getDrawableY()).to.be(-8);
|
||||
|
||||
expect(customObject.getCenterXInScene()).to.be(64 - 16);
|
||||
expect(customObject.getCenterYInScene()).to.be(32 - 4);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[32, 56],
|
||||
[-32, 56],
|
||||
[32, -8],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps hit-boxes up to date when its children move and shrink the top-left corner', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
leftSprite.setPosition(0 + 32, 0 + 8);
|
||||
rightSprite.setPosition(64, 0 + 8);
|
||||
|
||||
expect(customObject.getWidth()).to.be(128 - 32);
|
||||
expect(customObject.getHeight()).to.be(64);
|
||||
|
||||
expect(customObject.getX()).to.be(0);
|
||||
expect(customObject.getY()).to.be(0);
|
||||
|
||||
expect(customObject.getDrawableX()).to.be(32);
|
||||
expect(customObject.getDrawableY()).to.be(8);
|
||||
|
||||
expect(customObject.getCenterXInScene()).to.be(64 + 16);
|
||||
expect(customObject.getCenterYInScene()).to.be(32 + 8);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[96, 72],
|
||||
[32, 72],
|
||||
[96, 8],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 72],
|
||||
[64, 72],
|
||||
[128, 8],
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps hit-boxes up to date when new children is added', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
|
||||
const middleSprite = createSpriteObject(customObject._instanceContainer);
|
||||
middleSprite.setX(32);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(3);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[2].vertices).to.eql([
|
||||
[96, 64],
|
||||
[32, 64],
|
||||
[96, 0],
|
||||
]);
|
||||
});
|
||||
|
||||
it('properly computes hitboxes and point positions after the scene layer camera has moved', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
const sceneLayer = runtimeScene.getLayer('');
|
||||
|
||||
// Check the hitboxes and positions with default camera position
|
||||
expect(customObject.getCenterXInScene()).to.be(64);
|
||||
expect(customObject.getCenterYInScene()).to.be(32);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
|
||||
// Move the layer camera.
|
||||
sceneLayer.setCameraX(2000);
|
||||
sceneLayer.setCameraY(4000);
|
||||
customObject.invalidateHitboxes();
|
||||
|
||||
// The object hitboxes and positions stay the same.
|
||||
expect(customObject.getCenterXInScene()).to.be(64);
|
||||
expect(customObject.getCenterYInScene()).to.be(32);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
});
|
||||
|
||||
it('properly computes hitboxes and point positions after the custom object layer camera has moved', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
const customObjectLayer = customObject
|
||||
.getInstanceContainer()
|
||||
.getLayer('');
|
||||
|
||||
// Check the hitboxes and positions with default camera position
|
||||
expect(customObject.getCenterXInScene()).to.be(64);
|
||||
expect(customObject.getCenterYInScene()).to.be(32);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
|
||||
// Move the layer camera.
|
||||
customObjectLayer.setCameraX(2000);
|
||||
customObjectLayer.setCameraY(4000);
|
||||
customObject.invalidateHitboxes();
|
||||
|
||||
// The object hitboxes and positions stay the same.
|
||||
expect(customObject.getCenterXInScene()).to.be(64);
|
||||
expect(customObject.getCenterYInScene()).to.be(32);
|
||||
|
||||
expect(customObject.getHitBoxes().length).to.be(2);
|
||||
expect(customObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(customObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
});
|
||||
|
||||
/** @type {FloatPoint} */
|
||||
const workingPoint = [0, 0];
|
||||
|
||||
describe('convertCoords', function () {
|
||||
it('can transform a point from the scene', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
const instanceContainer = customObject._instanceContainer;
|
||||
|
||||
customObject.setPosition(16, 8);
|
||||
expect(instanceContainer.convertCoords(16, 8, workingPoint)).to.eql([
|
||||
0,
|
||||
0,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can transform a point from the scene with a negative AABB min position', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
const instanceContainer = customObject._instanceContainer;
|
||||
|
||||
leftSprite.setPosition(-16, -8);
|
||||
customObject.setPosition(0, 0);
|
||||
expect(instanceContainer.convertCoords(0, 0, workingPoint)).to.eql([
|
||||
0,
|
||||
0,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can transform a point from the scene with a positive AABB min position', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
const instanceContainer = customObject._instanceContainer;
|
||||
|
||||
leftSprite.setPosition(16, 8);
|
||||
customObject.setPosition(0, 0);
|
||||
expect(instanceContainer.convertCoords(0, 0, workingPoint)).to.eql([
|
||||
0,
|
||||
0,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertInverseCoords', function () {
|
||||
it('can transform a point to the scene', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
const instanceContainer = customObject._instanceContainer;
|
||||
|
||||
customObject.setPosition(16, 8);
|
||||
expect(
|
||||
instanceContainer.convertInverseCoords(0, 0, workingPoint)
|
||||
).to.eql([16, 8]);
|
||||
});
|
||||
|
||||
it('can transform a point to scene with a negative AABB min position', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
const instanceContainer = customObject._instanceContainer;
|
||||
|
||||
leftSprite.setPosition(-16, -8);
|
||||
customObject.setPosition(0, 0);
|
||||
expect(
|
||||
instanceContainer.convertInverseCoords(0, 0, workingPoint)
|
||||
).to.eql([0, 0]);
|
||||
});
|
||||
|
||||
it('can transform a point to the scene with a positive AABB min position', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2Children(runtimeScene);
|
||||
const instanceContainer = customObject._instanceContainer;
|
||||
|
||||
leftSprite.setPosition(16, 8);
|
||||
customObject.setPosition(0, 0);
|
||||
expect(
|
||||
instanceContainer.convertInverseCoords(0, 0, workingPoint)
|
||||
).to.eql([0, 0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with custom objects as children', function () {
|
||||
/** @type {gdjs.CustomRuntimeObject} */
|
||||
let rootCustomObject;
|
||||
/** @type {gdjs.CustomRuntimeObject} */
|
||||
let topCustomObject;
|
||||
/** @type {gdjs.RuntimeObject} */
|
||||
let topLeftSprite;
|
||||
/** @type {gdjs.RuntimeObject} */
|
||||
let topRightSprite;
|
||||
/** @type {gdjs.CustomRuntimeObject} */
|
||||
let bottomCustomObject;
|
||||
/** @type {gdjs.RuntimeObject} */
|
||||
let bottomLeftSprite;
|
||||
/** @type {gdjs.RuntimeObject} */
|
||||
let bottomRightSprite;
|
||||
|
||||
const makeCustomObjectWith2ChildrenAt2Levels = (instanceContainer) => {
|
||||
rootCustomObject = createCustomObject(instanceContainer);
|
||||
topCustomObject = createCustomObject(rootCustomObject._instanceContainer);
|
||||
// Child-object creation should be done in the onCreate method of custom object.
|
||||
// TODO EBO Rewrite this test when an events-based object has initialInstances.
|
||||
topLeftSprite = createSpriteObject(topCustomObject._instanceContainer);
|
||||
topRightSprite = createSpriteObject(topCustomObject._instanceContainer);
|
||||
topRightSprite.setX(64);
|
||||
|
||||
bottomCustomObject = createCustomObject(
|
||||
rootCustomObject._instanceContainer
|
||||
);
|
||||
// Child-object creation should be done in the onCreate method of custom object.
|
||||
// TODO EBO Rewrite this test when an events-based object has initialInstances.
|
||||
bottomLeftSprite = createSpriteObject(
|
||||
bottomCustomObject._instanceContainer
|
||||
);
|
||||
bottomRightSprite = createSpriteObject(
|
||||
bottomCustomObject._instanceContainer
|
||||
);
|
||||
bottomRightSprite.setX(64);
|
||||
|
||||
bottomCustomObject.setY(64);
|
||||
};
|
||||
|
||||
it('can return hit-boxes according to its children', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2ChildrenAt2Levels(runtimeScene);
|
||||
|
||||
expect(rootCustomObject.getWidth()).to.be(128);
|
||||
expect(rootCustomObject.getHeight()).to.be(128);
|
||||
|
||||
expect(rootCustomObject.getAABB()).to.eql({
|
||||
min: [0, 0],
|
||||
max: [128, 128],
|
||||
});
|
||||
|
||||
expect(rootCustomObject.getCenterXInScene()).to.be(64);
|
||||
expect(rootCustomObject.getCenterYInScene()).to.be(64);
|
||||
|
||||
expect(rootCustomObject.getHitBoxes().length).to.be(4);
|
||||
expect(rootCustomObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[2].vertices).to.eql([
|
||||
[64, 128],
|
||||
[0, 128],
|
||||
[64, 64],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[3].vertices).to.eql([
|
||||
[128, 128],
|
||||
[64, 128],
|
||||
[128, 64],
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps hit-boxes up to date when its children move and push the bottom-right corner', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2ChildrenAt2Levels(runtimeScene);
|
||||
|
||||
bottomRightSprite.setPosition(64 + 32, 0 + 8);
|
||||
|
||||
expect(rootCustomObject.getWidth()).to.be(128 + 32);
|
||||
expect(rootCustomObject.getHeight()).to.be(128 + 8);
|
||||
|
||||
expect(rootCustomObject.getX()).to.be(0);
|
||||
expect(rootCustomObject.getY()).to.be(0);
|
||||
|
||||
expect(rootCustomObject.getCenterXInScene()).to.be(64 + 16);
|
||||
expect(rootCustomObject.getCenterYInScene()).to.be(64 + 4);
|
||||
|
||||
expect(rootCustomObject.getHitBoxes().length).to.be(4);
|
||||
expect(rootCustomObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[2].vertices).to.eql([
|
||||
[64, 128],
|
||||
[0, 128],
|
||||
[64, 64],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[3].vertices).to.eql([
|
||||
[160, 136],
|
||||
[96, 136],
|
||||
[160, 72],
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps hit-boxes up to date when new children is added', async () => {
|
||||
const runtimeGame = await gdjs.getPixiRuntimeGameWithAssets();
|
||||
const runtimeScene = createSceneWithLayer(runtimeGame);
|
||||
makeCustomObjectWith2ChildrenAt2Levels(runtimeScene);
|
||||
|
||||
const topMiddleSprite = createSpriteObject(
|
||||
topCustomObject._instanceContainer
|
||||
);
|
||||
topMiddleSprite.setX(32);
|
||||
|
||||
expect(rootCustomObject.getHitBoxes().length).to.be(5);
|
||||
expect(rootCustomObject.getHitBoxes()[0].vertices).to.eql([
|
||||
[64, 64],
|
||||
[0, 64],
|
||||
[64, 0],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[1].vertices).to.eql([
|
||||
[128, 64],
|
||||
[64, 64],
|
||||
[128, 0],
|
||||
]);
|
||||
// This is the new child.
|
||||
expect(rootCustomObject.getHitBoxes()[2].vertices).to.eql([
|
||||
[96, 64],
|
||||
[32, 64],
|
||||
[96, 0],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[3].vertices).to.eql([
|
||||
[64, 128],
|
||||
[0, 128],
|
||||
[64, 64],
|
||||
]);
|
||||
expect(rootCustomObject.getHitBoxes()[4].vertices).to.eql([
|
||||
[128, 128],
|
||||
[64, 128],
|
||||
[128, 64],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -18,7 +18,7 @@ gdjs.TestRuntimeObject = class TestRuntimeObject extends gdjs.RuntimeObject {
|
||||
|
||||
/**
|
||||
* @param {gdjs.RuntimeScene} runtimeScene
|
||||
* @param {ObjectData} objectData
|
||||
* @param {ObjectData & any} objectData
|
||||
*/
|
||||
constructor(runtimeScene, objectData) {
|
||||
// *ALWAYS* call the base gdjs.RuntimeObject constructor.
|
||||
@@ -31,13 +31,13 @@ gdjs.TestRuntimeObject = class TestRuntimeObject extends gdjs.RuntimeObject {
|
||||
setCustomWidthAndHeight(customWidth, customHeight) {
|
||||
this._customWidth = customWidth;
|
||||
this._customHeight = customHeight;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
setCustomCenter(customCenterX, customCenterY) {
|
||||
this._customCenterX = customCenterX;
|
||||
this._customCenterY = customCenterY;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
getRendererObject() {
|
||||
@@ -51,7 +51,7 @@ gdjs.TestRuntimeObject = class TestRuntimeObject extends gdjs.RuntimeObject {
|
||||
setWidth(width) {
|
||||
if (width !== this._customWidth) {
|
||||
this._customWidth = width;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
return this._customWidth;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ gdjs.TestRuntimeObject = class TestRuntimeObject extends gdjs.RuntimeObject {
|
||||
setHeight(height) {
|
||||
if (height !== this._customHeight) {
|
||||
this._customHeight = height;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
return this._customHeight;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
this._customHeight = customHeight;
|
||||
super._scaleX = this._customWidth / this._unscaledWidth;
|
||||
super._scaleY = this._customHeight / this._unscaledHeight;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
setUnscaledWidthAndHeight(unscaledWidth, unscaledHeight) {
|
||||
@@ -41,13 +41,13 @@
|
||||
this._unscaledHeight = unscaledHeight;
|
||||
super._scaleX = this._customWidth / this._unscaledWidth;
|
||||
super._scaleY = this._customHeight / this._unscaledHeight;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
setCustomCenter(customCenterX, customCenterY) {
|
||||
this._customCenterX = customCenterX;
|
||||
this._customCenterY = customCenterY;
|
||||
this.hitBoxesDirty = true;
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
getRendererObject() {
|
||||
|
||||
@@ -9,7 +9,7 @@ describe('gdjs.Layer', function() {
|
||||
var runtimeScene = new gdjs.RuntimeScene(runtimeGame);
|
||||
|
||||
it('can convert coordinates', function(){
|
||||
var layer = new gdjs.Layer({name: 'My layer', visibility: true, effects:[]}, runtimeScene)
|
||||
var layer = new gdjs.RuntimeSceneLayer({name: 'My layer', visibility: true, effects:[]}, runtimeScene)
|
||||
layer.setCameraX(100, 0);
|
||||
layer.setCameraY(200, 0);
|
||||
layer.setCameraRotation(90, 0);
|
||||
@@ -18,7 +18,7 @@ describe('gdjs.Layer', function() {
|
||||
expect(layer.convertCoords(350, 450, 0)[1]).to.be.within(149.9999, 150.001);
|
||||
});
|
||||
it('can convert inverse coordinates', function(){
|
||||
var layer = new gdjs.Layer({name: 'My layer', visibility: true, effects:[]}, runtimeScene)
|
||||
var layer = new gdjs.RuntimeSceneLayer({name: 'My layer', visibility: true, effects:[]}, runtimeScene)
|
||||
layer.setCameraX(100, 0);
|
||||
layer.setCameraY(200, 0);
|
||||
layer.setCameraRotation(90, 0);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user