Implement AnchorBehavior for the Javascript Platform

This commit is contained in:
Florian Rival
2016-07-25 23:23:30 +02:00
parent 7d8178c2e5
commit a1fa6dad15
6 changed files with 457 additions and 4 deletions

View File

@@ -0,0 +1,48 @@
/**
GDevelop - Anchor Behavior Extension
Copyright (c) 2016 Victor Levasseur (victorlevasseur52@gmail.com)
This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Version.h"
#include <iostream>
void DeclareAnchorBehaviorExtension(gd::PlatformExtension & extension);
/**
* \brief This class declares information about the JS extension.
*/
class AnchorBehaviorJsExtension : public gd::PlatformExtension
{
public:
/**
* \brief Constructor of an extension declares everything the extension contains: objects, actions, conditions and expressions.
*/
AnchorBehaviorJsExtension()
{
DeclareAnchorBehaviorExtension(*this);
GetBehaviorMetadata("AnchorBehavior::AnchorBehavior").SetIncludeFile("AnchorBehavior/anchorruntimebehavior.js");
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
};
};
#if defined(EMSCRIPTEN)
extern "C" gd::PlatformExtension * CreateGDJSAnchorBehaviorExtension() {
return new AnchorBehaviorJsExtension;
}
#else
/**
* Used by GDevelop to create the extension class
* -- Do not need to be modified. --
*/
extern "C" gd::PlatformExtension * GD_EXTENSION_API CreateGDJSExtension() {
return new AnchorBehaviorJsExtension;
}
#endif
#endif

View File

@@ -0,0 +1,155 @@
/**
GDevelop - Anchor Behavior Extension
Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
*/
/**
* @class AnchorRuntimeBehavior
* @constructor
*/
gdjs.AnchorRuntimeBehavior = function(runtimeScene, behaviorData, owner)
{
gdjs.RuntimeBehavior.call(this, runtimeScene, behaviorData, owner);
this._leftEdgeAnchor = behaviorData.leftEdgeAnchor;
this._rightEdgeAnchor = behaviorData.rightEdgeAnchor;
this._topEdgeAnchor = behaviorData.topEdgeAnchor;
this._bottomEdgeAnchor = behaviorData.bottomEdgeAnchor;
this._invalidDistances = true;
this._leftEdgeDistance = 0;
this._rightEdgeDistance = 0;
this._topEdgeDistance = 0;
this._bottomEdgeDistance = 0;
};
gdjs.AnchorRuntimeBehavior.prototype = Object.create( gdjs.RuntimeBehavior.prototype );
gdjs.AnchorRuntimeBehavior.thisIsARuntimeBehaviorConstructor = "AnchorBehavior::AnchorBehavior";
gdjs.AnchorRuntimeBehavior.HorizontalAnchor = {
NONE: 0,
WINDOW_LEFT: 1,
WINDOW_RIGHT: 2,
PROPORTIONAL: 3
};
gdjs.AnchorRuntimeBehavior.VerticalAnchor = {
NONE: 0,
WINDOW_TOP: 1,
WINDOW_BOTTOM: 2,
PROPORTIONAL: 3
};
gdjs.AnchorRuntimeBehavior.prototype.onActivate = function() {
this._invalidDistances = true;
};
gdjs.AnchorRuntimeBehavior.prototype.doStepPreEvents = function(runtimeScene) {
};
gdjs.AnchorRuntimeBehavior.prototype.doStepPostEvents = function(runtimeScene) {
var rendererWidth = runtimeScene.getGame().getRenderer().getCurrentWidth();
var rendererHeight = runtimeScene.getGame().getRenderer().getCurrentHeight();
var layer = runtimeScene.getLayer(this.owner.getLayer());
if(this._invalidDistances)
{
//Calculate the distances from the window's bounds.
var topLeftPixel = layer.convertCoords(
this.owner.getDrawableX(),
this.owner.getDrawableY()
);
//Left edge
if(this._leftEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_LEFT)
this._leftEdgeDistance = topLeftPixel[0];
else if(this._leftEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_RIGHT)
this._leftEdgeDistance = rendererWidth - topLeftPixel[0];
else if(this._leftEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.PROPORTIONAL)
this._leftEdgeDistance = topLeftPixel[0] / rendererWidth;
//Top edge
if(this._topEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.WINDOW_TOP)
this._topEdgeDistance = topLeftPixel[1];
else if(this._topEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.WINDOW_BOTTOM)
this._topEdgeDistance = rendererHeight - topLeftPixel[1];
else if(this._topEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.PROPORTIONAL)
this._topEdgeDistance = topLeftPixel[1] / rendererHeight;
var bottomRightPixel = layer.convertCoords(
this.owner.getDrawableX() + this.owner.getWidth(),
this.owner.getDrawableY() + this.owner.getHeight()
);
//Right edge
if(this._rightEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_LEFT)
this._rightEdgeDistance = bottomRightPixel[0];
else if(this._rightEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_RIGHT)
this._rightEdgeDistance = rendererWidth - bottomRightPixel[0];
else if(this._rightEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.PROPORTIONAL)
this._rightEdgeDistance = bottomRightPixel[0] / rendererWidth;
//Bottom edge
if(this._bottomEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.WINDOW_TOP)
this._bottomEdgeDistance = bottomRightPixel[1];
else if(this._bottomEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.WINDOW_BOTTOM)
this._bottomEdgeDistance = rendererHeight - bottomRightPixel[1];
else if(this._bottomEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.PROPORTIONAL)
this._bottomEdgeDistance = bottomRightPixel[1] / rendererHeight;
this._invalidDistances = false;
}
else
{
//Move and resize the object if needed
var leftPixel = 0;
var topPixel = 0;
var rightPixel = 0;
var bottomPixel = 0;
//Left edge
if(this._leftEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_LEFT)
leftPixel = this._leftEdgeDistance;
else if(this._leftEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_RIGHT)
leftPixel = rendererWidth - this._leftEdgeDistance;
else if(this._leftEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.PROPORTIONAL)
leftPixel = this._leftEdgeDistance * rendererWidth;
//Top edge
if(this._topEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.WINDOW_TOP)
topPixel = this._topEdgeDistance;
else if(this._topEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.WINDOW_BOTTOM)
topPixel = rendererHeight - this._topEdgeDistance;
else if(this._topEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.PROPORTIONAL)
topPixel = this._topEdgeDistance * rendererHeight;
//Right edge
if(this._rightEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_LEFT)
rightPixel = this._rightEdgeDistance;
else if(this._rightEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.WINDOW_RIGHT)
rightPixel = rendererWidth - this._rightEdgeDistance;
else if(this._rightEdgeAnchor === gdjs.AnchorRuntimeBehavior.HorizontalAnchor.PROPORTIONAL)
rightPixel = this._rightEdgeDistance * rendererWidth;
//Bottom edge
if(this._bottomEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.WINDOW_TOP)
bottomPixel = this._bottomEdgeDistance;
else if(this._bottomEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.WINDOW_BOTTOM)
bottomPixel = rendererHeight - this._bottomEdgeDistance;
else if(this._bottomEdgeAnchor === gdjs.AnchorRuntimeBehavior.VerticalAnchor.PROPORTIONAL)
bottomPixel = this._bottomEdgeDistance * rendererHeight;
var topLeftCoord = layer.convertInverseCoords(leftPixel, topPixel);
var bottomRightCoord = layer.convertInverseCoords(rightPixel, bottomPixel);
//Move and resize the object according to the anchors
if(this._rightEdgeAnchor != gdjs.AnchorRuntimeBehavior.HorizontalAnchor.NONE)
this.owner.setWidth(bottomRightCoord[0] - topLeftCoord[0]);
if(this._bottomEdgeAnchor != gdjs.AnchorRuntimeBehavior.VerticalAnchor.NONE)
this.owner.setHeight(bottomRightCoord[1] - topLeftCoord[1]);
if(this._leftEdgeAnchor != gdjs.AnchorRuntimeBehavior.HorizontalAnchor.NONE)
this.owner.setX(topLeftCoord[0] + this.owner.getX() - this.owner.getDrawableX());
if(this._topEdgeAnchor != gdjs.AnchorRuntimeBehavior.VerticalAnchor.NONE)
this.owner.setY(topLeftCoord[1] + this.owner.getY() - this.owner.getDrawableY());
}
};

View File

@@ -4,7 +4,7 @@ Copyright (c) 2013-2016 Florian Rival (Florian.Rival@gmail.com)
*/
/**
* The draggableRuntimeBehavior represents a behavior allowing objects to be
* The DraggableRuntimeBehavior represents a behavior allowing objects to be
* moved using the mouse.
*
* @class DraggableRuntimeBehavior

View File

@@ -163,12 +163,14 @@ gdjs.Layer.prototype.setCameraRotation = function(rotation, cameraId) {
* Convert a point from the canvas coordinates (For example, the mouse position) to the
* "world" coordinates.
*
* TODO: Update this method to store the result in a static array
*
* @method convertCoords
* @param x {Number} The x position, in canvas coordinates.
* @param y {Number} The y position, in canvas coordinates.
* @param cameraId The camera number. Currently ignored.
*/
gdjs.Layer.prototype.convertCoords = function(x,y, cameraId) {
gdjs.Layer.prototype.convertCoords = function(x, y, cameraId) {
x -= this._width/2;
y -= this._height/2;
x /= Math.abs(this._zoomFactor);
@@ -178,7 +180,21 @@ gdjs.Layer.prototype.convertCoords = function(x,y, cameraId) {
x = Math.cos(this._cameraRotation/180*3.14159)*x - Math.sin(this._cameraRotation/180*3.14159)*y;
y = Math.sin(this._cameraRotation/180*3.14159)*tmp + Math.cos(this._cameraRotation/180*3.14159)*y;
return [x+this.getCameraX(cameraId), y+this.getCameraY(cameraId)];
return [x + this.getCameraX(cameraId), y + this.getCameraY(cameraId)];
};
gdjs.Layer.prototype.convertInverseCoords = function(x, y, cameraId) {
x -= this.getCameraX(cameraId);
y -= this.getCameraY(cameraId);
var tmp = x;
x = Math.cos(-this._cameraRotation/180*3.14159)*x - Math.sin(-this._cameraRotation/180*3.14159)*y;
y = Math.sin(-this._cameraRotation/180*3.14159)*tmp + Math.cos(-this._cameraRotation/180*3.14159)*y;
x *= Math.abs(this._zoomFactor);
y *= Math.abs(this._zoomFactor);
return [x + this._width/2, y + this._height/2];
};
gdjs.Layer.prototype.getWidth = function() {

View File

@@ -19,7 +19,7 @@ gdjs.Variable = function(varData)
this._numberDirty = false;
this._stringDirty = true;
this._isStructure = false;
this._children = {};
this._children = {}; //TODO: Use a hashtable and avoid de/allocations.
this._undefinedInContainer = false;
if ( varData !== undefined ) {

View File

@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8" ?>
<project firstLayout="">
<gdVersion build="92" major="4" minor="0" revision="0" />
<properties folderProject="false" linuxExecutableFilename="" macExecutableFilename="" packageName="com.example.gamename" useExternalSourceFiles="false" winExecutableFilename="" winExecutableIconFile="">
<name>Project</name>
<author></author>
<windowWidth>800</windowWidth>
<windowHeight>600</windowHeight>
<latestCompilationDirectory></latestCompilationDirectory>
<maxFPS>60</maxFPS>
<minFPS>10</minFPS>
<verticalSync>false</verticalSync>
<extensions>
<extension name="BuiltinObject" />
<extension name="BuiltinAudio" />
<extension name="BuiltinVariables" />
<extension name="BuiltinTime" />
<extension name="BuiltinMouse" />
<extension name="BuiltinKeyboard" />
<extension name="BuiltinJoystick" />
<extension name="BuiltinCamera" />
<extension name="BuiltinWindow" />
<extension name="BuiltinFile" />
<extension name="BuiltinNetwork" />
<extension name="BuiltinScene" />
<extension name="BuiltinAdvanced" />
<extension name="Sprite" />
<extension name="BuiltinCommonInstructions" />
<extension name="BuiltinCommonConversions" />
<extension name="BuiltinStringInstructions" />
<extension name="BuiltinMathematicalTools" />
<extension name="BuiltinExternalLayouts" />
<extension name="AnchorBehavior" />
</extensions>
<platforms>
<platform name="GDevelop JS platform" />
<platform name="GDevelop C++ platform" />
</platforms>
<currentPlatform>GDevelop C++ platform</currentPlatform>
</properties>
<resources>
<resources>
<resource alwaysLoaded="false" file="brickWall.png" kind="image" name="brickWall.png" smoothed="true" userAdded="false" />
<resource alwaysLoaded="false" file="Grass.png" kind="image" name="Grass.png" smoothed="true" userAdded="false" />
</resources>
<resourceFolders />
</resources>
<objects />
<objectsGroups />
<variables />
<layouts>
<layout b="209" disableInputWhenNotFocused="true" mangledName="New_32scene" name="New scene" oglFOV="90.000000" oglZFar="500.000000" oglZNear="1.000000" r="209" standardSortMethod="true" stopSoundsOnStartup="true" title="" v="209">
<uiSettings grid="false" gridB="255" gridG="180" gridHeight="32" gridOffsetX="0" gridOffsetY="0" gridR="158" gridWidth="32" snap="true" windowMask="false" zoomFactor="1.000000" />
<objectsGroups />
<variables />
<instances>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="TopLeft" width="0.000000" x="27.000000" y="25.999954" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="TopLeft" width="0.000000" x="28.999939" y="117.999908" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="TopLeft" width="0.000000" x="120.999954" y="27.999924" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="BottomRight" width="0.000000" x="656.000000" y="451.999908" zOrder="2">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="Proportional" width="0.000000" x="335.999969" y="229.999969" zOrder="3">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
</instances>
<objects>
<object name="TopLeft" type="Sprite">
<variables />
<behaviors>
<behavior bottomEdgeAnchor="0" leftEdgeAnchor="1" name="Anchor" rightEdgeAnchor="0" topEdgeAnchor="1" type="AnchorBehavior::AnchorBehavior" />
</behaviors>
<animations>
<animation name="" useMultipleDirections="false">
<directions>
<direction looping="false" timeBetweenFrames="1.000000">
<sprites>
<sprite hasCustomCollisionMask="false" image="brickWall.png">
<points />
<originPoint name="origine" x="0.000000" y="0.000000" />
<centerPoint automatic="true" name="centre" x="35.000000" y="35.000000" />
<customCollisionMask>
<polygon>
<vertice x="0.000000" y="0.000000" />
<vertice x="70.000000" y="0.000000" />
<vertice x="70.000000" y="70.000000" />
<vertice x="0.000000" y="70.000000" />
</polygon>
</customCollisionMask>
</sprite>
</sprites>
</direction>
</directions>
</animation>
</animations>
</object>
<object name="BottomRight" type="Sprite">
<variables />
<behaviors>
<behavior bottomEdgeAnchor="0" leftEdgeAnchor="2" name="Anchor" rightEdgeAnchor="0" topEdgeAnchor="2" type="AnchorBehavior::AnchorBehavior" />
</behaviors>
<animations>
<animation name="" useMultipleDirections="false">
<directions>
<direction looping="false" timeBetweenFrames="1.000000">
<sprites>
<sprite hasCustomCollisionMask="false" image="brickWall.png">
<points />
<originPoint name="origine" x="0.000000" y="0.000000" />
<centerPoint automatic="true" name="centre" x="35.000000" y="35.000000" />
<customCollisionMask>
<polygon>
<vertice x="0.000000" y="0.000000" />
<vertice x="70.000000" y="0.000000" />
<vertice x="70.000000" y="70.000000" />
<vertice x="0.000000" y="70.000000" />
</polygon>
</customCollisionMask>
</sprite>
</sprites>
</direction>
</directions>
</animation>
</animations>
</object>
<object name="Proportional" type="Sprite">
<variables />
<behaviors>
<behavior bottomEdgeAnchor="3" leftEdgeAnchor="3" name="Anchor" rightEdgeAnchor="3" topEdgeAnchor="3" type="AnchorBehavior::AnchorBehavior" />
</behaviors>
<animations>
<animation name="" useMultipleDirections="false">
<directions>
<direction looping="false" timeBetweenFrames="1.000000">
<sprites>
<sprite hasCustomCollisionMask="false" image="Grass.png">
<points />
<originPoint name="origine" x="0.000000" y="0.000000" />
<centerPoint automatic="true" name="centre" x="35.000000" y="35.000000" />
<customCollisionMask>
<polygon>
<vertice x="0.000000" y="0.000000" />
<vertice x="70.000000" y="0.000000" />
<vertice x="70.000000" y="70.000000" />
<vertice x="0.000000" y="70.000000" />
</polygon>
</customCollisionMask>
</sprite>
</sprites>
</direction>
</directions>
</animation>
</animations>
</object>
</objects>
<events>
<event disabled="false" folded="false">
<type>BuiltinCommonInstructions::Standard</type>
<conditions>
<condition>
<type inverted="false" value="KeyPressed" />
<parameters>
<parameter></parameter>
<parameter>Space</parameter>
</parameters>
<subConditions />
</condition>
<condition>
<type inverted="false" value="Egal" />
<parameters>
<parameter>TimeFromStart()</parameter>
<parameter>&gt;</parameter>
<parameter>0.5</parameter>
</parameters>
<subConditions />
</condition>
</conditions>
<actions>
<action>
<type inverted="false" value="SetWindowSize" />
<parameters>
<parameter></parameter>
<parameter>SceneWindowWidth() + 40</parameter>
<parameter>SceneWindowHeight() + 40</parameter>
<parameter>yes</parameter>
</parameters>
<subActions />
</action>
<action>
<type inverted="false" value="Scene" />
<parameters>
<parameter></parameter>
<parameter>&quot;New scene&quot;</parameter>
<parameter>true</parameter>
</parameters>
<subActions />
</action>
</actions>
<events />
</event>
</events>
<layers>
<layer name="" visibility="true">
<cameras>
<camera defaultSize="true" defaultViewport="true" height="0.000000" viewportBottom="1.000000" viewportLeft="0.000000" viewportRight="1.000000" viewportTop="0.000000" width="0.000000" />
</cameras>
<effects />
</layer>
</layers>
<behaviorsSharedData>
<behaviorSharedData name="Anchor" type="AnchorBehavior::AnchorBehavior" />
</behaviorsSharedData>
</layout>
</layouts>
<externalEvents />
<externalLayouts />
<externalSourceFiles />
</project>